Rate Limits
Usage limits, response headers, and best practices for staying within quota.
Limits by Tier
Rate limits are applied per API key. If you exceed the limit, the API returns a 429 Too Many Requests response.
| Tier | Per Minute | Per Day | Per Week |
|---|---|---|---|
| Free | 10 req | 100 req | 50 conversions |
| Pro | 60 req | 10,000 req | 200 conversions |
| Team | 300 req | 100,000 req | 500 conversions |
Response Headers
Every API response includes rate-limit headers so you can proactively manage your usage:
| Header | Description |
|---|---|
| X-RateLimit-Limit | The maximum number of requests allowed in the current time window. |
| X-RateLimit-Remaining | The number of requests remaining in the current time window. |
| X-RateLimit-Reset | Unix timestamp (seconds) when the current window resets. |
Example response headers:
HTTP/1.1 200 OK X-RateLimit-Limit: 60 X-RateLimit-Remaining: 42 X-RateLimit-Reset: 1705312800
Handling 429 Responses
When you receive a 429 response, the body includes a retry_after field indicating how many seconds to wait before retrying:
{
"error": {
"code": "rate_limit_exceeded",
"message": "Rate limit exceeded. Please retry after 12 seconds.",
"status": 429,
"retry_after": 12
}
}Tip: Monitor the
X-RateLimit-Remaining header proactively to throttle your requests before hitting the limit.Exponential Backoff
For production systems, implement exponential backoff with jitter to gracefully handle rate limits and transient errors:
async function requestWithBackoff(url, options, maxRetries = 5) {
let attempt = 0;
while (attempt < maxRetries) {
const res = await fetch(url, options);
if (res.ok) {
return res.json();
}
// Only retry on rate-limit or server errors
if (res.status !== 429 && res.status < 500) {
const { error } = await res.json();
throw new Error(error.message);
}
const { error } = await res.json();
// Use server-provided retry_after, or calculate backoff
const retryAfter = error.retry_after
? error.retry_after * 1000
: Math.min(1000 * Math.pow(2, attempt), 30000);
// Add jitter (0-25% of wait time)
const jitter = retryAfter * Math.random() * 0.25;
const waitMs = retryAfter + jitter;
console.log(
`Rate limited. Retrying in ${Math.round(waitMs / 1000)}s `
+ `(attempt ${attempt + 1}/${maxRetries})`
);
await new Promise(resolve => setTimeout(resolve, waitMs));
attempt++;
}
throw new Error('Max retries exceeded');
}Python example
import time
import random
import requests
def request_with_backoff(url, headers, max_retries=5):
for attempt in range(max_retries):
response = requests.post(url, headers=headers)
if response.ok:
return response.json()
if response.status_code not in (429, 500, 502, 503):
error = response.json().get("error", {})
raise Exception(error.get("message", "Request failed"))
error = response.json().get("error", {})
retry_after = error.get("retry_after", min(2 ** attempt, 30))
# Add jitter
jitter = retry_after * random.uniform(0, 0.25)
wait = retry_after + jitter
print(f"Rate limited. Retrying in {wait:.1f}s "
f"(attempt {attempt + 1}/{max_retries})")
time.sleep(wait)
raise Exception("Max retries exceeded")Best practices summary:
- Always respect the
retry_aftervalue when provided. - Add random jitter to avoid thundering herd effects.
- Set a maximum retry count to prevent infinite loops.
- Log rate-limit events to identify usage patterns.
- Consider queuing requests client-side to stay under the per-minute limit.