Rate Limits
Understand how rate limiting works and how to optimize your API usage.
Overview
Rate limits protect our API from abuse and ensure fair usage for all users. Limits are applied per API key and vary based on your plan.
Limits reset automatically
Per-minute limits reset every 60 seconds. Daily limits reset at midnight UTC.
Limits by Plan
Each plan has different rate limits and quotas:
Free
Requests per minute
10
Requests per day
100
QR codes per month
50
- Basic QR types
- PNG format only
Pro
Requests per minute
60
Requests per day
5,000
QR codes per month
5,000
- All QR types
- All formats
- Custom styling
- Dynamic QR codes
Business
Requests per minute
300
Requests per day
50,000
QR codes per month
Unlimited
- Everything in Pro
- Priority support
- Team collaboration
- Bulk operations
Rate Limit Headers
Every API response includes headers to help you track your usage:
| Header | Description | Example |
|---|---|---|
| X-RateLimit-Limit | Max requests per minute for your plan | 60 |
| X-RateLimit-Remaining | Requests remaining in current window | 45 |
| X-RateLimit-Reset | Unix timestamp when the window resets | 1704067200 |
| Retry-After | Seconds to wait (only on 429 responses) | 30 |
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1704067200Handling Rate Limits
When you exceed the rate limit, you'll receive a 429 response. Here's how to handle it:
{
"success": false,
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please retry after 30 seconds.",
"details": {
"retryAfter": 30
}
}
}Implementing Exponential Backoff
Use exponential backoff with jitter for the most resilient implementation:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.ok) {
return response.json();
}
if (response.status === 429) {
const retryAfter = response.headers.get('Retry-After');
const waitTime = retryAfter
? parseInt(retryAfter, 10) * 1000
: Math.min(1000 * Math.pow(2, attempt) + Math.random() * 1000, 60000);
console.log(`Rate limited. Waiting ${waitTime}ms before retry...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
continue;
}
// Non-retryable error
const error = await response.json();
throw new Error(error.error?.message || 'Request failed');
}
throw new Error('Max retries exceeded');
}
// Usage
const qrCode = await fetchWithRetry('https://quality-qr.app/api/v1/qr', {
method: 'POST',
headers: {
'Authorization': 'Bearer YOUR_API_KEY',
'Content-Type': 'application/json',
},
body: JSON.stringify({ type: 'url', content: 'https://example.com' }),
});Best Practices
Monitor your usage
Check the X-RateLimit-Remaining header to avoid hitting limits unexpectedly.
Use bulk endpoints
When generating multiple QR codes, use the bulk endpoint to create up to 100 codes in a single request.
Cache responses
Cache generated QR codes on your end to avoid regenerating the same codes repeatedly.
Implement request queuing
Queue requests client-side and process them at a rate below your limit for smoother performance.
Avoid request bursts
Spread requests evenly over time instead of sending many at once. Bursting can trigger rate limits even if you're under the daily quota.
Need Higher Limits?
Upgrade to a higher plan for increased rate limits, or contact us for custom enterprise limits.