The envelope
Every success wraps its payload in data, with list metadata in meta when there is any. Every failure is an error object with a stable machine-readable code, a human message, optional details, and the requestId to quote when you write to support.
{
"data": { … },
"meta": { … }
}{
"error": {
"code": "VALIDATION_FAILED",
"message": "…",
"details": { … },
"requestId": "…"
}
}Error codes you will meet
- 401
INVALID_API_KEYThe API key is missing, unknown or revoked - 401
UNAUTHENTICATEDNo usable token on a route that needs one - 403
INSUFFICIENT_SCOPEThe token lacks the scope this endpoint declares - 422
VALIDATION_FAILEDThe body or query did not validate; details says what - 429
RATE_LIMITEDOver the key’s limit; wait for Retry-After - 502
UPSTREAM_UNAVAILABLEA service behind the API did not answer
Rate limits
Requests are counted per API key over a 60-second window. The default is 120 requests per minute, and a key can be issued with a higher limit — up to 10,000. Every response carries the three headers below; going over answers 429 RATE_LIMITED with a Retry-After header. Back off until it passes rather than retrying in a loop.
x-ratelimit-limit: 120
x-ratelimit-remaining: 118
x-ratelimit-reset: 1758854400Checkout carries its own stricter limits on top: quoting and placing orders are throttled per cart and per shopper, and a throttled response says which dimension tripped.
Request ids
Send your own X-Request-Id (letters, digits, ._~-, at most 64 characters) and it is echoed on the response; without one, an id is assigned. Failures repeat it inside the error envelope as requestId.
Pagination
Catalogue lists take a page query parameter and answer with list metadata in meta.
Versioning
The version is in the path — /v1/…. Additive changes (new fields, new endpoints) land in the current version; breaking changes only ever arrive as a new version path, with the old one kept running while integrations move.