Rate Limits
Understanding and handling API rate limits
Rate limits protect the API from abuse and ensure fair usage for all users.
Current Limits
| Limit Type | Value | Scope |
|---|---|---|
| Requests per minute (RPM) | 60 | Per API key |
| Requests per day (RPD) | 1,000 | Per API key |
Rate Limit Headers
All API responses include rate limit information:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1699999999| Header | Description |
|---|---|
X-RateLimit-Limit | Maximum requests allowed in the window |
X-RateLimit-Remaining | Requests remaining in current window |
X-RateLimit-Reset | Unix timestamp when the limit resets |
Rate Limit Errors
When you exceed the rate limit:
HTTP Status: 429 Too Many Requests
{
"error": "Rate Limit Exceeded",
"message": "Too many requests per minute"
}Additional header when rate limited:
Retry-After: 45The Retry-After header indicates seconds to wait before retrying.
Handling Rate Limits
Basic Retry Logic
async function fetchWithRateLimit(url: string, options: RequestInit) {
const response = await fetch(url, options);
if (response.status === 429) {
const retryAfter = parseInt(
response.headers.get('Retry-After') || '60'
);
console.log(`Rate limited. Waiting ${retryAfter} seconds...`);
await sleep(retryAfter * 1000);
// Retry the request
return fetch(url, options);
}
return response;
}
function sleep(ms: number) {
return new Promise(resolve => setTimeout(resolve, ms));
}Exponential Backoff
For production applications, use exponential backoff:
async function fetchWithBackoff(
url: string,
options: RequestInit,
maxRetries = 5
) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
// Get retry delay
const retryAfter = response.headers.get('Retry-After');
const baseDelay = retryAfter
? parseInt(retryAfter) * 1000
: Math.pow(2, attempt) * 1000;
// Add jitter to prevent thundering herd
const jitter = Math.random() * 1000;
const delay = baseDelay + jitter;
console.log(`Rate limited. Retry ${attempt + 1}/${maxRetries} in ${delay}ms`);
await sleep(delay);
}
throw new Error('Max retries exceeded');
}Request Queue
For high-throughput applications, implement a queue:
class RequestQueue {
private queue: Array<() => Promise<void>> = [];
private processing = false;
private requestsThisMinute = 0;
private minuteStart = Date.now();
async add<T>(fn: () => Promise<T>): Promise<T> {
return new Promise((resolve, reject) => {
this.queue.push(async () => {
try {
const result = await fn();
resolve(result);
} catch (error) {
reject(error);
}
});
this.process();
});
}
private async process() {
if (this.processing) return;
this.processing = true;
while (this.queue.length > 0) {
// Reset counter every minute
if (Date.now() - this.minuteStart > 60000) {
this.requestsThisMinute = 0;
this.minuteStart = Date.now();
}
// Wait if at limit
if (this.requestsThisMinute >= 60) {
const waitTime = 60000 - (Date.now() - this.minuteStart);
await sleep(waitTime);
continue;
}
const task = this.queue.shift();
if (task) {
this.requestsThisMinute++;
await task();
}
}
this.processing = false;
}
}
// Usage
const queue = new RequestQueue();
// These requests will be automatically queued and rate-limited
await queue.add(() => verifyFact('Fact 1'));
await queue.add(() => verifyFact('Fact 2'));Best Practices
1. Check Headers Proactively
Monitor X-RateLimit-Remaining and slow down before hitting limits:
function checkRateLimit(response: Response) {
const remaining = parseInt(
response.headers.get('X-RateLimit-Remaining') || '60'
);
if (remaining < 10) {
console.warn(`Low rate limit: ${remaining} requests remaining`);
}
if (remaining < 5) {
// Slow down requests
return { shouldDelay: true, delay: 5000 };
}
return { shouldDelay: false };
}2. Cache Results
Don't verify the same fact twice:
const cache = new Map<string, VerifyResult>();
async function verifyFactCached(fact: string) {
const cacheKey = fact.toLowerCase().trim();
if (cache.has(cacheKey)) {
return cache.get(cacheKey);
}
const result = await verifyFact(fact);
cache.set(cacheKey, result);
return result;
}3. Batch When Possible
If verifying multiple facts, consider combining them:
// Instead of:
await verifyFact('The sky is blue');
await verifyFact('Water is wet');
// Combine into one statement:
await verifyFact('The sky is blue and water is wet');4. Use Multiple API Keys
For different use cases, create separate API keys:
- Development key (lower usage)
- Production key (higher limits)
- Testing key (isolated limits)
Each key has its own rate limit quota.
Need Higher Limits?
If you consistently need higher rate limits:
- Contact us at support@mira.network
- Describe your use case
- We can discuss custom rate limit tiers
Enterprise plans include higher limits and dedicated support.