Skip to content

Errors and rate limits

Errors are JSON with a human-readable detail and a stable machine-readable code. When the message contains values, they are also in params, so you can translate the message by code.

{
"detail": "Too many requests for this API key (limit 120 per minute); retry after 12s",
"code": "rate_limited",
"params": { "limit": 120, "retry_after": 12 }
}
  • Match on code, never on detail. detail may change wording.
  • Invalid input is 422 with code: validation_error and an errors list naming the fields.
  • Every response has an X-Request-Id header. Include it when you contact support.
Status code (examples) When Retry?
400 bad_request, invalid_cursor, invalid_idempotency_key The request cannot be used as sent No, fix the request
401 unauthenticated Missing, malformed, expired or revoked key No
403 insufficient_scope The key’s scopes or the creator’s role do not allow this No
404 not_found Not found, or not in your account No
409 conflict, idempotency_key_reused Conflict with the current state, or an Idempotency-Key reused for a different request No, unless you change the request
422 validation_error Missing field, wrong type, unknown enum value, more than 1000 sales lines No, fix the request
429 rate_limited Rate limit reached Yes, after Retry-After seconds
5xx Server error Yes, with backoff and the same Idempotency-Key

Records of another account always answer 404, never 403, so ids do not leak across accounts.

Each API key may make 120 requests per minute (a fixed one-minute window). Above that the API answers 429 with code rate_limited and a Retry-After header in seconds, until the next minute starts.

  • Wait Retry-After seconds, then retry. Do not retry in a tight loop.
  • Batch writes: send up to 1000 sales lines per request instead of one per line.
  • Use one key per integration, so one busy job does not slow down another.
  • Rely on 429 and Retry-After rather than on the number: the limit may change.