Capay Global

Errors

Errors use conventional HTTP status codes plus a machine-readable body: a closed catalog of error codes, a human sentence, and a next_step that tells you what to do about it.

Error shape

Validation failures list the offending fields in validation_errors. Every error carries the request_id to quote to support.

422 response
{
  "status": "error",
  "error": {
    "type": "validation_error",
    "code": "validation_error",
    "message": "One or more request parameters are invalid.",
    "next_step": "Fix the fields listed in validation_errors and retry the request.",
    "validation_errors": [
      { "field": "country", "message": "country must be a 2-letter ISO code, e.g. CM" },
      { "field": "amount", "message": "amount is required as a decimal string, e.g. \"5000\"" }
    ],
    "request_id": "c4a1f8e2-9d30-47b6-8e5f-1a2b3c4d5e6f"
  }
}

Error catalog

The catalog is closed: these are all the codes the API returns today. Retries with the same Idempotency-Key are always safe on 5xx responses.

CodeHTTPType
invalid_api_key401authentication_error
insufficient_scope403authentication_error
route_not_found404invalid_request_error
resource_not_found404invalid_request_error
validation_error422validation_error
idempotency_key_reused422idempotency_error
request_in_flight409idempotency_error
rate_limited429rate_limit_error
ip_rate_limited429rate_limit_error
limit_exceeded403invalid_request_error
amount_below_minimum403invalid_request_error
insufficient_balance402invalid_request_error
merchant_restricted403invalid_request_error
settlement_managed403invalid_request_error
provider_unavailable503provider_error
unsupported_country422invalid_request_error
unsupported_currency422invalid_request_error
method_not_available422invalid_request_error
prohibited_corridor403invalid_request_error
corridor_closed503provider_error
corridor_awaiting_float503provider_error
service_paused503provider_error
card_data_rejected422invalid_request_error
risk_rejected403invalid_request_error
compliance_blocked403invalid_request_error
refund_unsupported_rail422invalid_request_error
refund_below_rail_minimum422invalid_request_error
refund_payer_details_missing422invalid_request_error
fx_pair_unsupported422invalid_request_error
fx_rate_unavailable503provider_error
sandbox_only403invalid_request_error
link_not_found404invalid_request_error
link_disabled410invalid_request_error
link_expired410invalid_request_error
report_window_invalid422validation_error
checkout_sessions_disabled403invalid_request_error
session_reference_in_use409invalid_request_error
session_not_open409invalid_request_error
session_not_found404invalid_request_error
session_expired410invalid_request_error
session_disabled410invalid_request_error
agent_live_money_disabled403invalid_request_error
agent_currency_not_allowed403invalid_request_error
agent_corridor_not_allowed403invalid_request_error
agent_beneficiary_not_allowed403invalid_request_error
agent_cap_per_transaction_exceeded403invalid_request_error
agent_cap_daily_exceeded403invalid_request_error
agent_cap_monthly_exceeded403invalid_request_error
agent_batch_not_allowed403invalid_request_error
agent_key_rotated403invalid_request_error
internal_error500api_error

Reason codes

Errors describe a request that was refused; reason codes describe how an accepted transaction turned out. Every non-success outcome of a collection, payout or refund carries a reason_code from this closed vocabulary, on the resource itself, in its event history and in webhooks. Handle each code you care about explicitly, and make the default branch of your status switch mean undetermined: keep polling GET /{id} or wait for the webhook. A status your code does not handle is never a failure and never a success.

CodeCategoryTerminalDescription
payer_timeoutCUSTOMERyesThe payer did not confirm the payment prompt in time.
insufficient_fundsCUSTOMERyesThe payer's account balance was insufficient.
invalid_customerCUSTOMERyesThe customer identifier (MSISDN or account) is invalid or not registered.
cancelled_by_payerCUSTOMERyesThe payer explicitly declined or cancelled the payment.
provider_errorPROVIDERyesThe provider returned an unrecoverable error.
provider_unavailablePROVIDERnoThe provider is temporarily unavailable; the transaction may be retried or enqueued.
expiredPLATFORMyesThe transaction expired before completion.
duplicatePLATFORMyesA duplicate of an already-processed transaction.
unknownPLATFORMnoThe outcome is not yet determined.
limit_exceededRISKyesA configured transaction or velocity limit was exceeded.
risk_reviewRISKnoThe transaction is held for risk review.
amount_mismatchRECONCILIATIONnoThe provider-confirmed amount differs from the requested amount; under reconciliation.
insufficient_balancePLATFORMyeserrors.rc.insufficient_balance
resolve_unsupportedPLATFORMyeserrors.rc.resolve_unsupported
batch_cancelledPLATFORMyeserrors.rc.batch_cancelled
awaiting_floatPROVIDERnoThe provider wallet funding this corridor is being replenished. The payout holds its reserve and sends as soon as the float is restored; nothing else is required of you.