Skip to main content

Errors and retries

Errors always come back in the standard envelope with status: CANCELLED. The machine-readable part is statusCode — an internal application code that does not match the HTTP status.

StatusCode enum

CodeNameHTTPMeaningRetry?
0OK200Success
1ACCEPTED202Accepted for async processingPoll
2IDEMPOTENCY_REPLAY200Idempotent replay — the original result
3VALIDATION_ERROR422 / 400 / 415Validation failed❌ Fix the request
4UNAUTHORIZED401Not authenticated
5FORBIDDEN403No scope, IP not in allowlist, or key revoked
6NOT_FOUND404Resource not found
7CONFLICT409Conflict / duplicate
8LIMIT_REACHED429Per-window rate limit hit (ours or the upstream shop service)✅ Back off
9OUT_OF_STOCK422Not in stock❌ (retry later at your discretion)
10INSUFFICIENT_FUNDS422Not enough balance❌ Top up first
11UPSTREAM_ERROR502Upstream service error✅ Careful retry
12INTERNAL_ERROR500Server error✅ Careful retry
13API_KEY_LIMIT_EXCEEDED409Order does not fit the key's transactionLimit❌ Raise the limit
14PROVIDER_UNAVAILABLE504Provider did not answer after our retries. Order not created, funds not charged. Retry-After: 2✅ Retry

Retry policy that works

statusCode 8 → sleep Retry-After (or exponential back-off), retry
statusCode 11 → exponential back-off, cap at ~3 attempts
statusCode 12 → exponential back-off, cap at ~3 attempts
statusCode 14 → honour Retry-After (2s), retry
everything else → do not retry; fix the request or the key

Always reuse the same referenceId when retrying a purchase. That is what turns a retry into a replay instead of a second charge — see Idempotency.

Two 409s that mean opposite things

Both return HTTP 409, and only one of them is worth reacting to programmatically:

  • statusCode: 13 + errorCode: "api_key_transaction_limit_exceeded" — the key's spend cap is exhausted. Permanent until raised. No amount of back-off helps.
  • statusCode: 7 — a plain conflict, usually a duplicate.

:::info Changed in 2026-05 Transaction-limit exhaustion moved from 429 to 409. If your client special-cased 429 for "key limit reached", move that branch to 409 + errorCode="api_key_transaction_limit_exceeded" and leave only true rate-limit back-off on 429. See Authentication. :::

PROVIDER_UNAVAILABLE is safe to retry

statusCode 14 is the one upstream failure with a guarantee attached: the order was not created and nothing was charged. We already exhausted our internal retries before returning it. Honour Retry-After: 2 and send the request again with the same referenceId.

Reporting a problem

Include the traceId from the envelope (or the X-Trace-Id response header). It resolves the request end to end in our logs — timestamps and endpoint names alone usually do not.