Skip to content
LogoLogo

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.

MethodEndpointPurpose
GET/v1/payout/prefund/balanceRead spendable and pending balances
GET/v1/payouts/active-banksResolve a beneficiary bank code
POST/v1/payouts/beneficiariesRegister a reusable beneficiary
GET/v1/payouts/beneficiariesList active beneficiaries
GET/v1/payouts/beneficiaries/{beneficiaryId}Get one beneficiary
DELETE/v1/payouts/beneficiaries/{beneficiaryId}Deactivate a beneficiary
POST/v1/payoutsCreate and submit a payout
GET/v1/payouts/{id}Read a payout for reconciliation
POST/v1/payouts/beneficiaries/{beneficiaryId}/addressGive a beneficiary a deposit trigger address
GET/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelistList the senders allowed to trigger it
POST/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelistAllow a sender
PATCH/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelist/{senderId}Pause a sender without losing it
DELETE/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelist/{senderId}Stop allowing a sender
GET/v1/payouts/deposits/{id}Read a deposit and the transfer it triggered
POST/v1/payouts/deposits/check-missedHave BLOX look at a transaction it never picked up
POST/v1/payouts/deposits/{id}/redriveRetry a deposit that produced no transfer

Get prefund balance

GET/v1/payout/prefund/balanceAPI key

Returns 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"
}
FieldTypeDescription
availablestringSpendable amount in sen
inFlightstringnetAmount of accepted payouts that are not final
receivablestringNormally "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
StatuscodeWhen
401UNAUTHORIZEDAPI key is missing, unknown, or inactive
403FEATURE_DISABLEDPayout is not enabled for the account
403ACCOUNT_TERMINATEDThe account is terminated
429RATE_LIMITEDThe route or account rate limit is exceeded
5xxINTERNAL_ERRORUnexpected BLOX failure; report requestId

Error examples

401 UNAUTHORIZED
{
  "code": "UNAUTHORIZED",
  "message": "API key is required",
  "requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}

Get active banks

GET/v1/payouts/active-banksAPI key

Returns 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"
  }
]
FieldTypeDescription
namestringBank or e-wallet name
bankCodestringThe bank's BIC

Use bankCode wherever the API asks for bankCode.

Error responses
StatuscodeWhen
401UNAUTHORIZEDAPI key is missing, unknown, or inactive
403FEATURE_DISABLEDPayout is not enabled for the account
403ACCOUNT_TERMINATEDThe account is terminated
429RATE_LIMITEDThe route or account rate limit is exceeded
5xxINTERNAL_ERRORUnexpected BLOX failure; report requestId

Error examples

401 UNAUTHORIZED
{
  "code": "UNAUTHORIZED",
  "message": "API key is required",
  "requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}

Create beneficiary

POST/v1/payouts/beneficiariesAPI key + signature

Registers a reusable beneficiary. This endpoint requires an Idempotency-Key UUID v4 and is limited to 20 requests per minute per account.

FieldTypeRequiredConstraints
namestringYes2–96 characters
bankCodestringYes1–11 characters; use a code from /v1/payouts/active-banks
accountNumberstringYes3–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
StatuscodeWhen
400VALIDATION_FAILEDA body field is missing, malformed, or outside its constraint
400INVALID_REQUESTIdempotency-Key is missing or malformed
400UNKNOWN_BENEFICIARYbankCode is not in your /v1/payouts/active-banks list
401UNAUTHORIZEDAPI key or signature is missing or invalid
403LIMIT_EXCEEDEDThe active-beneficiary cap is reached
403FEATURE_DISABLEDPayout is not enabled for the account
403ACCOUNT_TERMINATEDThe account is terminated
422VALIDATION_FAILEDThe idempotency key was already used with a different body
429RATE_LIMITEDThe route or account rate limit is exceeded
5xxINTERNAL_ERRORUnexpected 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

GET/v1/payouts/beneficiariesAPI key

Returns active beneficiaries, newest first.

QueryTypeDescription
limitinteger1–100; default 25
cursorstringOpaque nextCursor from the previous response
searchstringCase-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
StatuscodeWhen
400VALIDATION_FAILEDA query parameter is malformed or outside its constraint
401UNAUTHORIZEDAPI key is missing, unknown, or inactive
403FEATURE_DISABLEDPayout is not enabled for the account
403ACCOUNT_TERMINATEDThe account is terminated
429RATE_LIMITEDThe account rate limit is exceeded
5xxINTERNAL_ERRORUnexpected 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

GET/v1/payouts/beneficiaries/{beneficiaryId}API key

Returns one active beneficiary. Unknown, inactive, and cross-account IDs return 404 NOT_FOUND.

Path parameterTypeDescription
beneficiaryIdstring (UUID)Beneficiary owned by your account

Response — 200: Beneficiary object.

Error responses
StatuscodeWhen
401UNAUTHORIZEDAPI key is missing, unknown, or inactive
403FEATURE_DISABLEDPayout is not enabled for the account
403ACCOUNT_TERMINATEDThe account is terminated
404NOT_FOUNDBeneficiary is unknown, inactive, or belongs to another account
429RATE_LIMITEDThe account rate limit is exceeded
5xxINTERNAL_ERRORUnexpected BLOX failure; report requestId

Error examples

401 UNAUTHORIZED
{
  "code": "UNAUTHORIZED",
  "message": "API key is required",
  "requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}

Delete beneficiary

DELETE/v1/payouts/beneficiaries/{beneficiaryId}API key + signature

Soft-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
StatuscodeWhen
401UNAUTHORIZEDAPI key or signature is missing or invalid
403FEATURE_DISABLEDPayout is not enabled for the account
403ACCOUNT_TERMINATEDThe account is terminated
404NOT_FOUNDBeneficiary is unknown, inactive, or belongs to another account
429RATE_LIMITEDThe account rate limit is exceeded
5xxINTERNAL_ERRORUnexpected BLOX failure; report requestId

Error examples

401 UNAUTHORIZED
{
  "code": "UNAUTHORIZED",
  "message": "API key is required",
  "requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}

Create payout

POST/v1/payoutsAPI key + signature

Creates 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

HeaderRequiredDescription
Idempotency-KeyYesUUID v4 persisted per logical payout and reused on retry

Body

FieldTypeRequiredConstraints
amountintegerYes10010000000 sen
feeModestringYesDEDUCT_FROM_AMOUNT or CHARGE_TO_PREFUND
beneficiaryIdstring (UUID)ConditionalExactly one of beneficiaryId or beneficiary
beneficiaryobjectConditionalSame fields as Create beneficiary
referencestringNo1–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, or 503 with the same key.
  • Retry a rejected 4xx with 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
StatuscodeWhen
400VALIDATION_FAILEDThe body is invalid, including both or neither beneficiary fields
400INVALID_REQUESTThe idempotency key is invalid, bank verification fails, or the net amount is below RM1
400INSUFFICIENT_BALANCEThe prefund cannot cover netAmount + fee
400UNKNOWN_BENEFICIARYThe beneficiary is inactive, cross-account, or the bank code is not in your /v1/payouts/active-banks list
400LIMIT_EXCEEDEDA configured daily or monthly payout limit is reached
401UNAUTHORIZEDAPI key or signature is missing or invalid
403LIMIT_EXCEEDEDStoring a new inline beneficiary would exceed the active-beneficiary cap
403FEATURE_DISABLEDPayout is disabled or suspended by an uncovered prefund reversal
403ACCOUNT_FROZEN / ACCOUNT_PENDING_VERIFICATION / ACCOUNT_TERMINATEDThe account state blocks payouts
422VALIDATION_FAILEDThe idempotency key was already used with a different body
429RATE_LIMITEDThe route or account rate limit is exceeded
503SERVICE_UNAVAILABLEPayout creation is paused; nothing was created or debited
5xxINTERNAL_ERRORUnexpected 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

GET/v1/payouts/{id}API key

Returns 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 parameterTypeDescription
idstring (UUID)Payout owned by your account

Response — 200: Payout object. Unknown and cross-account IDs return 404 NOT_FOUND.

Error responses
StatuscodeWhen
401UNAUTHORIZEDAPI key is missing, unknown, or inactive
403FEATURE_DISABLEDPayout is disabled, including suspension by an uncovered prefund reversal
403ACCOUNT_TERMINATEDThe account is terminated
404NOT_FOUNDPayout is unknown or belongs to another account
429RATE_LIMITEDThe route or account rate limit is exceeded
5xxINTERNAL_ERRORUnexpected 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

POST/v1/payouts/beneficiaries/{beneficiaryId}/addressAPI key + signature

Gives 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"
  }
}
FieldTypeDescription
addressstringSend supported tokens here
networkstringEVM
destination.typestringBENEFICIARY
destination.idstring (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
StatuscodeWhen
403FEATURE_DISABLEDPaying a beneficiary from a deposit is not enabled on your account
404NOT_FOUNDUnknown beneficiary, one belonging to another account, or one that is not active
429RATE_LIMITEDOver 20 calls in the last minute

List allowed senders

GET/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelistAPI key

Returns 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"
  }
]
FieldTypeDescription
idstring (UUID)Pass this to disable or remove the sender
addressstringStored lowercase
labelstring | nullYour own note
activebooleanOnly active senders are accepted; see disable
createdAtstring (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

POST/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelistAPI key + signature

Allows one address to trigger payouts to this beneficiary. Up to 50 per address.

FieldTypeRequiredConstraintsDescription
addressstringYes0x and 40 hex charactersThe address you send from. Casing is ignored
labelstringNo1–120 charactersYour own note, returned on reads

Success response (201)

Returns the created sender in the same shape as List allowed senders.

Expected errors
StatuscodeWhen
400VALIDATION_FAILEDaddress is not a valid address, or label is longer than 120 characters
400CONFLICTThat address is already allowed here
403LIMIT_EXCEEDEDThe address already has 50 allowed senders
404NOT_FOUNDThe beneficiary has no trigger address, or is not yours

Disable or re-enable a sender

PATCH/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelist/{senderId}API key + signature

Turns 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

FieldTypeDescription
activebooleanfalse to disable, true to re-enable

Success response (200)

Returns the sender in the same shape as List allowed senders.

Expected errors
StatuscodeWhen
400VALIDATION_FAILEDactive is missing or is not a boolean
403ACCOUNT_FROZENThe account is frozen. Removing a sender still works
403ACCOUNT_PENDING_VERIFICATIONThe account is pending verification
404NOT_FOUNDThe sender id is unknown or belongs to a different address

Remove an allowed sender

DELETE/v1/payouts/beneficiaries/{beneficiaryId}/address/whitelist/{senderId}API key + signature

Stops 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

GET/v1/payouts/deposits/{id}API key

Returns 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"
}
FieldTypeDescription
idstring (UUID)The deposit id
txHashstringTransaction that carried the deposit
logIndexintegerPosition of this transfer within the transaction
chainIdintegerChain the deposit arrived on
tokenIdstring (UUID)Token deposited
amountstringDeposit amount in the token's smallest unit
fromstringThe address the tokens were sent from
statusstringPENDING while confirming, COMPLETED once credited, FAILED if it did not credit
confirmationsintegerConfirmations seen so far
triggerAddressstringThe beneficiary address that received it
destinationobjectThe beneficiary being paid
resultobject | nullThe transfer outcome
result.statusstringPENDING, PROCESSING, COMPLETED, or FAILED
result.statusReasonstring | nullWhy it failed. See Deposit status reason values
result.withdrawalobject | nullThe 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.

ValueMeaning
sender_not_allowedThe deposit came from an address you have not allowed
inactive_destinationThe beneficiary was deleted or deactivated
missing_destination_bank_detailsThe beneficiary has no bank on file
feature_disabledPaying a beneficiary from a deposit is not enabled on your account
account_frozen, account_suspended, account_terminatedYour account status blocked it
withdrawal_amount_out_of_rangeBelow the minimum or above the maximum for your account
daily_fiat_withdrawal_limit_exceededDaily limit reached
monthly_fiat_withdrawal_limit_exceededMonthly limit reached
fiat_withdrawal_rejected, fiat_withdrawal_failed, fiat_withdrawal_cancelledThe bank transfer did not complete
provider_errorAnything 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

POST/v1/payouts/deposits/check-missedAPI key + signature

Asks 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.

FieldTypeRequiredConstraintsDescription
txHashstringYes0x and 64 hex charactersTransaction that carried the deposit
chainIdintegerYesAn active BLOX networkChain the transaction is on

Success response (201)

{
  "status": "ALREADY_DETECTED",
  "depositIds": ["5e9d0273-8a41-4c62-b0f7-1d3e8c95a460"]
}
FieldTypeDescription
statusstringQUEUED if the transaction is now being picked up, ALREADY_DETECTED if BLOX had it
depositIdsstring[]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
StatuscodeWhen
400VALIDATION_FAILEDtxHash is not a valid hash, or chainId is not a positive integer
403FEATURE_DISABLEDPaying a beneficiary from a deposit is not enabled on your account
404NOT_FOUNDNo active BLOX network matches chainId
429RATE_LIMITEDOver 30 calls in the last minute

Retry a deposit

POST/v1/payouts/deposits/{id}/redriveAPI key + signature

Re-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
StatuscodeWhen
400INVALID_REQUESTThe deposit has not finished confirming, so there is nothing to retry
403FEATURE_DISABLEDPaying a beneficiary from a deposit is not enabled on your account
404NOT_FOUNDUnknown deposit, one belonging to another account, or one that did not arrive on a beneficiary's trigger address
429RATE_LIMITEDOver 60 calls in the last minute

Shared response schemas

Beneficiary object

FieldTypeDescription
idstring (UUID)Send as beneficiaryId when creating a payout
namestringUppercased beneficiary name
accountNumberstringBank account number
bank.codestringShort bank code
bank.namestringBank display name
autoWithdrawalAddressstring | nullThe beneficiary's deposit trigger address, or null if it has none
createdAtstring (ISO 8601)Creation time
updatedAtstring (ISO 8601)Last update time

Payout object

FieldTypeDescription
payoutIdstring (UUID)Unique payout identifier
statusstringINITIATED, SETTLED, REVERSED, or RETURNED
typestringSTANDARD for your payout; PREFUND_RETURN when BLOX returns part of your prefund balance
amountstringRequested amount in sen
feestringFee in sen
netAmountstringAmount sent to the beneficiary
beneficiaryIdstring (UUID) | nullBeneficiary paid; null on a PREFUND_RETURN
bankAccountIdstring (UUID) | nullYour own bank account, on a PREFUND_RETURN; null otherwise
idempotencyKeystring | nullOriginal create key; null on a PREFUND_RETURN
referencestringBank-facing transfer reference
statusReasonstring | nullStable reason key from the table below
createdAtstring (ISO 8601)Creation time
submittedAtstring (ISO 8601) | nullTime 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

ValueMeaning
pendingSubmitted; no terminal bank response yet
rejected_by_bankBank rejected the transfer
returned_by_bankSettled transfer was returned
invalid_beneficiary_bankBank cannot be routed to
under_reviewHeld for manual resolution; contact BLOX
provider_unavailableTemporary provider fault
reversed_by_supportBLOX manually reversed a stranded payout
provider_errorAnything else the rail reported. Contact BLOX with the payoutId
provider_errorOther 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.