Payout API Reference
All Payout API endpoints in integration order. Use https://api.sandbox.blox.my while testing and https://api.blox.my in production.
Read requests require blox-api-key. Write requests require the API key, an HTTP message signature, and—where shown—an Idempotency-Key UUID v4.
Every error uses { "code": "…", "message": "…", "requestId": "…" }. Branch on code, never message; the tables under each endpoint list the expected status and code combinations.
Get prefund balance
/v1/payout/prefund/balanceAPI keyReturns the prefund balance. This endpoint takes no parameters and is limited to 60 requests per minute per account.
Response — 200
{
"available": "4900000",
"inFlight": "99000",
"receivable": "0"
}| Field | Type | Description |
|---|---|---|
available | string | Spendable amount in sen |
inFlight | string | netAmount of accepted payouts that are not final |
receivable | string | Normally "0"; a negative value is owed to BLOX after an uncovered prefund reversal |
available already excludes inFlight; do not subtract it again. A negative receivable suspends payout routes with 403 FEATURE_DISABLED until resolved. Use payout.prefund_completed instead of polling for top-ups.
Error responses
| Status | code | When |
|---|---|---|
401 | UNAUTHORIZED | API key is missing, unknown, or inactive |
403 | FEATURE_DISABLED | Payout is not enabled for the account |
403 | ACCOUNT_TERMINATED | The account is terminated |
429 | RATE_LIMITED | The route or account rate limit is exceeded |
5xx | INTERNAL_ERROR | Unexpected BLOX failure; report requestId |
Error examples
401 UNAUTHORIZED
{
"code": "UNAUTHORIZED",
"message": "API key is required",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}Get active banks
/v1/payouts/active-banksAPI keyReturns the banks and e-wallets that can receive payouts, with the bank codes accepted by beneficiary and payout requests. The endpoint is limited to 600 requests per minute per account.
Response — 200
[
{
"name": "Maybank",
"bankCode": "MBBEMYKL"
},
{
"name": "TNG Digital (TouchNGo)",
"bankCode": "TNGDMYNB"
}
]| Field | Type | Description |
|---|---|---|
name | string | Bank or e-wallet name |
bankCode | string | The bank's BIC |
Use bankCode wherever the API asks for bankCode.
Error responses
| Status | code | When |
|---|---|---|
401 | UNAUTHORIZED | API key is missing, unknown, or inactive |
403 | FEATURE_DISABLED | Payout is not enabled for the account |
403 | ACCOUNT_TERMINATED | The account is terminated |
429 | RATE_LIMITED | The route or account rate limit is exceeded |
5xx | INTERNAL_ERROR | Unexpected BLOX failure; report requestId |
Error examples
401 UNAUTHORIZED
{
"code": "UNAUTHORIZED",
"message": "API key is required",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}Create beneficiary
/v1/payouts/beneficiariesAPI key + signatureRegisters a reusable beneficiary. This endpoint requires an Idempotency-Key UUID v4 and is limited to 20 requests per minute per account.
| Field | Type | Required | Constraints |
|---|---|---|---|
name | string | Yes | 2–96 characters |
bankCode | string | Yes | 1–11 characters; use a code from /v1/payouts/active-banks |
accountNumber | string | Yes | 3–20 digits |
The name is trimmed and uppercased. Registration does not deduplicate matching details; search first if the beneficiary may already exist. The default active-beneficiary limit is 1,000.
Response — 200
{
"id": "7c1a3e88-9d2b-4f61-8a44-1f0b6d3c9a55",
"name": "ADA LOVELACE",
"accountNumber": "1234567890",
"bank": { "code": "MBBM", "name": "Maybank" },
"autoWithdrawalAddress": null,
"createdAt": "2026-07-16T09:30:00.000Z",
"updatedAt": "2026-07-16T09:30:00.000Z"
}The response uses the shared Beneficiary object.
Error responses
| Status | code | When |
|---|---|---|
400 | VALIDATION_FAILED | A body field is missing, malformed, or outside its constraint |
400 | INVALID_REQUEST | Idempotency-Key is missing or malformed |
400 | UNKNOWN_BENEFICIARY | bankCode is not in your /v1/payouts/active-banks list |
401 | UNAUTHORIZED | API key or signature is missing or invalid |
403 | LIMIT_EXCEEDED | The active-beneficiary cap is reached |
403 | FEATURE_DISABLED | Payout is not enabled for the account |
403 | ACCOUNT_TERMINATED | The account is terminated |
422 | VALIDATION_FAILED | The idempotency key was already used with a different body |
429 | RATE_LIMITED | The route or account rate limit is exceeded |
5xx | INTERNAL_ERROR | Unexpected BLOX failure; report requestId |
Error examples
400 VALIDATION_FAILED
For a request with name: "A":
{
"code": "VALIDATION_FAILED",
"message": "name: Beneficiary name can't be less than 2 characters",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}List beneficiaries
/v1/payouts/beneficiariesAPI keyReturns active beneficiaries, newest first.
| Query | Type | Description |
|---|---|---|
limit | integer | 1–100; default 25 |
cursor | string | Opaque nextCursor from the previous response |
search | string | Case-insensitive substring match on name, account number, bank name, or auto-withdrawal address |
Response — 200
{
"data": [],
"hasMore": true,
"nextCursor": "9f21ab04-…"
}Each data item is a Beneficiary object. Continue with nextCursor until hasMore is false; nextCursor is null on the last page.
Error responses
| Status | code | When |
|---|---|---|
400 | VALIDATION_FAILED | A query parameter is malformed or outside its constraint |
401 | UNAUTHORIZED | API key is missing, unknown, or inactive |
403 | FEATURE_DISABLED | Payout is not enabled for the account |
403 | ACCOUNT_TERMINATED | The account is terminated |
429 | RATE_LIMITED | The account rate limit is exceeded |
5xx | INTERNAL_ERROR | Unexpected BLOX failure; report requestId |
Error examples
400 VALIDATION_FAILED
For ?limit=101:
{
"code": "VALIDATION_FAILED",
"message": "limit: Number must be less than or equal to 100",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}Get beneficiary
/v1/payouts/beneficiaries/{beneficiaryId}API keyReturns one active beneficiary. Unknown, inactive, and cross-account IDs return 404 NOT_FOUND.
| Path parameter | Type | Description |
|---|---|---|
beneficiaryId | string (UUID) | Beneficiary owned by your account |
Response — 200: Beneficiary object.
Error responses
| Status | code | When |
|---|---|---|
401 | UNAUTHORIZED | API key is missing, unknown, or inactive |
403 | FEATURE_DISABLED | Payout is not enabled for the account |
403 | ACCOUNT_TERMINATED | The account is terminated |
404 | NOT_FOUND | Beneficiary is unknown, inactive, or belongs to another account |
429 | RATE_LIMITED | The account rate limit is exceeded |
5xx | INTERNAL_ERROR | Unexpected BLOX failure; report requestId |
Error examples
401 UNAUTHORIZED
{
"code": "UNAUTHORIZED",
"message": "API key is required",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}Delete beneficiary
/v1/payouts/beneficiaries/{beneficiaryId}API key + signatureSoft-deletes the beneficiary and its deposit trigger address, if present. Sign @method and @path only; no Content-Digest is required.
Response — 200
{ "success": true }Error responses
| Status | code | When |
|---|---|---|
401 | UNAUTHORIZED | API key or signature is missing or invalid |
403 | FEATURE_DISABLED | Payout is not enabled for the account |
403 | ACCOUNT_TERMINATED | The account is terminated |
404 | NOT_FOUND | Beneficiary is unknown, inactive, or belongs to another account |
429 | RATE_LIMITED | The account rate limit is exceeded |
5xx | INTERNAL_ERROR | Unexpected BLOX failure; report requestId |
Error examples
401 UNAUTHORIZED
{
"code": "UNAUTHORIZED",
"message": "API key is required",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}Create payout
/v1/payoutsAPI key + signatureCreates and immediately submits a payout. The accepted payout is debited from available and returned as INITIATED. This endpoint is limited to 300 requests per minute per account.
Header
| Header | Required | Description |
|---|---|---|
Idempotency-Key | Yes | UUID v4 persisted per logical payout and reused on retry |
Body
| Field | Type | Required | Constraints |
|---|---|---|---|
amount | integer | Yes | 100–10000000 sen |
feeMode | string | Yes | DEDUCT_FROM_AMOUNT or CHARGE_TO_PREFUND |
beneficiaryId | string (UUID) | Conditional | Exactly one of beneficiaryId or beneficiary |
beneficiary | object | Conditional | Same fields as Create beneficiary |
reference | string | No | 1–20 trimmed characters; generated as PO + 8 characters when omitted |
DEDUCT_FROM_AMOUNT sends amount - fee; CHARGE_TO_PREFUND sends the full amount. In both cases, the prefund debit is netAmount + fee. Read both values from the response.
amount is the gross value before fees. With DEDUCT_FROM_AMOUNT, netAmount must remain at least RM1.00; under the standard RM1.50 fee floor, the smallest valid gross amount is RM2.50.
Inline beneficiaries are stored on first use and deduplicated by bank, account number, and case-insensitive name. Registered beneficiaries are optional.
Response — 200
{
"payoutId": "b0e6c2f4-2a1d-4a9e-9f3c-2c9f5a1b7e10",
"status": "INITIATED",
"type": "STANDARD",
"amount": "100000",
"fee": "1000",
"netAmount": "99000",
"beneficiaryId": "7c1a3e88-9d2b-4f61-8a44-1f0b6d3c9a55",
"bankAccountId": null,
"idempotencyKey": "6f9619ff-8b86-d011-b42d-00cf4fc964ff",
"reference": "INV-4471",
"statusReason": null,
"createdAt": "2026-07-16T09:30:00.000Z",
"submittedAt": null
}The response uses the shared Payout object. A 202 response means the original request for that key is still processing; retry with the same key.
Idempotency rules
- Persist one UUID v4 before sending a logical payout.
- Retry a timeout,
429,500, or503with the same key. - Retry a rejected
4xxwith a new key after correcting the request. - Reusing a key with a different body returns
422 VALIDATION_FAILED.
See Payout Errors for the complete code and retry table.
Error responses
| Status | code | When |
|---|---|---|
400 | VALIDATION_FAILED | The body is invalid, including both or neither beneficiary fields |
400 | INVALID_REQUEST | The idempotency key is invalid, bank verification fails, or the net amount is below RM1 |
400 | INSUFFICIENT_BALANCE | The prefund cannot cover netAmount + fee |
400 | UNKNOWN_BENEFICIARY | The beneficiary is inactive, cross-account, or the bank code is not in your /v1/payouts/active-banks list |
400 | LIMIT_EXCEEDED | A configured daily or monthly payout limit is reached |
401 | UNAUTHORIZED | API key or signature is missing or invalid |
403 | LIMIT_EXCEEDED | Storing a new inline beneficiary would exceed the active-beneficiary cap |
403 | FEATURE_DISABLED | Payout is disabled or suspended by an uncovered prefund reversal |
403 | ACCOUNT_FROZEN / ACCOUNT_PENDING_VERIFICATION / ACCOUNT_TERMINATED | The account state blocks payouts |
422 | VALIDATION_FAILED | The idempotency key was already used with a different body |
429 | RATE_LIMITED | The route or account rate limit is exceeded |
503 | SERVICE_UNAVAILABLE | Payout creation is paused; nothing was created or debited |
5xx | INTERNAL_ERROR | Unexpected BLOX failure; report requestId |
Error examples
400 VALIDATION_FAILED
For a request with amount: 99:
{
"code": "VALIDATION_FAILED",
"message": "amount: Amount can't be less than 1 MYR",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}400 INVALID_REQUEST
{
"code": "INVALID_REQUEST",
"message": "Idempotency-Key must be a valid UUID v4",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}400 INSUFFICIENT_BALANCE
{
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient prefund balance",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}400 UNKNOWN_BENEFICIARY
{
"code": "UNKNOWN_BENEFICIARY",
"message": "Beneficiary not found",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}400 LIMIT_EXCEEDED
{
"code": "LIMIT_EXCEEDED",
"message": "Daily payout limit exceeded",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}401 UNAUTHORIZED
{
"code": "UNAUTHORIZED",
"message": "API key is required",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 LIMIT_EXCEEDED
{
"code": "LIMIT_EXCEEDED",
"message": "Active beneficiary limit exceeded",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 FEATURE_DISABLED
{
"code": "FEATURE_DISABLED",
"message": "Payout is not enabled for this account",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 ACCOUNT_FROZEN
{
"code": "ACCOUNT_FROZEN",
"message": "Account is frozen",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 ACCOUNT_PENDING_VERIFICATION
{
"code": "ACCOUNT_PENDING_VERIFICATION",
"message": "Account is pending verification",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 ACCOUNT_TERMINATED
{
"code": "ACCOUNT_TERMINATED",
"message": "Account is terminated",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}422 VALIDATION_FAILED
{
"code": "VALIDATION_FAILED",
"message": "Idempotency key was already used with a different request body",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}429 RATE_LIMITED
{
"code": "RATE_LIMITED",
"message": "Too many payout requests. Please try again later.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}503 SERVICE_UNAVAILABLE
{
"code": "SERVICE_UNAVAILABLE",
"message": "Payout service is temporarily unavailable. Please try again later.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}Get payout
/v1/payouts/{id}API keyReturns a payout by payoutId. Use webhooks for status changes; use this endpoint for reconciliation or missed webhook recovery. The endpoint is limited to 600 requests per minute per account.
| Path parameter | Type | Description |
|---|---|---|
id | string (UUID) | Payout owned by your account |
Response — 200: Payout object. Unknown and cross-account IDs return 404 NOT_FOUND.
Error responses
| Status | code | When |
|---|---|---|
401 | UNAUTHORIZED | API key is missing, unknown, or inactive |
403 | FEATURE_DISABLED | Payout is disabled, including suspension by an uncovered prefund reversal |
403 | ACCOUNT_TERMINATED | The account is terminated |
404 | NOT_FOUND | Payout is unknown or belongs to another account |
429 | RATE_LIMITED | The route or account rate limit is exceeded |
5xx | INTERNAL_ERROR | Unexpected BLOX failure; report requestId |
Error examples
401 UNAUTHORIZED
{
"code": "UNAUTHORIZED",
"message": "API key is required",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}Create a deposit trigger address
/v1/payouts/beneficiaries/{beneficiaryId}/addressAPI key + signatureGives a beneficiary an on-chain address. Tokens sent to it are paid to that beneficiary automatically, with no POST /v1/payouts from you and without touching your prefund balance. See Pay a beneficiary from a deposit.
The beneficiary must be active. Calling this again returns the same address — a beneficiary has one, for its lifetime — so no Idempotency-Key is needed. Limited to 20 calls per minute. Deleting the beneficiary deactivates its address.
Success response (201)
{
"address": "0x7c1a3e889d2b4f618a441f0b6d3c9a5588ab01cd",
"network": "EVM",
"destination": {
"type": "BENEFICIARY",
"id": "7c1a3e88-9d2b-4f61-8a44-1f0b6d3c9a55"
}
}| Field | Type | Description |
|---|---|---|
address | string | Send supported tokens here |
network | string | EVM |
destination.type | string | BENEFICIARY |
destination.id | string (UUID) | The beneficiary who gets paid |
The address ignores every deposit until you allow at least one sender. The same value appears as autoWithdrawalAddress on the Beneficiary object.
Expected errors
| Status | code | When |
|---|---|---|
403 | FEATURE_DISABLED | Paying a beneficiary from a deposit is not enabled on your account |
404 | NOT_FOUND | Unknown beneficiary, one belonging to another account, or one that is not active |
429 | RATE_LIMITED | Over 20 calls in the last minute |
List allowed senders
/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelistAPI keyReturns the senders allowed to trigger this beneficiary's address, oldest first.
Success response (200)
[
{
"id": "3f8c1d02-5b47-4a6e-91cd-77e2b0a4f915",
"address": "0x9a3f7c21b8e04d6f5a19c2e70b48d3f61a5e9d02",
"label": "Treasury wallet",
"active": true,
"createdAt": "2026-08-07T09:31:05.000Z"
}
]| Field | Type | Description |
|---|---|---|
id | string (UUID) | Pass this to disable or remove the sender |
address | string | Stored lowercase |
label | string | null | Your own note |
active | boolean | Only active senders are accepted; see disable |
createdAt | string (ISO 8601) | Creation time |
Disabled senders are listed too. They count toward the 50-sender limit until you remove them.
404 NOT_FOUND if the beneficiary has no trigger address yet.
Allow a sender
/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelistAPI key + signatureAllows one address to trigger payouts to this beneficiary. Up to 50 per address.
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
address | string | Yes | 0x and 40 hex characters | The address you send from. Casing is ignored |
label | string | No | 1–120 characters | Your own note, returned on reads |
Success response (201)
Returns the created sender in the same shape as List allowed senders.
Expected errors
| Status | code | When |
|---|---|---|
400 | VALIDATION_FAILED | address is not a valid address, or label is longer than 120 characters |
400 | CONFLICT | That address is already allowed here |
403 | LIMIT_EXCEEDED | The address already has 50 allowed senders |
404 | NOT_FOUND | The beneficiary has no trigger address, or is not yours |
Disable or re-enable a sender
/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelist/{senderId}API key + signatureTurns a sender off without losing it. A disabled sender stops triggering transfers immediately, keeps its label, and stays in the list ready to be turned back on. Use this to pause a wallet you expect to send from again; use remove when you are done with it, which is also what frees its place against the 50-sender limit.
Request body
| Field | Type | Description |
|---|---|---|
active | boolean | false to disable, true to re-enable |
Success response (200)
Returns the sender in the same shape as List allowed senders.
Expected errors
| Status | code | When |
|---|---|---|
400 | VALIDATION_FAILED | active is missing or is not a boolean |
403 | ACCOUNT_FROZEN | The account is frozen. Removing a sender still works |
403 | ACCOUNT_PENDING_VERIFICATION | The account is pending verification |
404 | NOT_FOUND | The sender id is unknown or belongs to a different address |
Remove an allowed sender
/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelist/{senderId}API key + signatureStops accepting deposits from that sender and frees its place against the 50-sender limit. Deposits already on their way are unaffected. Sign @method and @path only; no Content-Digest is required.
Success response (200)
{ "success": true }404 NOT_FOUND if the sender id is unknown or belongs to a different address.
Get a deposit
/v1/payouts/deposits/{id}API keyReturns a deposit to a beneficiary's trigger address and the transfer it produced. This is the same payload the deposit webhook delivers.
A deposit is readable on the channel that produced it. Deposits paid into your own bank account are read with GET /v1/wallet/deposits/{id}.
Success response (200)
{
"id": "5e9d0273-8a41-4c62-b0f7-1d3e8c95a460",
"txHash": "0x5d5355...103ee3",
"logIndex": 12,
"chainId": 1,
"tokenId": "a71c4e08-2f96-4b3d-85ae-6c0f7d21b943",
"amount": "100000",
"from": "0x9a3f7c21b8e04d6f5a19c2e70b48d3f61a5e9d02",
"status": "COMPLETED",
"confirmations": 24,
"triggerAddress": "0x7c1a3e889d2b4f618a441f0b6d3c9a5588ab01cd",
"destination": {
"type": "BENEFICIARY",
"id": "7c1a3e88-9d2b-4f61-8a44-1f0b6d3c9a55",
"name": "ADA LOVELACE"
},
"result": {
"status": "COMPLETED",
"statusReason": null,
"withdrawal": {
"id": "c4a80f13-6d29-4e75-83b1-9f0c2a7e5d68",
"amount": "100000",
"status": "COMPLETED",
"refId": "FW-20260807-0001",
"reference": "Invoice 4471",
"createdAt": "2026-08-07T09:31:05.000Z",
"updatedAt": "2026-08-07T09:34:22.000Z"
}
},
"createdAt": "2026-08-07T09:30:44.000Z",
"updatedAt": "2026-08-07T09:34:22.000Z"
}| Field | Type | Description |
|---|---|---|
id | string (UUID) | The deposit id |
txHash | string | Transaction that carried the deposit |
logIndex | integer | Position of this transfer within the transaction |
chainId | integer | Chain the deposit arrived on |
tokenId | string (UUID) | Token deposited |
amount | string | Deposit amount in the token's smallest unit |
from | string | The address the tokens were sent from |
status | string | PENDING while confirming, COMPLETED once credited, FAILED if it did not credit |
confirmations | integer | Confirmations seen so far |
triggerAddress | string | The beneficiary address that received it |
destination | object | The beneficiary being paid |
result | object | null | The transfer outcome |
result.status | string | PENDING, PROCESSING, COMPLETED, or FAILED |
result.statusReason | string | null | Why it failed. See Deposit status reason values |
result.withdrawal | object | null | The bank transfer, once one exists |
amount and result.withdrawal.amount use different units — the token's smallest unit and sen. Read each from its own field.
A transfer produced this way does not appear in GET /v1/payouts and does not use your prefund balance.
404 NOT_FOUND for an unknown deposit id, one belonging to another account, or one paid into your own bank account.
Deposit status reason values
result.statusReason is null unless result.status is FAILED. These are distinct from the payout status reason values, which describe a payout you created.
| Value | Meaning |
|---|---|
sender_not_allowed | The deposit came from an address you have not allowed |
inactive_destination | The beneficiary was deleted or deactivated |
missing_destination_bank_details | The beneficiary has no bank on file |
feature_disabled | Paying a beneficiary from a deposit is not enabled on your account |
account_frozen, account_suspended, account_terminated | Your account status blocked it |
withdrawal_amount_out_of_range | Below the minimum or above the maximum for your account |
daily_fiat_withdrawal_limit_exceeded | Daily limit reached |
monthly_fiat_withdrawal_limit_exceeded | Monthly limit reached |
fiat_withdrawal_rejected, fiat_withdrawal_failed, fiat_withdrawal_cancelled | The bank transfer did not complete |
provider_error | Anything else the rail reported. Contact BLOX with the deposit id |
Deposits from before this vocabulary settled may still read inactive_beneficiary or missing_beneficiary_bank_details — the older names for inactive_destination and missing_destination_bank_details.
The tokens stay credited to your wallet in every case. Where the cause is yours to fix, fix it and retry the deposit.
Check for a missed deposit
/v1/payouts/deposits/check-missedAPI key + signatureAsks BLOX to look at a transaction it never picked up. Use it when you sent tokens to a beneficiary's address and nothing arrived.
This is the only endpoint that takes a transaction hash. When the transaction turns out to be known already, the response carries the deposit ids — use those with Get a deposit and Retry a deposit. Limited to 30 calls per minute.
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
txHash | string | Yes | 0x and 64 hex characters | Transaction that carried the deposit |
chainId | integer | Yes | An active BLOX network | Chain the transaction is on |
Success response (201)
{
"status": "ALREADY_DETECTED",
"depositIds": ["5e9d0273-8a41-4c62-b0f7-1d3e8c95a460"]
}| Field | Type | Description |
|---|---|---|
status | string | QUEUED if the transaction is now being picked up, ALREADY_DETECTED if BLOX had it |
depositIds | string[] | The deposits in that transaction. Populated on ALREADY_DETECTED, empty on QUEUED |
Check status before reading depositIds: an empty array on QUEUED means the deposits do not exist yet, not that none were found. One transaction can pay several beneficiaries. On QUEUED, wait for the webhook rather than calling again.
Expected errors
| Status | code | When |
|---|---|---|
400 | VALIDATION_FAILED | txHash is not a valid hash, or chainId is not a positive integer |
403 | FEATURE_DISABLED | Paying a beneficiary from a deposit is not enabled on your account |
404 | NOT_FOUND | No active BLOX network matches chainId |
429 | RATE_LIMITED | Over 30 calls in the last minute |
Retry a deposit
/v1/payouts/deposits/{id}/redriveAPI key + signatureRe-evaluates a deposit that was credited but produced no transfer. Use it after fixing the cause — allowing the sender, reactivating the beneficiary, or waiting for a limit to roll over.
Safe to call more than once. A deposit that already paid out returns its existing transfer, and no second transfer is created. Limited to 60 calls per minute.
No request body. Sign @method and @path only.
Success response (201)
The deposit, in the same shape as Get a deposit, read back after the retry.
Expected errors
| Status | code | When |
|---|---|---|
400 | INVALID_REQUEST | The deposit has not finished confirming, so there is nothing to retry |
403 | FEATURE_DISABLED | Paying a beneficiary from a deposit is not enabled on your account |
404 | NOT_FOUND | Unknown deposit, one belonging to another account, or one that did not arrive on a beneficiary's trigger address |
429 | RATE_LIMITED | Over 60 calls in the last minute |
Shared response schemas
Beneficiary object
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Send as beneficiaryId when creating a payout |
name | string | Uppercased beneficiary name |
accountNumber | string | Bank account number |
bank.code | string | Short bank code |
bank.name | string | Bank display name |
autoWithdrawalAddress | string | null | The beneficiary's deposit trigger address, or null if it has none |
createdAt | string (ISO 8601) | Creation time |
updatedAt | string (ISO 8601) | Last update time |
Payout object
| Field | Type | Description |
|---|---|---|
payoutId | string (UUID) | Unique payout identifier |
status | string | INITIATED, SETTLED, REVERSED, or RETURNED |
type | string | STANDARD for your payout; PREFUND_RETURN when BLOX returns part of your prefund balance |
amount | string | Requested amount in sen |
fee | string | Fee in sen |
netAmount | string | Amount sent to the beneficiary |
beneficiaryId | string (UUID) | null | Beneficiary paid; null on a PREFUND_RETURN |
bankAccountId | string (UUID) | null | Your own bank account, on a PREFUND_RETURN; null otherwise |
idempotencyKey | string | null | Original create key; null on a PREFUND_RETURN |
reference | string | Bank-facing transfer reference |
statusReason | string | null | Stable reason key from the table below |
createdAt | string (ISO 8601) | Creation time |
submittedAt | string (ISO 8601) | null | Time handed to the bank rails |
Exactly one of beneficiaryId and bankAccountId is ever set. Everything you create is STANDARD, with a beneficiary.
The create response always has submittedAt: null; read the payout later if you need the submission time. INITIATED covers both queued and bank-pending payouts, and submittedAt distinguishes them.
Status reason values
| Value | Meaning |
|---|---|
pending | Submitted; no terminal bank response yet |
rejected_by_bank | Bank rejected the transfer |
returned_by_bank | Settled transfer was returned |
invalid_beneficiary_bank | Bank cannot be routed to |
under_review | Held for manual resolution; contact BLOX |
provider_unavailable | Temporary provider fault |
reversed_by_support | BLOX manually reversed a stranded payout |
provider_error | Anything else the rail reported. Contact BLOX with the payoutId |
provider_error | Other provider failure; quote the payoutId to BLOX |
Branch on these stable keys, never on human-readable messages. The REST record and Webhook Events use the same values.