Held Transfers
Bank transfers to a checkout’s one-time account that were the wrong amount, or arrived after it closed. Each is held out of your available balance until you accept it as a payment or return it to the customer.
The held_transfer object
Represents a held_transfer entity in the rafiqPay system.
| Field | Type & Flags | Description |
|---|---|---|
| id | string | Held transfer ID (htr_...). |
| status | enum | held | accepted | returning | returned | refunded_by_provider. refunded_by_provider means the bank sent the money back to the sender itself, and there is nothing to decide. |
| reason | enum | mismatch (the wrong amount) | expired (arrived after the account closed). |
| expectedAmount | string | What the checkout asked for, in naira. |
| receivedAmount | string | What arrived, in naira. |
| senderName | stringNullable | The sender’s name, as the bank gave it. |
| chargeId | string | The checkout’s charge. It is not changed by this transfer. |
| checkoutSessionId | string | The checkout session the account was opened for. |
| acceptedChargeId | stringNullable | The new charge made when you accepted it. |
| returnPayoutId | stringNullable | The payout (trf_...) that sends it back, once you return it. |
| note | stringNullable | A short note, for example when the bank returned it. |
| createdAt | string | When the transfer arrived (ISO 8601). |
| decidedAt | stringNullable | When it was accepted or returned. |
{
"id": "htr_01J9KANZU7",
"object": "held_transfer",
"status": "held",
"reason": "mismatch",
"currency": "NGN",
"expectedAmount": "35000.00",
"receivedAmount": "30000.00",
"senderName": "AMINA BELLO",
"chargeId": "pay_01J9KANZU881",
"checkoutSessionId": "cs_test_kanzu_99182736",
"acceptedChargeId": null,
"returnPayoutId": null,
"note": null,
"createdAt": "2026-11-07T10:42:00.000Z",
"decidedAt": null
}Endpoints & Operations
List held transfers
Lists held transfers, newest first (up to 200). Filter with status and mode.
| Parameter | Type | Requirement | Description |
|---|---|---|---|
| status | enum | Optional | held | accepted | returning | returned | refunded_by_provider. |
| mode | enum | Optional | live | test. Defaults to live. |
curl -X GET "https://api.rafiqpay.net/v1/held-transfers" \
-H "Authorization: Bearer rp_test_sk_kanzu_9f8a7b6c5d4e3f2a"{
"object": "list",
"data": [
{
"id": "htr_01J9KANZU7",
"status": "held",
"reason": "mismatch",
"receivedAmount": "30000.00"
}
],
"hasMore": false,
"nextCursor": null
}Retrieve a held transfer
Retrieves one held transfer.
curl -X GET "https://api.rafiqpay.net/v1/held-transfers/:id" \
-H "Authorization: Bearer rp_test_sk_kanzu_9f8a7b6c5d4e3f2a"{
"id": "htr_01J9KANZU7",
"object": "held_transfer",
"status": "held",
"reason": "mismatch",
"expectedAmount": "35000.00",
"receivedAmount": "30000.00"
}Accept a held transfer
Credits the amount that arrived as a new charge of its own, with the usual fee. The original checkout is left as it was. Needs the refund permission, so it is done by a signed-in team member (Owner, Admin, Finance or Support); API keys cannot accept. A transfer that is no longer held is refused with 409.
curl -X POST "https://api.rafiqpay.net/v1/held-transfers/:id/accept" \
-H "Authorization: Bearer rp_test_sk_kanzu_9f8a7b6c5d4e3f2a" \
-H "Idempotency-Key: idem_accept-held-transfer_01"{
"heldTransfer": {
"id": "htr_01J9KANZU7",
"status": "accepted",
"acceptedChargeId": "pay_01J9KANZU902"
},
"chargeId": "pay_01J9KANZU902"
}Return a held transfer
Sends the full amount back to the customer, with no fee, to the account they give you. Only a team member signed in to the dashboard can do this, with the refund permission and a fresh code from their authenticator app; an API key is refused. If the payout fails, the money is held again. transfer.returned is sent when the money has gone. A transfer that is no longer held is refused with 409.
| Parameter | Type | Requirement | Description |
|---|---|---|---|
| bankCode | string | Required | The customer’s bank, from GET /v1/transfers/banks. |
| accountNumber | string | Required | The customer’s 10-digit account number. The bank does not tell us which account the money came from, so ask the customer. |
| code | string | Required | A fresh code from your authenticator app. |
curl -X POST "https://api.rafiqpay.net/v1/held-transfers/:id/return" \
-H "Authorization: Bearer rp_test_sk_kanzu_9f8a7b6c5d4e3f2a" \
-H "Idempotency-Key: idem_return-held-transfer_01" \
-H "Content-Type: application/json" \
-d '{
"bankCode": "058",
"accountNumber": "0123456789",
"code": "482910"
}'{
"heldTransfer": {
"id": "htr_01J9KANZU7",
"status": "returning",
"returnPayoutId": "trf_01J9KANZU"
},
"payoutStatus": "processing"
}| HTTP Status | Error Code | Condition |
|---|---|---|
| 400 | AUTHENTICATOR_CODE_INVALID | The code did not match. Use the latest code in the authenticator app. |
| 400 | AUTHENTICATOR_CODE_USED | The code was already used. Wait for the next one. |
| 403 | TWO_FACTOR_SETUP_REQUIRED | The team member has not set up two-step sign-in. |
Related Webhook Events
These events are dispatched to your webhook endpoints when actions occur on this resource: