Errors
Every failed request answers with an HTTP status and a JSON body under error:
message is written to be shown to a person. code is stable and is what your own code
should branch on.
Status codes
Note that a missing or invalid credential answers 403, not 401.
Validation errors
A VALIDATION_ERROR carries an issues array saying exactly which fields were wrong and
where they were:
path is the route to the offending field, so ["items", 0, "productId"] means the
first item in the list you sent.
Filtering has its own validation: an unknown field, an operator mixed with plain keys, or
a value that does not fit the column all return 400 describing the problem. See
Filtering.
Permission errors
A key that does not hold the endpoint's permission gets the missing scope back in the message, which is usually enough to fix it without reading anything else:
Update the key's permissions under Settings → API keys, or use a key that already holds it. See Authentication.
Plan limits
Reaching a limit on your plan is a 400 with BAD_REQUEST, worded as what you reached
and what to do about it:
Some limits block the action outright and some only warn in the dashboard. See Plans and limits.
Rate limiting
A 429 carries a Retry-After header with whole seconds until the request can be
afforded again. Wait that long rather than retrying immediately, and prefer larger pages
to more requests: one call for 250 records costs the same as one call for 10.
See Rate limits for the size of the budget and what spends it.
Retrying
Retry 429 after the interval it gives you, and 500 with a backoff. Do not retry 400,
403, 404 or 409: the same request will fail the same way until something changes.
If you are retrying a request that records an event, send an idempotency key so a duplicate does not count twice. See Conventions.