Skip to content

Errors

Every error response has the same shape:

422 Unprocessable Entity
{ "error": {
"type": "invalid_request_error", "code": "limit_exceeded",
"message": "Supera el límite por operación de pago móvil",
"request_id": "req_8a0312ba896772bc441134cd",
"meta": { "limit": "per_tx_max", "max": "10000000", "scope": "platform" } } }
Field What it is
code Stable code. Program against this
type Error family: tells you whether retrying makes sense
message Human-readable text, in Spanish today. It may change or be translated: do not parse it
request_id Also travels in the x-request-id header. Include it when you open a ticket
meta Structured context when there is some: which limit was exceeded, which field is invalid, how much balance there was. Absent on internal errors

Your switch on error.code needs a default for unknown codes.

type HTTP Meaning Retry?
invalid_request_error 400 · 404 · 409 · 422 Something in the request is wrong Not without fixing
authentication_error 401 · 403 Credentials or permissions No
rate_limit_error 429 You are going too fast Yes, slower
upstream_error 502 · 503 A payment network failure Yes, with the same Idempotency-Key
api_error ≥ 500 Our failure Yes
Code HTTP What to do
api_key_missing 401 The x-api-key header is missing
api_key_invalid 401 Check your credentials
api_key_revoked 401 That key was revoked
api_key_expired 401 Request a new one
tenant_suspended 403 Contact support
insufficient_scope 403 Use a key with the scope in meta.required
Code HTTP What to do
validation_failed 400 Fix the body or the query. The message says which field; sometimes meta.field does too
api_version_unsupported 400 BC-Version with a version that doesn’t exist, or 2026-10-22 in production. Use 2026-11-03 (migrate to the English names)
invalid_amount 400 Amount ≤ 0, out of range, or so small the fee would eat it
unsupported_asset 400 Unsupported asset or pair
Code HTTP What to do
idempotency_key_reused 409 New key: the body changed
idempotency_request_in_flight 409 The original is still in progress; retry in seconds
Code HTTP What to do
quote_not_found 404 It does not exist, or it belongs to another program
quote_expired 422 Request a new quote
quote_already_consumed 409 Another payout already used that quote
sell_rate_missing 422 You sell at your own rate and there is none set for that asset: set it
Code HTTP What to do
beneficiary_not_found 404 The beneficiaryId is not yours or does not exist
beneficiary_blocked 422 It is blocked: it can neither be read nor paid out to
beneficiary_instrument_missing 422 No phone number for pago móvil, or no account for bank transfer. meta carries beneficiaryId and instrument
Code HTTP What to do
insufficient_tenant_funds 422 Your balance is not enough. Only if you operate prefunded
credit_limit_exceeded 422 You used up your daily-close credit line
limit_exceeded 422 meta says which limit (per_tx_max, daily_max, monthly_max, daily_count_max), the cap and the usage
invalid_state_transition 409 The operation does not apply to the payment’s current state

payment_not_found, quote_not_found, beneficiary_not_found and event_not_found → 404, same as a resource from another program.

Code HTTP What to do
no_route_available 503 There is no payment network for that bank/method right now. Retry later
upstream_error 502 A failure of the payment network or the issuer. Retry with the same Idempotency-Key
rate_limited 429 Slow down. Respect Retry-After
internal_error 500 Our failure. Retryable; send the request_id if it persists

An error that does not fit the codes above arrives with a generic code per family: not_found (404), conflict (409), unprocessable (422) or invalid_request (400). Treat them like the rest of their family.


Payment network rejection reasons are not error.code

Section titled “Payment network rejection reasons are not error.code”
201 Created — the payout was processed and the payment network rejected it
{ "id": "89920401-26da-4f69-b57d-bc20e0366ce2", "status": "failed",
"reason": "beneficiary_missing_phone",
"asset": "BS", "amount": "5000000", "feeAmount": "0" }
reason What happened
beneficiary_missing_phone The beneficiary’s mobile number is missing for pago móvil. It is optional for bank transfer
beneficiary_missing_account The account number for bank transfer is missing
beneficiary_mismatch Name or national ID do not match the holder of that account or phone
invalid_destination_account The destination account does not exist or is malformed
sender_required There was no sender through any of the three paths
sender_phone_unsupported No available payment network accepted the sender’s international (E.164) phone number
amount_below_minimum Below the payment network’s floor
amount_above_limit Above the payment network’s ceiling
amount_not_positive Amount ≤ 0
amount_precision_loss The amount cannot be represented without losing cents
bank_unreachable That payment network does not cover the destination bank
instrument_unsupported That payment network does not offer that method
payout_insufficient_balance No balance in the paying account for the payment plus the payment network’s fee
payout_balance_unavailable The paying account’s balance could not be read: nothing was sent
payout_rejected Generic payment network rejection
payout_timeout We do not know whether it paid → the payment stays unknown, not failed
no_route No payment network available for that combination

The same value is stored in the payment’s status_reason and in the transition’s reason inside events[]. What to do with each one: when something fails.

A payment with status: "unknown" responds 200/201, not an error: the payment network did not confirm, and the payment is in doubt. See payment states.