Skip to main content
Every AptaPay error response has the same shape:
error.code is a stable machine string. Build your logic against it and against the three booleans — never against the HTTP status alone, and never by string-matching message. Message text can change without notice; error.code will not.

The three booleans

Exactly one of the three is always true. This is the whole contract for safe retries.
The request reached a final answer. Retrying with the same idempotency key cannot change it.What to do: if it was a debit-adjacent operation, reverse your own side and surface the failure to your user. Do not retry.
Safe to retry. Nothing has been applied on our side or the provider’s.What to do: retry with backoff, using the same idempotency key. Never mint a new key for a retriable failure — a new key restarts the whole operation as if it were unrelated.
The outcome is unknown. The request may or may not have been applied by the provider.What to do: do not reverse anything. Poll GET /v1/collections/{reference} or GET /v1/payouts/{reference} until it resolves to a terminal status, or escalate to manual review after a reasonable timeout. Reversing an ambiguous outcome is exactly how a double-processing or a lost debit happens.
The single most damaging integration bug in a payments API is treating ambiguous as terminal and reversing. If you write only one branch carefully, write this one.

Handling the three cases

handle-error.ts

Common codes

A few worth calling out:
  • insufficient_tenant_float — your float balance in that currency does not cover the amount plus the estimated fee. Top up; the request itself was well-formed.
  • velocity_limit_exceeded — you crossed a per-hour, per-day or per-destination cap. Retriable, but retrying immediately will fail again; back off meaningfully.
  • idempotency_key_reused — the same key with different parameters. This is a bug or an attack on your side, never a legitimate retry. See Idempotency.
  • mode_mismatch — your body claimed a mode that disagrees with the key you signed with. Mode comes from the key. See Modes.

Status codes