Rate Limiting
API requests are rate limited to ensure fair usage and platform stability.
Limits​
| Environment | Limit |
|---|---|
| Sandbox | 100 requests/minute |
| Production | Based on plan |
Rate Limit Headers​
Every response includes rate limit information:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 95
X-RateLimit-Reset: 1703693400
| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests per window |
X-RateLimit-Remaining | Remaining requests in current window |
X-RateLimit-Reset | Unix 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​
- Cache responses — Avoid repeated requests for the same data
- Batch operations — Combine multiple requests when possible
- Monitor headers — Track remaining requests
- Implement backoff — Handle 429 errors gracefully
- Use webhooks — Instead of polling for status changes
- Test in sandbox — Verify rate limit handling before production