Wallet API Reference
All Wallet 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 persisted before the first request.
Amounts are integers in sen in request bodies and strings in responses. Every error uses { "code": "…", "message": "…", "requestId": "…" }; branch on code, never message. See Errors for shared behavior.
| Method | Endpoint | Purpose |
|---|---|---|
GET | /v1/wallet/address | Read EVM and Solana deposit addresses |
GET | /v1/wallet/balance | Read available and pending balances |
GET | /v1/wallet/networks | Resolve active networks and token IDs |
POST | /v1/wallet/token/withdrawals | Send tokens to an external address |
GET | /v1/wallet/token/withdrawals/{id} | Read one token transfer's status |
GET | /v1/wallet/bank-accounts | List linked bank accounts |
POST | /v1/wallet/fiat/withdrawals | Withdraw MYR to a linked bank account |
GET | /v1/wallet/fiat/withdrawals/{id} | Read one fiat withdrawal's status |
POST | /v1/wallet/bank-accounts/{bankAccountId}/address | Give a bank account a deposit trigger address |
GET | /v1/wallet/bank-accounts/{bankAccountId}/address/whitelist | List the senders allowed to trigger it |
POST | /v1/wallet/bank-accounts/{bankAccountId}/address/whitelist | Allow a sender |
PATCH | /v1/wallet/bank-accounts/{bankAccountId}/address/whitelist/{senderId} | Pause a sender without losing it |
DELETE | /v1/wallet/bank-accounts/{bankAccountId}/address/whitelist/{senderId} | Stop allowing a sender |
GET | /v1/wallet/deposits/{id} | Read a deposit and the withdrawal it triggered |
POST | /v1/wallet/deposits/check-missed | Have BLOX look at a transaction it never picked up |
POST | /v1/wallet/deposits/{id}/redrive | Retry a deposit that produced no withdrawal |
GET | /v1/wallet/transactions | List wallet movements for reconciliation |
Get wallet address
/v1/wallet/addressAPI keyReturns the wallet's deposit addresses. Missing addresses are created automatically.
Response — 200
{
"evmAddress": "0x742d35Cc6634C0532925a3b333Bc9e1234f8bD21",
"solAddress": "DRpbCBMxVnDK7maPM5tGv6MvB3v1sRMC99PZ8okm99hy"
}| Field | Type | Description |
|---|---|---|
evmAddress | string | Deposit address shared by supported EVM networks |
solAddress | string | Solana deposit address |
Error responses
| Status | code | When |
|---|---|---|
401 | UNAUTHORIZED | API key is missing, unknown, or inactive |
403 | FEATURE_DISABLED | Wallet API 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 wallet balance
/v1/wallet/balanceAPI keyReturns spendable and pending wallet balances.
Response — 200
{
"walletBalance": "250000",
"pendingWithdrawal": "0"
}| Field | Type | Description |
|---|---|---|
walletBalance | string | Spendable wallet balance in sen |
pendingWithdrawal | string | Balance currently involved in outbound withdrawals, in sen |
Error responses
| Status | code | When |
|---|---|---|
401 | UNAUTHORIZED | API key is missing, unknown, or inactive |
403 | FEATURE_DISABLED | Wallet API 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 supported networks
/v1/wallet/networksAPI keyReturns active networks with their active tokens. Resolve tokenId from this endpoint at runtime; IDs differ between sandbox and production.
| Query | Type | Required | Description |
|---|---|---|---|
id | string | No | Return one network by network ID |
tokenId | string (UUID) | No | Return the network containing this token |
Each network includes id, name, type, and tokens. Use a token's id as tokenId in Wallet transfers and Onramp checkouts. Match EVM tokens to 0x addresses and Solana tokens to Base58 addresses.
Contract addresses and chain IDs also appear on Environments & Chains; prefer this endpoint at runtime.
Error responses
| Status | code | When |
|---|---|---|
400 | VALIDATION_FAILED | id or tokenId is malformed |
401 | UNAUTHORIZED | API key is missing, unknown, or inactive |
403 | FEATURE_DISABLED | Wallet API 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
400 VALIDATION_FAILED
For a malformed tokenId:
{
"code": "VALIDATION_FAILED",
"message": "tokenId: Invalid UUID",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}Create token transfer
/v1/wallet/token/withdrawalsAPI key + signatureTransfers a token from the BLOX wallet to an external address. The endpoint is limited to 30 requests per minute per account.
Header
| Header | Required | Description |
|---|---|---|
Idempotency-Key | Yes | UUID v4 persisted for this transfer before the first request |
Body
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
tokenId | string (UUID) | Yes | Active token | ID from GET /v1/wallet/networks |
addressTo | string | Yes | Must match the token network | Recipient wallet address |
amount | integer | Yes | 1000–100000000 sen | Total wallet debit (RM10–RM1,000,000) |
reference | string | No | Maximum 32 characters | Your reconciliation reference |
EVM addresses use 0x plus 40 hexadecimal characters. Solana addresses use Base58. Transfers to your own deposit address, a contract address, or another restricted destination are rejected.
The requested amount is the total wallet debit. Network fees, when applicable, are deducted before delivery; the response gives the net amount and separate fee.
Response — 200
{
"id": "9b3bd9db-75d8-44dc-a74b-16fe968a01c7",
"status": "CREATED",
"toAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f8bD21",
"amount": "10000",
"fee": "0",
"reference": "ORDER-4471",
"source": "API",
"tokenId": "550e8400-e29b-41d4-a716-446655440000",
"token": {
"symbol": "MYRC",
"name": "MYR Coin",
"network": { "id": "ethereum", "name": "Ethereum", "type": "EVM" }
},
"txHash": null,
"confirmations": null,
"confirmedAt": null,
"createdAt": "2026-01-16T10:30:00.000Z",
"updatedAt": "2026-01-16T10:30:00.000Z"
}The initial status is CREATED for EVM transfers and PENDING for Solana transfers. See the Token transfer object for every field and status.
Persist one UUID v4 before sending. Reuse that key after no response, a timeout, 202, or 5xx. Reusing it with the same body returns the original transfer for 24 hours; a different body returns 422 VALIDATION_FAILED. After a 4xx, fix the request and use a new key.
Error responses
| Status | code | When |
|---|---|---|
400 | INVALID_REQUEST | The idempotency key, token, or destination is not accepted |
400 | VALIDATION_FAILED | The body, address, amount, or reference is invalid |
400 | INSUFFICIENT_BALANCE | The wallet cannot cover the requested debit |
400 | LIMIT_EXCEEDED | A configured daily or monthly limit is reached |
401 | UNAUTHORIZED | API key or request signature is missing or invalid |
403 | FEATURE_DISABLED | Wallet API is not enabled for the account |
403 | ACCOUNT_FROZEN | The account is frozen |
403 | ACCOUNT_TERMINATED | The account is terminated |
403 | ACCOUNT_PENDING_VERIFICATION | The account is pending verification |
422 | VALIDATION_FAILED | The idempotency key was used with another body |
429 | RATE_LIMITED | The 30-per-minute create limit is exceeded |
5xx | INTERNAL_ERROR | Unexpected BLOX failure; report requestId |
Error examples
400 INVALID_REQUEST
{
"code": "INVALID_REQUEST",
"message": "Missing idempotency key",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}400 VALIDATION_FAILED
For a request with amount: 999:
{
"code": "VALIDATION_FAILED",
"message": "amount: Amount can't be less than 10 MYR",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}400 INSUFFICIENT_BALANCE
{
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient MYRC balance in wallet.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}400 LIMIT_EXCEEDED
{
"code": "LIMIT_EXCEEDED",
"message": "Daily transaction limit exceeded.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}401 UNAUTHORIZED
{
"code": "UNAUTHORIZED",
"message": "API key is required",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 FEATURE_DISABLED
{
"code": "FEATURE_DISABLED",
"message": "Feature wallet_api is not enabled for this account.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 ACCOUNT_FROZEN
{
"code": "ACCOUNT_FROZEN",
"message": "Your account has been frozen. Please contact support.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 ACCOUNT_TERMINATED
{
"code": "ACCOUNT_TERMINATED",
"message": "Your account has been terminated. Please contact support.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 ACCOUNT_PENDING_VERIFICATION
{
"code": "ACCOUNT_PENDING_VERIFICATION",
"message": "Your account is pending verification. This action is not allowed for this account at this time.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}422 VALIDATION_FAILED
{
"code": "VALIDATION_FAILED",
"message": "Idempotency key used with different request payload",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}429 RATE_LIMITED
{
"code": "RATE_LIMITED",
"message": "Too many token withdrawals. Please try again later.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}500 INTERNAL_ERROR
{
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}Get token transfer
/v1/wallet/token/withdrawals/{id}API keyReturns one token transfer from the moment it is created. Use this endpoint to monitor status.
| Path | Type | Description |
|---|---|---|
id | string (UUID) | id returned by the create request |
Response — 200: Token transfer object. Unknown and cross-account IDs return 404 NOT_FOUND.
An EVM transfer is absent from GET /v1/wallet/transactions while it remains CREATED; this resource endpoint is therefore the authoritative status from creation.
Error responses
| Status | code | When |
|---|---|---|
401 | UNAUTHORIZED | API key is missing, unknown, or inactive |
403 | FEATURE_DISABLED | Wallet API is not enabled for the account |
403 | ACCOUNT_TERMINATED | The account is terminated |
404 | NOT_FOUND | The transfer 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
404 NOT_FOUND
{
"code": "NOT_FOUND",
"message": "Token withdrawal not found",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}List bank accounts
/v1/wallet/bank-accountsAPI keyReturns active bank accounts linked to the BLOX account. Use a verified account's id as bankAccountId when creating a fiat withdrawal.
| Query | Type | Required | Constraints | Description |
|---|---|---|---|---|
search | string | No | — | Filter by account name |
limit | integer | No | 1–100, default 25 | Records per page |
cursor | string | No | Previous page's last id | Omit for the first page |
Response — 200
{
"data": [
{
"id": "6639e2e8-9d71-4a77-9fd7-34fcd0ce5355",
"name": "Business account",
"accountNumber": "123456789012",
"verified": true,
"bank": { "code": "MBBM", "name": "Maybank" },
"createdAt": "2026-01-10T04:00:00.000Z",
"updatedAt": "2026-01-10T04:00:00.000Z"
}
],
"hasMore": false,
"nextCursor": null
}| Field | Type | Description |
|---|---|---|
id | string (UUID) | Send as bankAccountId when withdrawing |
name | string | Account label |
accountNumber | string | Unmasked bank account number |
verified | boolean | Whether BLOX has verified the account |
bank | object | null | { code, name } |
createdAt / updatedAt | string | ISO 8601 timestamps |
Iterate until hasMore is false. There is no total.
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 | Wallet API 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
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"
}Create fiat withdrawal
/v1/wallet/fiat/withdrawalsAPI key + signatureWithdraws MYR from the BLOX wallet to a linked bank account. The endpoint is limited to 30 requests per minute per account.
Header
| Header | Required | Description |
|---|---|---|
Idempotency-Key | Yes | UUID v4 persisted for this withdrawal before the first request |
Body
| Field | Type | Required | Constraints | Description |
|---|---|---|---|---|
bankAccountId | string (UUID) | Yes | Active linked account | ID from GET /v1/wallet/bank-accounts |
amount | integer | Yes | 1000–100000000 sen | Withdrawal amount (RM10–RM1,000,000) |
reference | string | No | Maximum 20 characters | Your reconciliation reference |
Individual accounts have an additional RM300,000 maximum; business accounts can use the full per-request range. Other account-level limits may apply.
Response — 200
{
"id": "1de31ea3-c2b5-454b-a1f0-547c21738aef",
"status": "PENDING",
"amount": "50000",
"fee": "0",
"reference": "WD-4471",
"refId": "FW-20260116-A1B2C3",
"source": "API",
"destination": {
"name": "ADA LOVELACE",
"accountNumber": "1234567890",
"bank": { "code": "MBBM", "name": "Maybank" }
},
"confirmedAt": null,
"createdAt": "2026-01-16T10:30:00.000Z",
"updatedAt": "2026-01-16T10:30:00.000Z"
}See the Fiat withdrawal object for every field and status. Idempotency and retry behavior match token transfers: persist the key before sending and reuse it for the same logical withdrawal.
Error responses
| Status | code | When |
|---|---|---|
400 | INVALID_REQUEST | The idempotency key or account-specific amount is not accepted |
400 | VALIDATION_FAILED | The body, amount, or reference is invalid |
400 | INSUFFICIENT_BALANCE | The wallet cannot cover the withdrawal |
400 | LIMIT_EXCEEDED | A configured daily or monthly limit is reached |
401 | UNAUTHORIZED | API key or request signature is missing or invalid |
403 | FEATURE_DISABLED | Wallet API is not enabled for the account |
403 | ACCOUNT_FROZEN | The account is frozen |
403 | ACCOUNT_TERMINATED | The account is terminated |
403 | ACCOUNT_PENDING_VERIFICATION | The account is pending verification |
404 | NOT_FOUND | The bank account is unknown, inactive, or belongs to another account |
422 | VALIDATION_FAILED | The idempotency key was used with another body |
429 | RATE_LIMITED | The 30-per-minute create limit is exceeded |
5xx | INTERNAL_ERROR | Unexpected BLOX failure; report requestId |
Error examples
400 INVALID_REQUEST
{
"code": "INVALID_REQUEST",
"message": "Missing idempotency key",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}400 VALIDATION_FAILED
For a request with amount: 999:
{
"code": "VALIDATION_FAILED",
"message": "amount: Amount can't be less than 10 MYR",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}400 INSUFFICIENT_BALANCE
{
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient MYRC balance in wallet.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}400 LIMIT_EXCEEDED
{
"code": "LIMIT_EXCEEDED",
"message": "Daily transaction limit exceeded.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}401 UNAUTHORIZED
{
"code": "UNAUTHORIZED",
"message": "API key is required",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 FEATURE_DISABLED
{
"code": "FEATURE_DISABLED",
"message": "Feature wallet_api is not enabled for this account.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 ACCOUNT_FROZEN
{
"code": "ACCOUNT_FROZEN",
"message": "Your account has been frozen. Please contact support.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 ACCOUNT_TERMINATED
{
"code": "ACCOUNT_TERMINATED",
"message": "Your account has been terminated. Please contact support.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}403 ACCOUNT_PENDING_VERIFICATION
{
"code": "ACCOUNT_PENDING_VERIFICATION",
"message": "Your account is pending verification. This action is not allowed for this account at this time.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}404 NOT_FOUND
{
"code": "NOT_FOUND",
"message": "Bank account not found",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}422 VALIDATION_FAILED
{
"code": "VALIDATION_FAILED",
"message": "Idempotency key used with different request payload",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}429 RATE_LIMITED
{
"code": "RATE_LIMITED",
"message": "Too many fiat withdrawals. Please try again later.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}500 INTERNAL_ERROR
{
"code": "INTERNAL_ERROR",
"message": "An unexpected error occurred.",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}Get fiat withdrawal
/v1/wallet/fiat/withdrawals/{id}API keyReturns one fiat withdrawal. Poll until COMPLETED, FAILED, or REJECTED.
| Path | Type | Description |
|---|---|---|
id | string (UUID) | id returned by the create request |
Response — 200: Fiat withdrawal 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 | Wallet API is not enabled for the account |
403 | ACCOUNT_TERMINATED | The account is terminated |
404 | NOT_FOUND | The withdrawal 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
404 NOT_FOUND
{
"code": "NOT_FOUND",
"message": "Fiat withdrawal not found",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}Create a deposit trigger address
/v1/wallet/bank-accounts/{bankAccountId}/addressAPI key + signatureGives a linked bank account an on-chain address. Tokens sent to it are withdrawn to that bank account automatically, with no create request from you. See Withdraw automatically on deposit.
The bank account must be active. Calling this again returns the same address — a bank account has one, for its lifetime — so no Idempotency-Key is needed. Limited to 20 calls per minute.
Success response (201)
{
"address": "0x7c1a3e889d2b4f618a441f0b6d3c9a5588ab01cd",
"network": "EVM",
"destination": {
"type": "BANK_ACCOUNT",
"id": "b21f4c77-3e5a-4d90-9c18-6a2f7e0b4d31"
}
}| Field | Type | Description |
|---|---|---|
address | string | Send supported tokens here |
network | string | EVM |
destination.type | string | BANK_ACCOUNT |
destination.id | string (UUID) | The bank account that gets paid |
The address ignores every deposit until you allow at least one sender.
Expected errors
| Status | code | When |
|---|---|---|
403 | FEATURE_DISABLED | Automatic withdrawal on deposit is not enabled on your account |
404 | NOT_FOUND | Unknown bank account, 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/wallet/bank-accounts/{bankAccountId}/address/whitelistAPI keyReturns the senders allowed to trigger this bank account'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 |
Disabled senders are listed too. They count toward the 50-sender limit until you remove them.
404 NOT_FOUND if the bank account has no trigger address yet.
Allow a sender
/v1/wallet/bank-accounts/{bankAccountId}/address/whitelistAPI key + signatureAllows one address to trigger withdrawals to this bank account. 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 bank account has no trigger address, or is not yours |
Disable or re-enable a sender
/v1/wallet/bank-accounts/{bankAccountId}/address/whitelist/{senderId}API key + signatureTurns a sender off without losing it. A disabled sender stops triggering withdrawals 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/wallet/bank-accounts/{bankAccountId}/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/wallet/deposits/{id}API keyReturns a deposit and, when it triggered one, the withdrawal it produced. This is the same payload the deposit webhook delivers.
Success response (200)
{
"id": "5e9d0273-8a41-4c62-b0f7-1d3e8c95a460",
"txHash": "0x5d53558791c9346d644d077354420f9a93600acf54eb806ecb9aad077c103ee3",
"logIndex": 12,
"chainId": 1,
"tokenId": "a71c4e08-2f96-4b3d-85ae-6c0f7d21b943",
"amount": "100000",
"from": "0x9a3f7c21b8e04d6f5a19c2e70b48d3f61a5e9d02",
"status": "COMPLETED",
"confirmations": 24,
"triggerAddress": "0x7c1a3e889d2b4f618a441f0b6d3c9a5588ab01cd",
"destination": {
"type": "BANK_ACCOUNT",
"id": "b21f4c77-3e5a-4d90-9c18-6a2f7e0b4d31",
"name": "ACME SDN BHD"
},
"result": {
"status": "COMPLETED",
"statusReason": null,
"withdrawal": {
"id": "c4a80f13-6d29-4e75-83b1-9f0c2a7e5d68",
"amount": "100000",
"status": "COMPLETED",
"refId": "FW-20260807-0001",
"reference": "ACME payout",
"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; matches GET /v1/wallet/networks |
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 | null | The address that received it, or null for an ordinary deposit |
destination | object | null | The bank account being paid, or null |
result | object | null | The withdrawal outcome, or null when nothing was triggered |
result.status | string | PENDING, PROCESSING, COMPLETED, or FAILED |
result.statusReason | string | null | Why it failed. See Status reason values |
result.withdrawal | object | null | The fiat withdrawal object, once one exists |
amount and result.withdrawal.amount use different units — the token's smallest unit and sen. Read each from its own field.
404 NOT_FOUND for an unknown deposit id, or one belonging to another account.
Deposit status reason values
result.statusReason is null unless result.status is FAILED.
| Value | Meaning |
|---|---|
sender_not_allowed | The deposit came from an address you have not allowed |
inactive_destination | The bank account was removed or deactivated |
missing_destination_bank_details | The bank account has no bank on file |
feature_disabled | Automatic withdrawal on 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 |
The tokens stay credited to your wallet in every case. Where the cause is yours to fix — an address you had not allowed, a bank account you reactivated, a limit that has since rolled over — fix it and retry the deposit.
Check for a missed deposit
/v1/wallet/deposits/check-missedAPI key + signatureAsks BLOX to look at a transaction it never picked up. Use it when you sent tokens 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 carry several deposits. 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 | Automatic withdrawal on 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/wallet/deposits/{id}/redriveAPI key + signatureRe-evaluates a deposit that was credited but produced no bank transfer. Use it after fixing the cause — allowing the sender, reactivating the bank account, or waiting for a limit to roll over.
Safe to call more than once. A deposit that already paid out returns its existing withdrawal, 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 | Automatic withdrawal on 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 trigger address |
429 | RATE_LIMITED | Over 60 calls in the last minute |
List wallet transactions
/v1/wallet/transactionsAPI keyReturns wallet movements newest first. Use it for history and reconciliation; use the resource-specific read endpoints to monitor one withdrawal.
| Query | Type | Required | Constraints | Description |
|---|---|---|---|---|
startDt | string | No | ISO 8601 datetime | Created on or after this time |
endDt | string | No | ISO 8601 datetime | Created on or before this time |
type | string | No | IN or OUT | Direction |
mode | string | No | FIAT or TOKEN | Transaction mode |
limit | integer | No | 1–100, default 25 | Records per page |
cursor | string | No | Previous response's nextCursor | Omit for the first page |
Response — 200
{
"data": [
{
"transactionId": "9b3bd9db-75d8-44dc-a74b-16fe968a01c7",
"type": "OUT",
"mode": "TOKEN",
"status": "PENDING",
"amount": "-10000",
"fee": "0",
"effectiveAmount": "-10000",
"beneficiary": "0x742d35Cc6634C0532925a3b844Bc9e7595f8bD21",
"reference": "ORDER-4471",
"refId": "",
"source": "API",
"networkId": "ethereum",
"createdAt": "2026-01-16T10:30:00.000Z",
"confirmedAt": null
}
],
"hasMore": true,
"nextCursor": "MjAyNi0wMS0xNlQxMDozMDowMC4wMDBafDliM2Jk…"
}Pass nextCursor back as cursor until hasMore is false. There is no total; cursors are opaque. Rows in CREATED status are omitted until the status advances.
| Field | Type | Description |
|---|---|---|
transactionId | string (UUID) | Wallet transaction identifier |
type | string | IN or OUT |
mode | string | FIAT or TOKEN |
status | string | Current transaction status |
amount | string | Signed amount in sen |
fee | string | Fee in sen |
effectiveAmount | string | Net signed wallet movement in sen |
beneficiary | string | null | Destination address, bank account, or other recipient label |
reference | string | null | Your reconciliation reference |
refId | string | BLOX reference when available |
source | string | Origin of the transaction, such as API |
networkId | string | null | Blockchain network for token movements |
createdAt | string | ISO 8601 creation timestamp |
confirmedAt | string | null | ISO 8601 completion timestamp |
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 | Wallet API 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
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"
}Shared response schemas
Token transfer object
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Unique transfer identifier |
status | string | CREATED, PENDING, PROCESSING, COMPLETED, or FAILED |
toAddress | string | Recipient wallet address |
amount | string | Net amount delivered, in sen |
fee | string | Fee deducted from the requested amount, in sen |
reference | string | null | Your reconciliation reference |
source | string | API for API-created transfers |
tokenId | string (UUID) | Selected token identifier |
token | object | { symbol, name, network: { id, name, type } } |
txHash | string | null | On-chain transaction hash after broadcast |
confirmations | number | null | Confirmations observed so far |
confirmedAt | string | null | ISO 8601 completion time |
createdAt / updatedAt | string | ISO 8601 timestamps |
Fiat withdrawal object
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Unique withdrawal identifier |
status | string | PENDING, PROCESSING, COMPLETED, FAILED, or REJECTED |
amount | string | Withdrawal amount in sen |
fee | string | Withdrawal fee in sen |
reference | string | null | Your reconciliation reference |
refId | string | BLOX withdrawal reference to quote to support |
source | string | API for API-created withdrawals |
destination | object | null | { name, accountNumber, bank: { code, name } } |
confirmedAt | string | null | ISO 8601 completion time |
createdAt / updatedAt | string | ISO 8601 timestamps |