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.