Skip to main content
Every response carries IETF-standard 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

Mint a fresh JWT and a fresh X-Request-Signature per attempt — do not capture once. JWTs are 60-second TTL and the signature is bound to the JWT’s nonce (Authentication). Retries across several attempts can add up to more than 60s of wall-clock time — a captured JWT will expire mid-loop and your next request returns 401 AUTH_TOKEN_EXPIRED (or a 401 AUTH_TOKEN_INVALID with details.reason: SIGNATURE_INVALID if you reused the signature). The pattern below takes a signRequest function that mints both on each attempt.

When you hit the limit

A 429 response uses the standard error envelope. The rate-limit posture lives in the headers, so details is empty:
Headers on a 429:
Compute your wait as 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 on LIVE or SANDBOX, and a sense of the burst pattern you need.

Common mistakes

  • Sleeping a fixed duration on 429 instead of waiting Retry-After seconds. A hard-coded sleep either thrashes the limit or wastes throughput. Compute the wait from Retry-After (or RateLimit-Reset as a fallback).
  • Treating RateLimit-Reset as 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. Use RateLimit-Reset * 1000 directly.
  • 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-Signature is bound to the JWT’s nonce — both must be re-minted per attempt. Pass a signRequest function 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.