Rate Limits
Every FourA API request passes through rate limiting. You'll encounter two types of limits: concurrency (simultaneous requests) and RPM (requests per minute). Both are enforced per service.
How Rate Limits Work
The API enforces limits at two levels:
- Global API limit: applies to all requests regardless of endpoint. This check runs first.
- Per-service limit: applies separately to each endpoint (single, proxy, browser). This check only runs if the global limit passes.
If the global limit is hit, the per-service check doesn't run. A request must pass both checks before it reaches the backend.
Each level tracks two metrics:
- Concurrency: how many requests are running at the same time.
- RPM: how many requests you've sent in the last 60 seconds.
Rate Limit Responses
When you hit a limit, the API returns a JSON response with your current usage and the limits in effect.
429: RPM Exceeded
{
"error": "Rate limit exceeded",
"status": 429,
"service": "single",
"retryAfter": 5,
"current": {
"concurrency": 12,
"rpm": 3000
},
"limits": {
"maxConcurrency": 500,
"maxRpm": 3000
}
}
You've sent too many requests in the last minute. Wait for the retryAfter period before sending more.
503: Concurrency Exceeded
{
"error": "Service at capacity",
"status": 503,
"service": "proxy",
"retryAfter": 2,
"current": {
"concurrency": 500,
"rpm": 1200
},
"limits": {
"maxConcurrency": 500,
"maxRpm": 3000
}
}
Too many requests are running at the same time. Some of your earlier requests haven't finished yet.
Service Disabled
When a service is temporarily taken offline for maintenance, the API returns 503 with a different error message:
{
"error": "Service disabled",
"status": 503,
"service": "single",
"retryAfter": 60,
"current": { "concurrency": 0, "rpm": 0 },
"limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}
This isn't a rate limit. The service is temporarily unavailable. Check the retryAfter value and retry after that many seconds. This typically resolves within minutes.
Both 503 shapes carry the same keys, so branch on the error string and never on which fields are present. Service disabled is maintenance, Service at capacity is concurrency.
On the maintenance shape, current.concurrency and current.rpm are always 0: the request was turned away before anything was measured. Don't read them as your real usage.
Response Fields
| Field | Type | Description |
|---|---|---|
error |
string | Human-readable error message |
status |
number | HTTP status code (429 or 503) |
service |
string | Which service hit the limit: single, proxy, browser, or api |
retryAfter |
number | Recommended wait time in seconds before retrying |
current.concurrency |
number | Your current number of active requests |
current.rpm |
number | Your requests in the last 60 seconds |
limits.maxConcurrency |
number | Maximum simultaneous requests allowed |
limits.maxRpm |
number | Maximum requests per minute allowed |
Handling Rate Limits
Use the retryAfter field to implement backoff:
import requests
import time
def fetch(url, max_retries=5):
for attempt in range(max_retries):
resp = requests.post(
"https://eu.api.foura.ai/api/single/",
headers={
"X-API-Key": "YOUR_API_KEY",
"Content-Type": "application/json"
},
json={"method": "GET", "url": url}
)
if resp.status_code in (429, 503):
data = resp.json()
wait = data.get("retryAfter", 5)
time.sleep(wait)
continue
return resp
raise Exception("Max retries exceeded")
Tips
- Check the
currentfields in rate limit responses to understand your usage patterns. - If you're consistently hitting concurrency limits, reduce the number of parallel requests.
- If you're hitting RPM limits, add a small delay between requests or batch them over a longer window.
- The
retryAftervalue varies by limit type: 2 seconds for concurrency, 5 seconds for RPM. - A "Service disabled" response means maintenance is in progress. Don't keep hammering the endpoint.
- Match on
errorto tell the two 503s apart. Both shapes carrycurrentandlimits, so a check for "are those fields there?" reads maintenance as a concurrency problem.
Related
- API Endpoints: Full parameter reference
- Error Handling: All error types and responses
- Troubleshooting: Common problems and fixes