API Rate Limits
API requests are rate-limited per API key using a token bucket algorithm. Limits vary by plan. When exceeded, you receive a 429 error with headers indicating when to retry.What It Is
Rate limiting protects the API from abuse and ensures fair usage. Each API key has a bucket of tokens that refills over time. Each request consumes one token.
How It Works
- Your plan determines your requests-per-minute (RPM) limit
- Each request consumes 1 token from your bucket
- Tokens refill continuously at your plan's rate
- When empty, requests return 429 until tokens refill
Rate Limits by Plan
| Plan | Requests/Minute | Burst Capacity |
|---|---|---|
| Starter | 60 | 60 |
| Pro | 300 | 300 |
| Agency | 1,200 | 1,200 |
Response Headers
Every response includes rate limit headers:
| Header | Description |
|---|---|
| X-RateLimit-Limit | Maximum requests per minute |
| X-RateLimit-Remaining | Tokens remaining in current window |
| X-RateLimit-Reset | Unix timestamp when bucket refills |
Request Example
``bash
curl -i "https://seogeo.tools/api/public/v1/projects" \
-H "Authorization: Bearer sg_live_abc123"
`
Response Headers Example
`
HTTP/1.1 200 OK
X-RateLimit-Limit: 300
X-RateLimit-Remaining: 298
X-RateLimit-Reset: 1706000000
`
Handling 429 Errors
When rate limited, the response is:
`json
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit exceeded. Try again in 60 seconds.",
"requestId": "req_abc123"
}
}
`
Retry Strategy
`javascript
// JavaScript retry with exponential backoff
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status !== 429) return response;
const resetTime = response.headers.get("X-RateLimit-Reset");
const waitMs = resetTime
? (parseInt(resetTime) * 1000 - Date.now())
: Math.pow(2, i) * 1000;
await new Promise(r => setTimeout(r, waitMs));
}
throw new Error("Max retries exceeded");
}
`
`python
Python retry with exponential backoff
import time
import requests
def fetch_with_retry(url, headers, max_retries=3):
for i in range(max_retries):
response = requests.get(url, headers=headers)
if response.status_code != 429:
return response
reset_time = response.headers.get("X-RateLimit-Reset")
if reset_time:
wait_seconds = int(reset_time) - int(time.time())
else:
wait_seconds = 2 i
time.sleep(max(wait_seconds, 1))
raise Exception("Max retries exceeded")
``
FAQ
Q: What happens if I exceed my rate limit?A: You receive a 429 error. Wait until X-RateLimit-Reset timestamp to retry.
Q: Can I request a higher limit?A: Upgrade your plan for higher limits. Agency plan offers 1,200 RPM.
Q: Do rate limits apply per key or per user?A: Rate limits are per API key. Multiple keys have separate limits.