Error Responses
BLOX APIs use standard HTTP status codes and return JSON error bodies.
Error Format
Every error on /v1 and /checkout has the same three fields:
{
"code": "UNAUTHORIZED",
"message": "API key is required",
"requestId": "9f21ab04-6c3e-4d90-b1a7-8e5f2c0d4416"
}| Field | Type | Description |
|---|---|---|
code | string | Stable SCREAMING_SNAKE_CASE identifier. This is the contract — branch on it |
message | string | For humans. May be reworded at any time; never parse it |
requestId | string (uuid) | Identifies the request in BLOX logs. Quote it when reporting a 5xx |
Adding a code is not a breaking change. Changing or removing one is.
Codes
| Status | Codes |
|---|---|
400 | INVALID_REQUEST, VALIDATION_FAILED, CONFLICT, INSUFFICIENT_BALANCE, LIMIT_EXCEEDED, UNKNOWN_BENEFICIARY |
401 | UNAUTHORIZED |
403 | FORBIDDEN, FEATURE_DISABLED, LIMIT_EXCEEDED, ACCOUNT_TERMINATED, ACCOUNT_FROZEN, ACCOUNT_SUSPENDED, ACCOUNT_PENDING_VERIFICATION, ACCOUNT_NOT_ACTIVE |
404 | NOT_FOUND |
422 | VALIDATION_FAILED |
429 | RATE_LIMITED |
503 | SERVICE_UNAVAILABLE |
5xx | INTERNAL_ERROR |
LIMIT_EXCEEDED comes back as 400 when an amount would breach a daily or monthly limit, and as 403 when a count is full — beneficiaries on the account, or allowed senders on a trigger address.
A 5xx never explains itself: the body is INTERNAL_ERROR with a fixed message and the detail goes to our logs under requestId. The exception is a deliberate 503 SERVICE_UNAVAILABLE, which means "retry later, nothing happened" and keeps its own message.
Authentication errors
401 Unauthorized
Everything below returns code: "UNAUTHORIZED". The message narrows it down while you are debugging, but it is prose — never branch on it.
| Cause | Fix |
|---|---|
| API key missing, unknown, or inactive | Send blox-api-key (or Authorization: Bearer) with an active key |
A write is missing Signature, Signature-Input, or Content-Digest | Sign every POST / PUT / PATCH / DELETE — see Request Signing |
| Signature or digest does not match | Re-sign over the exact bytes you send. Serializing the body twice is the usual cause |
| Signature algorithm differs from your registered signer | Sign with the key you registered |
| Clock drift | Keep created inside the window below, and keep your server clock synchronized |
| Signature reused | Sign each request fresh — a signature is accepted once |
{
"code": "UNAUTHORIZED",
"message": "…",
"requestId": "…"
}Freshness windows:
| Surface | created must be within | Reuse |
|---|---|---|
/v1 (Wallet, Onramp, Checkout) | 30s past, 5s future | Rejected — sign each request fresh |
Payout routes (/v1/payouts*, /v1/payout/prefund/balance) | ±300s | Rejected — sign each request fresh |
403 Forbidden
code | When |
|---|---|
ACCOUNT_TERMINATED | Account terminated |
ACCOUNT_FROZEN | Account frozen |
ACCOUNT_PENDING_VERIFICATION | Account pending verification |
ACCOUNT_SUSPENDED | Account suspended |
ACCOUNT_NOT_ACTIVE | Account inactive or closed |
FEATURE_DISABLED | Required product feature not enabled for the account |
ACCOUNT_TERMINATED blocks every route, reads included. The others block money-moving routes only, so reads keep working — except ACCOUNT_SUSPENDED, which still permits money out but not money in.
Contact the BLOX team to enable API products (e.g. payout) for your account.
Other common status codes
| Status | Meaning |
|---|---|
202 | Not an error — the first request with your Idempotency-Key is still running. Retry with the same key (Idempotency) |
400 | Validation or business-rule failure |
404 | Resource not found |
422 | An Idempotency-Key was reused with a different body |
429 | Rate limit exceeded (see Rate Limits) |
500 | Unexpected server error |
Schema validation failures come back as VALIDATION_FAILED, with the offending fields joined into message.
Handling errors
For 429, wait and retry with exponential backoff. Do not rely on rate-limit response headers.
Testing
# Missing / invalid API key
curl https://api.sandbox.blox.my/v1/health \
-H "blox-api-key: invalid_key"
# POST without signature headers (expect 401)
curl -X POST https://api.sandbox.blox.my/v1/payouts/beneficiaries \
-H "blox-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"TEST","bankCode":"MBBEMYKL","accountNumber":"1234567890"}'Support
- Email: support@blox.my
- GitHub: github.com/Blox-My