Skip to content

Errors

Every error has the same shape. Branch on code — it’s stable; message is for humans and may change.

{ "error": { "code": "insufficient_funds", "message": "Available balance is too low for this payout", "details": null } }
HTTP code Meaning What to do
400 validation_error body/query invalid (details lists fields), amount below the minimum, unknown starting_after fix the request; don’t retry as-is
400 invalid_request the request couldn’t be read (e.g. malformed JSON) fix the request
401 authentication_required no Authorization: Bearer sk_… header send your secret key
401 invalid_api_key key malformed, unknown or revoked check the key and its mode
403 forbidden account suspended, or simulate used with a live key contact Xaalis / use a test key
403 merchant_not_active live request while your account isn’t active yet use test mode until activated
404 not_found no such object for this key’s merchant and mode check id and test/live key
409 idempotency_conflict Idempotency-Key reused with different parameters (amount, provider, recipient…) use a new key for a different request
409 invalid_state the object can’t do that now (payment already final or expired, subscription no longer active, a test advance already running) read the object’s state; create a new one if needed
409 key_secret_unavailable a key issuance (API key or agent-wallet key) was retried: a secret is only ever shown once revoke the key id in the error, then issue a replacement with a new Idempotency-Key
422 insufficient_funds payout larger than available (fee included) pay out less
422 unsupported e.g. Orange Money payouts in live mode use Wave
429 rate_limited more than 100 requests/second on one key (60/s per IP on checkout routes) wait Retry-After seconds, then retry
502 provider_error Wave / Orange Money failed to start the payment retry, or offer the other method
503 temporarily_unavailable a dependency (ledger, database) timed out or is briefly unavailable — the request may already have taken effect — or a payout/refund outcome isn’t known yet wait Retry-After seconds, then retry with the same Idempotency-Key (a replay never applies it twice)
503 provider_not_configured that provider isn’t enabled on this platform offer the other method
500 internal_error our bug; request_id is included retry with the same Idempotency-Key; report the request_id

Quota headers. Responses that passed a rate check carry RateLimit-Policy (each policy’s allowance q per window w seconds) and RateLimit (remaining r, window t), following the IETF draft draft-ietf-httpapi-ratelimit-headers-11. Use them to slow down before you hit a 429; they’re a snapshot, not a promise. Every 429 carries Retry-After, and it wins over the snapshot.

Retry only 429 (after Retry-After), 5xx and network errors — and only with the same Idempotency-Key. Never retry any other 4xx unchanged.

The merchant dashboard has its own limits, per client IP: 60 requests per second, and 10 identity-document uploads per hour (also counted per business). People behind one shared connection share that allowance. A limited request changed nothing; the dashboard shows the wait (“réessayez dans 30 s”).