RateLimit-* headers so you know your cap and when the current window resets. The limit is 300 requests / 10-second window, tracked as a separate bucket per org, per environment (LIVE or SANDBOX), with the same cap in both. 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. LIVE and SANDBOX are separate buckets with the same cap; usage in one doesn’t count against the other.
Handling rate limits: pattern
When you hit the limit
A 429 response uses the standard error envelope and includes aRetry-After header. Its details object 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 support@mail.openfx.com. 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-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 near the rate-limit ceiling. A 300 req/10s ceiling and a 1-second poll across 30 background workers leaves zero headroom for actual user-driven requests. Pace well under the limit.
- Assuming a support-granted limit increase applies to both environments. LIVE and SANDBOX are separate buckets; a higher ceiling granted on one doesn’t carry over to the other.
What’s next
Metadata & tracing
X-Trace-Id on every response.
Idempotency
In-flight requests and safe retries.