Rate Limits
API rate limits protect the service and ensure fair usage. Learn how they work and how to handle them.
Rate Limit Overview
Limits by Plan
| Plan | Per Minute | Per Hour | Per Day |
|---|---|---|---|
| Pro | 60 | 1,000 | 10,000 |
| Enterprise | 300 | 5,000 | 100,000 |
Per-Key Limits
Limits apply per API key, not per account. Multiple keys have independent limits.
Rate Limit Headers
Every response includes rate limit info:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1640000060
| Header | Description |
|---|---|
X-RateLimit-Limit | Max requests in window |
X-RateLimit-Remaining | Requests left in window |
X-RateLimit-Reset | Unix timestamp when window resets |
Rate Limit Response
When exceeded, you receive 429 Too Many Requests:
{
"success": false,
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Retry after 30 seconds.",
"retry_after": 30
}
}
Headers also include:
Retry-After: 30
Handling Rate Limits
Check Headers
Monitor remaining requests:
async function makeRequest(url) {
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
const remaining = response.headers.get('X-RateLimit-Remaining');
console.log(`Requests remaining: ${remaining}`);
return response;
}
Exponential Backoff
Implement retry with backoff:
async function requestWithRetry(url, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
if (response.status !== 429) {
return response;
}
const retryAfter = response.headers.get('Retry-After') || 1;
const delay = retryAfter * 1000 * Math.pow(2, attempt);
console.log(`Rate limited. Retrying in ${delay}ms`);
await new Promise(resolve => setTimeout(resolve, delay));
}
throw new Error('Max retries exceeded');
}
Queue Requests
For bulk operations, use a queue:
class RateLimitedQueue {
constructor(requestsPerMinute = 60) {
this.interval = 60000 / requestsPerMinute;
this.queue = [];
this.processing = false;
}
add(request) {
return new Promise((resolve, reject) => {
this.queue.push({ request, resolve, reject });
this.process();
});
}
async process() {
if (this.processing) 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(r => setTimeout(r, this.interval));
}
this.processing = false;
}
}
Reducing API Calls
Batch Operations
Instead of multiple calls:
# ❌ Multiple requests
POST /v1/tags {"title": "Tag 1"}
POST /v1/tags {"title": "Tag 2"}
POST /v1/tags {"title": "Tag 3"}
Use batch endpoint:
# ✅ Single request
POST /v1/tags/batch
{
"tags": [
{"title": "Tag 1"},
{"title": "Tag 2"},
{"title": "Tag 3"}
]
}
Caching
Cache responses when possible:
const cache = new Map();
const CACHE_TTL = 60000; // 1 minute
async function getCachedTag(tagId) {
const cached = cache.get(tagId);
if (cached && Date.now() - cached.time < CACHE_TTL) {
return cached.data;
}
const response = await fetch(`/v1/tags/${tagId}`, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
const data = await response.json();
cache.set(tagId, { data, time: Date.now() });
return data;
}
Use Webhooks
Instead of polling:
// ❌ Polling
setInterval(async () => {
const tags = await fetchTags();
checkForChanges(tags);
}, 5000);
Set up webhooks:
// ✅ Webhooks
app.post('/webhook', (req, res) => {
const event = req.body;
handleTagChange(event);
res.sendStatus(200);
});
Endpoint-Specific Limits
Some endpoints have additional limits:
| Endpoint | Additional Limit |
|---|---|
| File upload | 10/minute |
| Bulk operations | 5/minute |
| QR generation | 30/minute |
Monitoring Usage
Dashboard
View API usage:
- Go to Account → API Keys
- Click on a key
- View Usage tab
See:
- Requests per day
- Requests per endpoint
- Error rates
Usage Alerts
Set up notifications:
- Go to API Keys → Alerts
- Configure thresholds:
- 80% of daily limit
- High error rate
- Sustained rate limiting
Increasing Limits
Upgrade Plan
Higher tier = higher limits:
- Pro: 60/min, 10K/day
- Enterprise: 300/min, 100K/day
Request Increase
For special cases:
- Contact [email protected]
- Explain use case
- Request limit increase
- Custom limits available (Enterprise)
Best Practices
Efficient API Usage
- Batch when possible - Use bulk endpoints
- Cache responses - Don't re-fetch unchanged data
- Use webhooks - Avoid polling
- Paginate wisely - Request appropriate page sizes
- Handle errors - Implement proper retry logic
Monitoring
- Track remaining - Monitor rate limit headers
- Alert early - Warn at 80% usage
- Log failures - Track 429 responses
- Analyze patterns - Optimize high-frequency calls
Troubleshooting
Unexpected Rate Limits
If hitting limits unexpectedly:
- Check for runaway loops in code
- Verify caching is working
- Look for duplicate requests
- Check if multiple services share key
Inconsistent Limits
Limits are per-key:
- Multiple keys = independent limits
- Test and prod keys have same limits
- Per-minute window rolls continuously