Reference
Errors
How the API signals failure: HTTP status codes on REST, an errors array on GraphQL, and RFC error bodies on OAuth.
Payer uses conventional HTTP status codes and returns a JSON body describing what went wrong. The exact shape depends on the surface you're calling.
REST status codes
The Checkout API and other REST endpoints return these:
| Status | Meaning | Typical cause |
|---|---|---|
200 | OK | The request succeeded. |
400 | Bad request | An action isn't valid for the resource's state — e.g. cancelling a paid session. |
401 | Unauthorized | Missing, malformed or unknown token. |
403 | Forbidden | The token lacks the required scope, or a PAT sent an X-Active-Merchant header. |
404 | Not found | No resource with that id for this account. |
409 | Conflict | An Idempotency-Key is still in flight, or was reused mid-request. |
422 | Unprocessable | A field failed validation, or an Idempotency-Key was reused with a different body. |
429 | Too many requests | The credential's per-minute rate limit was exceeded. |
A simple error carries a message:
403 Forbidden
{
"message": "Forbidden",
"error": "This credential does not have the required scope: checkout:write"
}Validation errors
Field validation failures return 422 with a Laravel-style errors map — one array of messages per offending field:
422 Unprocessable
{
"message": "The amount field is required. (and 1 more error)",
"errors": {
"amount": ["The amount field is required."],
"reference": ["The reference has already been taken."]
}
}GraphQL errors
GraphQL always responds 200 at the HTTP layer. Failures appear in a top-level errors array, and the affected field in data is null:
GraphQL error
{
"data": { "balance": null },
"errors": [
{
"message": "This credential does not have the required scope: balances:read",
"extensions": { "category": "authorization" }
}
]
}OAuth errors
The OAuth token and revoke endpoints follow RFC 6749 — a machine-readable error with a human error_description:
OAuth error
{
"error": "invalid_grant",
"error_description": "The authorization code is invalid or has expired."
}Handling errors well
- Retry writes with the same `Idempotency-Key`. A
5xxor a network blip is safe to retry — the original response is replayed, not repeated. See Idempotency. - Back off on `429`. Limits are per credential; spread load or split work across keys rather than hammering one.
- Read `errors`, not just the field. On GraphQL a partial response can carry both
dataanderrors.