Envelope
Every response — success or error — comes back in the same envelope:
// success
{ "success": true, "data": { ... }, "error": null }
// error
{
"success": false,
"data": null,
"error": "human-friendly message",
"code": "HTTP_404",
"details": null
}error is a sentence for your logs. code is VALIDATION_ERROR for a 422 (and details then lists the fields that failed) and HTTP_<status> for the others, such as HTTP_401 or HTTP_409. Branch on the HTTP status first. A few money errors carry their own code (for example a locked account).
HTTP status codes
| Code | Meaning | Retry? |
|---|---|---|
| 200 | OK | — |
| 201 | Created | — |
| 400 | Bad request — for example an unknown currency | No — fix it |
| 401 | Missing or invalid API key | No — check the key |
| 403 | Wrong key mode for the path (test key on a live path or the reverse), or the merchant account is suspended | No |
| 404 | Resource not found (or it belongs to another merchant or mode) | No |
| 409 | Conflict — Idempotency-Key reused with a different body, or a payment method the checkout does not allow | No — fix it |
| 422 | A field failed validation, or an unknown field was sent | No — fix it |
| 423 | Currency not enabled for the account, or the account is locked | No |
| 429 | Rate-limited (60 requests per 60 seconds per key and endpoint) — honour Retry-After | Yes, after the delay |
| 500–504 | Server problem on our side | Yes, with backoff + jitter |
| 503 | The developer API is temporarily paused | Yes, later |
Retry 5xx, timeouts and 429 with the same Idempotency-Key. Do not retry other 4xx responses.