Overview
The default maximum rate limit is configurable per API key. After exceeding the rate limit, you’ll receive a 429 response error code with details about when you can retry.
Every API response includes headers that help you track your current usage:
| Header | Description |
|---|
X-RateLimit-Limit | Maximum requests allowed per time window |
X-RateLimit-Remaining | Requests remaining in current time window |
X-RateLimit-Reset | Unix timestamp when rate limit resets |
Retry-After | Seconds to wait before retrying (429 responses only) |
Example response headers:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 999
X-RateLimit-Reset: 1640995200
Rate Limit Response
When you exceed your rate limit, you’ll receive a 429 status code:
{
"success": false,
"error": {
"code": 429,
"timestamp": "2024-01-01T00:00:00.000Z",
"message": "Rate limit exceeded",
"details": "error/rate_limit_exceeded"
}
}
Default Limits
Rate limits vary by subscription plan and API key configuration:
| Plan | Requests per Minute | Requests per Hour | Requests per Day |
|---|
| Free | 100 | 1,000 | 10,000 |
| Starter | 500 | 5,000 | 50,000 |
| Professional | 2,000 | 20,000 | 200,000 |
| Enterprise | Custom | Custom | Custom |
These are example limits. Actual limits are configured per API key and may vary based on your subscription plan.
Best Practices
Always check rate limit headers in responses to track usage:
const response = await fetch('/api/users', {
headers: {
'Authorization': 'Bearer leo_xxxxxxxxx',
'Content-Type': 'application/json'
}
});
const remaining = response.headers.get('X-RateLimit-Remaining');
const reset = response.headers.get('X-RateLimit-Reset');
console.log(`Requests remaining: ${remaining}`);
console.log(`Reset time: ${new Date(reset * 1000)}`);
2. Implement Exponential Backoff
When you receive a 429 response, implement exponential backoff:
async function makeRequestWithBackoff(url, options, maxRetries = 3) {
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const response = await fetch(url, options);
if (response.status === 429) {
if (attempt === maxRetries) {
throw new Error('Max retries exceeded');
}
const retryAfter = response.headers.get('Retry-After') || Math.pow(2, attempt);
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
continue;
}
return response;
} catch (error) {
if (attempt === maxRetries) throw error;
await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
}
}
}
3. Cache Responses
Cache API responses to reduce unnecessary requests:
const cache = new Map();
async function getCachedData(endpoint, ttl = 300000) { // 5 minutes
const cached = cache.get(endpoint);
if (cached && Date.now() - cached.timestamp < ttl) {
return cached.data;
}
const response = await makeRequest(endpoint);
const data = await response.json();
cache.set(endpoint, {
data,
timestamp: Date.now()
});
return data;
}
4. Batch Requests
When possible, use bulk endpoints to reduce request count:
// Instead of multiple single requests
for (const userId of userIds) {
await makeRequest(`/api/users/${userId}`);
}
// Use bulk endpoints
const users = await makeRequest('/api/users/bulk', {
method: 'POST',
body: JSON.stringify({ user_ids: userIds })
});
5. Use Webhooks
For real-time updates, use webhooks instead of polling:
// Instead of polling every minute
setInterval(async () => {
const updates = await makeRequest('/api/updates');
processUpdates(updates);
}, 60000);
// Configure webhooks for real-time updates
// No polling required - updates pushed to your endpoint
Handling Rate Limits
Graceful Degradation
Implement graceful degradation when rate limits are approached:
async function fetchDataWithFallback(endpoint) {
try {
const response = await makeRequest(endpoint);
const remaining = response.headers.get('X-RateLimit-Remaining');
// If low on requests, use cached data
if (remaining < 10) {
const cached = getCachedData(endpoint);
if (cached) return cached;
}
return await response.json();
} catch (error) {
if (error.status === 429) {
// Return cached data if available
return getCachedData(endpoint) || { error: 'Rate limited' };
}
throw error;
}
}
Request Queuing
Implement request queuing to stay within limits:
class RateLimitedQueue {
constructor(requestsPerSecond = 10) {
this.queue = [];
this.processing = false;
this.interval = 1000 / requestsPerSecond;
}
async add(request) {
return new Promise((resolve, reject) => {
this.queue.push({ request, resolve, reject });
this.process();
});
}
async process() {
if (this.processing || this.queue.length === 0) return;
this.processing = true;
while (this.queue.length > 0) {
const { request, resolve, reject } = this.queue.shift();
try {
const result = await request();
resolve(result);
} catch (error) {
reject(error);
}
await new Promise(resolve => setTimeout(resolve, this.interval));
}
this.processing = false;
}
}
Increasing Rate Limits
To increase your rate limits:
- Assess Your Needs: Calculate expected request volume
- Business Justification: Explain use case and requirements
- Contact Support: Reach out with details about your application
- Plan Upgrade: Consider upgrading to higher-tier plan
Enterprise Options
Enterprise customers can get:
- Custom rate limits
- Dedicated infrastructure
- SLA guarantees
- Priority support
- Burst capacity allowances
Monitoring and Alerts
Set Up Monitoring
Monitor your API usage to avoid unexpected rate limiting:
function trackApiUsage(response) {
const remaining = response.headers.get('X-RateLimit-Remaining');
const limit = response.headers.get('X-RateLimit-Limit');
const usagePercent = ((limit - remaining) / limit) * 100;
// Alert when usage exceeds 80%
if (usagePercent > 80) {
console.warn(`High API usage: ${usagePercent}%`);
// Send alert to monitoring system
}
}
Usage Analytics
Track patterns to optimize usage:
- Peak usage times
- Most frequently called endpoints
- Cache hit/miss ratios
- Error rates during high usage