Skip to main content

Rate Limiting

API requests are rate limited to ensure fair usage and platform stability.

Limits​

EnvironmentLimit
Sandbox100 requests/minute
ProductionBased on plan

Rate Limit Headers​

Every response includes rate limit information:

X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1703693400
HeaderDescription
X-RateLimit-LimitMaximum requests per window
X-RateLimit-RemainingRemaining requests in current window
X-RateLimit-ResetUnix timestamp when the window resets

Rate Limit Exceeded​

When you exceed the rate limit, you'll receive:

Status: 429 Too Many Requests

{
"code": "error.rate_limit",
"message": "Too many requests. Please try again later."
}

Handling Rate Limits​

Check Headers​

Monitor the X-RateLimit-Remaining header and slow down before hitting the limit.

async function makeRequest(url, options) {
const response = await fetch(url, options);

const remaining = parseInt(response.headers.get('X-RateLimit-Remaining'));

if (remaining < 10) {
console.warn(`Rate limit warning: ${remaining} requests remaining`);
}

return response;
}

Implement Backoff​

When rate limited, wait and retry:

async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);

if (response.status === 429) {
const resetTime = response.headers.get('X-RateLimit-Reset');
const waitMs = resetTime
? parseInt(resetTime) * 1000 - Date.now()
: 60000;

console.log(`Rate limited. Waiting ${waitMs}ms...`);
await new Promise((r) => setTimeout(r, Math.max(waitMs, 1000)));
continue;
}

return response;
}

throw new Error('Max retries exceeded');
}

Exponential Backoff​

For repeated failures:

async function fetchWithExponentialBackoff(url, options) {
const maxRetries = 5;
const baseDelay = 1000;

for (let attempt = 0; attempt < maxRetries; attempt++) {
try {
const response = await fetch(url, options);

if (response.status === 429) {
const delay = baseDelay * Math.pow(2, attempt);
console.log(`Retry ${attempt + 1}: waiting ${delay}ms`);
await new Promise((r) => setTimeout(r, delay));
continue;
}

return response;
} catch (error) {
if (attempt === maxRetries - 1) throw error;
}
}
}

Best Practices​

  1. Cache responses — Avoid repeated requests for the same data
  2. Batch operations — Combine multiple requests when possible
  3. Monitor headers — Track remaining requests
  4. Implement backoff — Handle 429 errors gracefully
  5. Use webhooks — Instead of polling for status changes
  6. Test in sandbox — Verify rate limit handling before production