Error reference

Every error type the API can return, with meaning and how to react.

Error reference

All errors are JSON with the same envelope:

{
  "error": {
    "type": "invalid_request",
    "code": "customer_email_invalid",
    "message": "customer_email must be a valid email address",
    "param": "customer_email",
    "request_id": "req_01H…"
  }
}
  • type — high-level family (see table below).
  • code — machine-readable specific error. Always populated for validation and idempotency errors.
  • message — human-readable. Safe to log, do not show verbatim to end customers.
  • param — the offending body field, when applicable.
  • request_id — always log it. Support can look it up instantly.

HTTP status codes

HTTP Meaning Retry?
200 / 201 Success
400 Client error (bad input) No — fix and resend
401 Auth failed (missing / bad / revoked key) No
402 Payment declined at the network Depends (see decline_code)
403 Key valid but not allowed for this action No
404 Resource not found No
409 Conflict (idempotency reuse, merchant not ready) No — see code
422 Semantically invalid (e.g. session already paid) No
429 Rate limited Yes — respect Retry-After
5xx spuke server issue Yes — with the same Idempotency-Key

error.type values

Type HTTP When
invalid_request 400 Missing / malformed field. param tells you which.
amount_too_small 400 Below the 2.50 EUR equivalent minimum.
amount_too_large 400 Above the per-charge maximum.
currency_unsupported 400 Currency not in the supported list.
authentication_error 401 Key missing, malformed, revoked or wrong mode (test vs live).
permission_error 403 Key valid but scope/role forbids this action.
card_error 402 Buyer's card was declined. See code / decline_code.
idempotency_error 409 Same Idempotency-Key reused with a different request body. code = idempotency_key_reused.
resource_conflict 409 e.g. merchant_not_ready, subscription_already_canceled.
not_found 404 The id does not exist under this merchant.
invalid_state 422 session_expired, session_already_completed, charge_disputed.
rate_limit_error 429 Too many requests. Back off.
api_error 5xx Transient spuke error. Retry with the same Idempotency-Key.

Idempotency conflict — exact shape

Reusing an Idempotency-Key with a body that differs from the original request always returns:

{
  "error": {
    "type": "idempotency_error",
    "code": "idempotency_key_reused",
    "message": "Idempotency-Key reused with a different request body"
  }
}
  • HTTP status: 409 Conflict
  • Uniqueness scope: (merchant_id, method, path, Idempotency-Key).
  • Same key + same body → replays the original response (status + body) verbatim.
  • Same key + different body → the 409 shown above.
  • Keys expire after 24 hours.

Recommended handling

  • Never retry 4xx errors except 409 idempotency_error after you've fixed the body and rotated the key.
  • Always retry 5xx with the same idempotency key, using exponential backoff (1s → 2s → 4s, max 5 attempts).
  • On 429, sleep for the number of seconds in Retry-After (default 1) before the next attempt.
  • Show error.message to internal operators, not to end customers — use a friendly wrapper.