RateLimit-* headers so you know your cap and when the current window resets. The limit is per org, per environment (LIVE or SANDBOX) — 300 requests / 10-second window on LIVE, 600 requests / 10-second window on SANDBOX (2× LIVE). All API keys under an org share the same environment bucket; creating more keys does not raise the limit. When you exceed it you get a 429; wait Retry-After seconds, then retry.
Rate-limit headers
RateLimit-Reset is a duration, not a timestamp. RateLimit-Reset: 8
means “the window resets in 8 seconds from now” — compute your wait as
RateLimit-Reset * 1000 milliseconds from when you received the response,
not by comparing it against a clock. On a 429 or a 409 IDEMPOTENCY_IN_FLIGHT, prefer the Retry-After header (also seconds) — the
more specific, purpose-built signal for exactly when to retry.Default limits
The limit is per org, per environment — bucketed by whichever
X-App-Mode (LIVE or SANDBOX) the request used, shared across every API key under that org. Regional enforcement means counters are tracked per geographic edge location, so a distributed source may see a multiplied effective limit.
Handling rate limits: pattern
When you hit the limit
A 429 response uses the standard error envelope. The rate-limit posture lives in the headers, sodetails is empty:
Retry-After * 1000 milliseconds (both Retry-After and RateLimit-Reset are a duration in seconds, not an epoch timestamp — prefer Retry-After, the more specific signal for exactly when to retry). The same Retry-After header is present on 409 IDEMPOTENCY_IN_FLIGHT too — see Idempotency.
Need a higher rate limit?
Email [email protected]. Provide your org ID, whether you need it onLIVE or SANDBOX, and a sense of the burst pattern you need.
Common mistakes
- Sleeping a fixed duration on 429 instead of waiting
Retry-Afterseconds. A hard-coded sleep either thrashes the limit or wastes throughput. Compute the wait fromRetry-After(orRateLimit-Resetas a fallback). - Treating
RateLimit-Resetas an epoch timestamp. It’s a duration in seconds from the response, not a Unix timestamp —RateLimit-Reset * 1000 - Date.now()computes a nonsensical wait. UseRateLimit-Reset * 1000directly. - Retrying a 429 indefinitely. A single reset-wait is not a license to retry forever. Cap retry attempts; on exhaustion, surface the error to the caller.
- Capturing the JWT or signature outside the retry loop. JWTs are 60s TTL and the
X-Request-Signatureis bound to the JWT’snonce— both must be re-minted per attempt. Pass asignRequestfunction so each attempt gets a fresh token AND a fresh signature. See the Warning above. - Polling at the rate-limit floor. A 300 req/10s (LIVE) ceiling and a 1-second poll across 30 background workers leaves zero headroom for actual user-driven requests. Pace well under the limit.
- Mixing Live and Sandbox traffic against the same limit assumptions. SANDBOX’s limit is 2× LIVE’s, and they’re separate buckets — verify your limits in each.
What’s next
Metadata & tracing
X-Trace-Id on every response.
Idempotency
In-flight requests and safe retries.