Rate limits

Token-bucket limits per API key, with standard headers on every response.

Limits are enforced per API key using a token-bucket algorithm. When a bucket empties the API returns 429 Too Many Requests.

Default limits

EnvironmentRequests / minuteBurstWrite ops / minute
Sandbox (qxk_test_…)30060120
Live (qxk_live_…)1,200200600
EnterpriseCustomCustomCustom

Contact support to lift live limits for production launches.

Headers

Every response — including 2xx — carries the current bucket state:

HeaderDescription
X-RateLimit-LimitBucket capacity (per minute).
X-RateLimit-RemainingTokens left in the current window.
X-RateLimit-ResetUnix seconds until the bucket refills.
Retry-AfterSeconds to wait. Present on 429 only.

429 response

HTTP/1.1 429 Too Many Requests
Retry-After: 3
X-RateLimit-Limit: 1200
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1737049200
Content-Type: application/json

{
  "error": {
    "code": "rate_limited",
    "type": "rate_limit_error",
    "message": "Rate limit exceeded. Retry in 3 seconds.",
    "retryable": true,
    "request_id": "req_01HR2X8YQ4T5B0G6ZP"
  }
}

Handling 429s

  1. Read Retry-After and wait exactly that long — do not retry sooner.
  2. Use the same Idempotency-Key so retries don't double-charge.
  3. Add jitter to smooth out fleet-wide spikes.
  4. Watch X-RateLimit-Remaining proactively and shed load client-side.
async function callWithBackoff(req) {
  for (let i = 0; i < 5; i++) {
    const res = await fetch(req);
    if (res.status !== 429) return res;
    const wait = Number(res.headers.get("Retry-After") ?? 1) * 1000;
    await new Promise(r => setTimeout(r, wait + Math.random() * 250));
  }
  throw new Error("rate_limit_exceeded");
}

Aggressive retries without honoring Retry-After may result in the key being throttled to a lower tier.