Errors & Rate Limits

Error envelope

Every error response shares one shape:

{
  "error": {
    "code": "orders.idempotency_payload_mismatch",
    "message": "A human-readable sentence — not guaranteed stable wording.",
    "request_id": "a correlation id, worth including in a support request"
  }
}

code is a stable, dot-namespaced string safe to branch on programmatically.

Common codes

Status Code Meaning
400 validation.invalid_request Malformed body/params
401 (generic) Missing, invalid, or revoked key
403 reseller_api.insufficient_scope Valid key, wrong scope for this endpoint
404 (generic) Not found, or belongs to a different account (never 403 for this)
409 orders.idempotency_payload_mismatch Same Idempotency-Key, different request body
429 reseller_api.rate_limited General per-key/per-account rate limit hit — see below
429 reseller_api.webhook_outbound_rate_limited Webhook test-ping/replay limit hit — see below
503 reseller_api.rate_limiter_unavailable Rate limiter backend unreachable on a write request — see below

Rate limits

Each API key has a per-endpoint-class (read vs. write) request budget, counted both per-key and per-account, on a fixed 60-second window. A limit hit returns 429 reseller_api.rate_limited with a real Retry-After header — wait at least that many seconds before retrying the same class of request again. These numbers are conservative defaults, not yet validated against real external production traffic — treat them as subject to change, not a committed SLA.

The Account → Developer dashboard has its own, separate per-account budget (not shared with your API key's own budget) for the same reason: your dashboard usage and your key's usage are different things and shouldn't throttle each other.

Webhook test-ping (POST /webhooks/{id}/test — callable from the public API or the dashboard) and manual replay (POST /webhooks/{id}/deliveries/{id}/replay — public API only) share one additional, stricter limit — 5 requests per 300 seconds, per account — because both make a real outbound HTTP request on demand. See Webhooks for detail.

If the rate-limiter backend itself is temporarily unreachable, a write request fails with 503 reseller_api.rate_limiter_unavailable rather than being let through uncounted; a read request is allowed through as usual.