Rate Limits
Jeder FourA API-Request durchläuft drei Prüfungen, bevor er eine Engine erreicht: die Limits deines eigenen Tarifs, dann das geteilte Plattform-Kontingent für den aufgerufenen Endpoint und schließlich das geteilte Plattform-Kontingent für den gesamten Traffic. Jede Prüfung kann einen Request eigenständig ablehnen, und jede antwortet mit einem unterschiedlichen Body.
Die drei Prüfungen in Reihenfolge
- Tariflimits. Was dein eigener Tarif erlaubt: welche Endpoints und Parameter enthalten sind, wie viele Requests pro Endpoint gleichzeitig laufen dürfen, wie viele pro Minute, wie viele Browser-Requests pro Tag und das im Abrechnungszeitraum verfügbare Guthaben sowie die Bandbreite.
- Globales Plattformlimit. Alles, was der von dir aufgerufene API-Host in diesem Moment verarbeitet, unabhängig vom Endpoint. Eine Ablehnung hier meldet
"service": "api". - Plattformlimit pro Endpoint. Traffic auf dem aufgerufenen Single-, Proxy- oder Browser-Dienst.
Dein eigener Tarif wird zuerst geprüft. Diese Reihenfolge ist vertraglich bindend und kein Implementierungsdetail. Die geteilten Kontingente sind Gemeinschaftsressourcen. Daher darf ein Request, den die Plattform ohnehin ablehnen würde, diese Kontingente auf dem Weg zur Ablehnung nicht verbrauchen. Ein Account, der weit mehr sendet als sein Tarif erlaubt, wird gestoppt, bevor er Ressourcen berührt, die andere nutzen.
Die Prüfungen 2 und 3 zählen den Gesamttraffic von FourA, nicht deinen. Verstehe eine Ablehnung durch eine dieser beiden Prüfungen als "FourA ist ausgelastet" und nicht als "du hast zu viel gesendet". Prüfung 1 betrifft ausschließlich deinen Account, und nichts anderes auf der Plattform beeinflusst sie.
Eine Ablehnung durch eine der geteilten Prüfungen erstattet deinem Account alles zurück, was beim Einlass gezählt wurde: das Minuten-Bucket ebenso wie den Browser-Tages-Slot, da der Request nie ein Backend erreicht hat. Sie zählt auch nicht für die Retry-Pause, die unter Requests pro Minute beschrieben ist: Die Kapazität von FourA hat ihn abgelehnt, nicht dein Tarif.
POST /api/auto/ belegt keinen eigenen Slot. Die Single-, Proxy- und Browser-Sub-Calls, die es für dich ausführt, durchlaufen alle drei Prüfungen wie jeder andere Request. Ein paralleler Batch von Auto-Calls wird deinem Tarif also über seine Sub-Calls angerechnet. (Deine Request-Zähler und deine Erfolgsrate zählen den Auto-Call selbst einmal; die Sub-Calls werden als dessen Versuche angezeigt.)
Tariflimits
Ein Tariflimit antwortet mit einem X-FourA-Limit Header, der das ablehnende Limit nennt. Derselbe Code steht im Body unter reason, sodass du darauf reagieren kannst, ohne Header zu lesen. Jeder Tariflimit-Body enthält error, reason und documentation; die restlichen Felder hängen vom jeweiligen Limit ab.
X-FourA-Limit |
Status | Was erschöpft ist |
|---|---|---|
plan_limit_feature |
403 | Der aufgerufene Endpoint oder der Parameter exitCountries ist nicht in deinem Plan enthalten |
plan_limit_premium |
403 | exitClass: premium ist nicht in deinem Plan enthalten |
plan_limit_concurrency |
429 | Gleichzeitige Requests auf diesem Endpoint |
plan_limit_rate |
429 | Requests pro Minute auf diesem Endpoint |
plan_limit_browser_daily |
429 | Browser-Requests für den heutigen Tag |
plan_limit_credits |
429 | Abgerechnete Credits für den Abrechnungszeitraum |
plan_limit_bandwidth |
429 | Bandbreite für den Abrechnungszeitraum |
Die Werte hinter jedem Limit hängen von deinem Plan ab. Der Tab Limits & Features unter Usage & Limits listet sie neben deiner aktuellen Nutzung auf. Hardcode sie nicht: Jede Ablehnung enthält das Limit, das sie ausgelöst hat.
Ein abgelehnter Request verbraucht nichts. Das Ergebnis ist rate_limit, und nur success wird abgerechnet.
Endpoint oder Parameter nicht im Plan enthalten
Ein 403 mit plan_limit_feature bedeutet, dass der Aufruf etwas angefordert hat, das dein Plan nicht enthält. Die Prüfung erfolgt, bevor etwas gezählt wird. Ein abgelehnter Aufruf wirkt sich daher nicht auf deine Rate-Limits oder Tageszähler aus.
{
"error": "The browser endpoint is not included in your plan (Free). Upgrade to use it.",
"reason": "plan_limit_feature",
"documentation": "https://foura.ai/prices"
}
Derselbe Code und Status beantworten einen POST /api/proxy/-Aufruf, der exitCountries für einen Plan ohne Geo-Targeting setzt. Der error-String benennt den Parameter:
{
"error": "Geo targeting (the exitCountries parameter) is not included in your plan (Free). Remove the parameter or upgrade.",
"reason": "plan_limit_feature",
"documentation": "https://foura.ai/prices"
}
plan_limit_premium hat die gleiche Form für exitClass: premium in einem Tarif ohne Premium-Exits. FourA kann einen solchen Request stattdessen aus dem Standard-Pool bedienen und exitClass: standard in der Response melden, verarbeite also beide Antworten. Keine von beiden verbraucht einen Premium-Exit. Siehe exitClass.
Kein 403 setzt Retry-After. Warten ändert das Ergebnis nicht.
Gleichzeitige Requests
Gleichzeitigkeit wird pro Endpoint gezählt: Dein Tarif enthält ein Limit für Single, eins für Proxy und eins für Browser. Der Request, der das Limit überschreitet, wird als 429 mit Retry-After: 1 beantwortet:
{
"error": "Concurrency limit reached: your plan allows 50 simultaneous proxy request(s). Retry when an in-flight request finishes.",
"reason": "plan_limit_concurrency",
"documentation": "https://foura.ai/prices",
"limit": 50,
"in_flight": 51,
"retry_after_seconds": 1
}
in_flight zählt auch den abgewiesenen Request, daher zeigt es mindestens eins mehr an als limit.
Die Lösung besteht darin, deine eigene Parallelität zu begrenzen, anstatt aggressiver zu wiederholen. Wenn du auf einen 429-Fehler mit dem sofortigen erneuten Senden desselben Batches reagierst, erzeugt dies für jeden einzelnen Aufruf darin einen weiteren 429-Fehler. Siehe Requests parallel ausführen für ein ausgearbeitetes Muster.
Requests pro Minute
Single und Proxy haben ein Kontingent pro Minute, gemessen über eine gleitende Minute. Nur zugelassene Requests zählen dazu: Ein abgewiesener Request wird wieder abgezogen, sodass ein Account, der kontinuierlich etwas mehr als sein Kontingent anfragt, bis zu seinem Limit bedient wird, anstatt fast alles abgewiesen zu bekommen.
{
"error": "Rate limit reached: your plan allows 600 single requests per minute. Cool down and retry.",
"reason": "plan_limit_rate",
"documentation": "https://foura.ai/prices",
"limit_per_minute": 600,
"current_rate": 613,
"retry_after_seconds": 17
}
retry_after_seconds gibt an, wie lange es dauert, bis ein weiterer Request zugelassen wird, wenn du dazwischen nichts sendest: mindestens 1 Sekunde und höchstens 120. Der Retry-After-Header enthält denselben Wert.
Für das schnellere Wiederholen abgelehnter Requests gilt eine eigene Regel. Wenn die in der gleitenden Minute durch dieses Kontingent abgelehnten Requests das Doppelte des Kontingents überschreiten, wird der Aufruf stattdessen mit einer 30-sekündigen Pause abgelehnt:
{
"error": "Rate limit cooldown: 1250 requests over your plan's 600 single requests per minute were refused in the last minute and kept arriving. Pause for 30 seconds.",
"reason": "plan_limit_rate",
"documentation": "https://foura.ai/prices",
"limit_per_minute": 600,
"current_rate": 540,
"refused_last_minute": 1250,
"cooldown": true,
"retry_after_seconds": 30
}
Ablehnungen während der Pause werden nicht gezählt, daher endet die Pause von selbst mit fortschreitender Minute, selbst wenn ein Client weiterhin Retries sendet. Um die Pause vom normalen Kontingent zu unterscheiden, lies cooldown statt des error-Textes.
Browser-Requests pro Tag
Browser hat kein Minuten-Kontingent. Sein Plan-Limit ist eine Anzahl von Browser-Requests pro Tag, gezählt ab Mitternacht UTC, und der Zähler erfasst jeden zugelassenen Browser-Request, nicht nur erfolgreiche.
{
"error": "Daily browser limit reached: your plan allows 300 browser requests per day (resets at midnight UTC).",
"reason": "plan_limit_browser_daily",
"documentation": "https://foura.ai/prices",
"limit_per_day": 300,
"used_today": 301
}
Diese Verweigerung enthält keinen retry_after_seconds- und keinen Retry-After-Header, da die Wartezeit Stunden statt Sekunden beträgt. Behandle dies als Stopp und plane den nächsten Durchlauf für Mitternacht UTC.
Credits für den Abrechnungszeitraum
Nur abgerechnete Credits zählen, also nur erfolgreiche Requests. Wenn die abgerechnete Gesamtsumme die dir in diesem Zeitraum verfügbaren Credits erreicht, werden weitere Requests verweigert, bis der Zeitraum zurückgesetzt wird oder du weitere kaufst.
{
"error": "Credit limit reached: 75,000 of 75,000 credits used this billing period. Upgrade your plan or wait for the reset.",
"reason": "plan_limit_credits",
"documentation": "https://foura.ai/prices",
"used": 75000,
"hard_stop": 75000,
"retry_after_seconds": 86400,
"resets_at": "2026-10-01T00:00:00.000Z"
}
hard_stop ist der abgerechnete Guthabenstand, ab dem Requests fuer diesen Zeitraum gestoppt werden. Lies diesen Wert direkt aus dem Body aus, anstatt ihn zu berechnen: Er enthaelt bereits alle Credits, die du zusaetzlich zum Tarif gekauft hast.
Bandbreite fuer den Abrechnungszeitraum
Tarife mit einem Bandbreitenlimit lehnen Requests ab, sobald der Standard-Traffic in diesem Zeitraum das Limit erreicht. Premium-Traffic hat ein eigenes Kontingent und zaehlt nicht zu diesem Limit. Gekaufte Bandbreite zaehlt genauso wie inklusive Bandbreite, und der error-String gibt an, was dir insgesamt zur Verfuegung steht, nicht nur was der Tarif allein enthaelt.
{
"error": "Bandwidth limit reached: 50 GB is available to you this billing period.",
"reason": "plan_limit_bandwidth",
"documentation": "https://foura.ai/prices",
"used_bytes": 53687091200,
"limit_bytes": 53687091200,
"retry_after_seconds": 86400,
"resets_at": "2026-10-01T00:00:00.000Z"
}
Bei beiden Periodenlimits ist retry_after_seconds auf 24 Stunden begrenzt; resets_at ist der genaue Zeitpunkt, an dem die Periode zurückgesetzt wird.
Plan-Limit-Felder
| Feld | Typ | Vorhanden bei | Beschreibung |
|---|---|---|---|
error |
string | alle | Für Menschen lesbare Nachricht, einschließlich des für dich geltenden Werts |
reason |
string | alle | plan_limit_ plus Name des Limits. Identischer Wert wie der X-FourA-Limit-Header. |
documentation |
string | alle | Link zur Plan-Übersicht |
retry_after_seconds |
number | Concurrency, Rate, Credits, Bandbreite | Wartezeit. Identischer Wert wie der Retry-After-Header. |
limit |
number | Concurrency | Gleichzeitige Requests, die der Plan auf diesem Endpoint erlaubt |
in_flight |
number | Concurrency | Laufende Requests auf diesem Endpoint für deinen Account, einschließlich des abgelehnten |
limit_per_minute |
number | Rate | Requests pro Minute, die der Plan auf diesem Endpoint erlaubt |
current_rate |
number | Rate | In der gleitenden Minute gezählte Requests, einschließlich des abgelehnten |
refused_last_minute |
number | Rate Pause | Durch das Minutenkontingent abgelehnte Requests in der gleitenden Minute. Nur bei der 30-Sekunden-Pause. |
cooldown |
boolean | Rate Pause | true bei der 30-Sekunden-Pause wegen zu schneller Retries. Fehlt bei einer normalen Minutenablehnung. |
limit_per_day |
number | Browser täglich | Browser-Requests, die der Plan pro Tag erlaubt |
used_today |
number | Browser täglich | Heute gezählte Browser-Requests, einschließlich des abgelehnten |
used |
number | Credits | Bisher abgerechnete Credits in dieser Periode |
hard_stop |
number | Credits | Abgerechnete Credits, ab denen Requests in dieser Periode gestoppt werden |
used_bytes |
number | Bandbreite | Bisheriger Standard-Traffic in dieser Periode in Bytes. Premium-Traffic ist nicht enthalten. |
limit_bytes |
number | Bandbreite | Verfügbare Bytes in dieser Periode |
resets_at |
string | Credits, Bandbreite | ISO-8601-Zeitstempel des Periodenendes |
Plan-Limits verwenden retry_after_seconds. Die unten aufgeführten Plattform-Limits verwenden retryAfter. Ein Retry-Helper muss beide auswerten oder den Retry-After-Header lesen, den nur Plan-Limits setzen.
Plattform-Limits
Die Plattform-Checks erfassen zwei Werte pro Service und einen weiteren über alle Services hinweg:
- Concurrency: Wie viele Requests FourA gleichzeitig verarbeitet.
- RPM: Wie viele Requests FourA in den letzten 60 Sekunden angenommen hat.
Beide Zähler werden von allen geteilt, die diesen Service nutzen. current und limits in den folgenden Responses beschreiben die Plattform, nicht deinen Account. Wenn du deinen eigenen Wert benötigst, lies in_flight aus einer Plan-Limit-Response oder öffne Nutzung & Limits im Dashboard.
429: RPM überschritten
{
"error": "Rate limit exceeded",
"status": 429,
"service": "single",
"retryAfter": 5,
"current": {
"concurrency": 12,
"rpm": 3000
},
"limits": {
"maxConcurrency": 500,
"maxRpm": 3000
}
}
Der Dienst hat die zulässigen Requests für die letzte Minute verbraucht. Warte retryAfter Sekunden.
503: Concurrency Exceeded
{
"error": "Service at capacity",
"status": 503,
"service": "proxy",
"retryAfter": 2,
"current": {
"concurrency": 500,
"rpm": 1200
},
"limits": {
"maxConcurrency": 500,
"maxRpm": 3000
}
}
Der Service verarbeitet gerade so viele Requests gleichzeitig wie maximal zulässig. Dies löst sich in wenigen Sekunden auf.
Service deaktiviert
Wenn ein Service für Wartungsarbeiten vorübergehend offline genommen wird, gibt die API einen 503 mit einer anderen Fehlermeldung zurück:
{
"error": "Service disabled",
"status": 503,
"service": "single",
"retryAfter": 60,
"current": { "concurrency": 0, "rpm": 0 },
"limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}
Das ist kein Rate Limit. Der Dienst ist vorübergehend nicht verfügbar. Prüfe den Wert von retryAfter und versuche es nach dieser Anzahl an Sekunden erneut. Dies löst sich normalerweise innerhalb von Minuten.
Beide 503-Formate enthalten dieselben Keys. Verzweige daher nach dem error-String und niemals danach, welche Felder vorhanden sind. Service disabled bedeutet Wartung, Service at capacity bedeutet Concurrency.
Beim Wartungsformat sind current.concurrency und current.rpm immer 0: Der Request wurde abgewiesen, bevor Messungen stattfanden.
Platform Limit Fields
| Feld | Typ | Beschreibung |
|---|---|---|
error |
string | Lesbare Fehlermeldung |
status |
number | HTTP-Statuscode (429 oder 503) |
service |
string | Welcher Dienst den Call abgelehnt hat: single, proxy, browser oder api |
retryAfter |
number | Empfohlene Wartezeit in Sekunden vor dem nächsten Versuch |
current.concurrency |
number | Requests, die der Dienst plattformweit ausführte, als er ablehnte |
current.rpm |
number | Requests, die der Dienst in den letzten 60 Sekunden plattformweit verarbeitet hat |
limits.maxConcurrency |
number | Plattformweites Concurrency-Limit des Dienstes |
limits.maxRpm |
number | Plattformweites Limit des Dienstes pro Minute |
Alle Ablehnungen mit einem Helper behandeln
Retry-After ist bei Plan-Limits gesetzt, bei denen sich Warten lohnt, retry_after_seconds steht in deren Body und retryAfter in den Plattform-Bodies. Lies alle drei in dieser Reihenfolge aus und brich bei den Plan-Limits ab, die sich durch Warten nicht beheben lassen:
import time
import requests
# Plan limits that a short wait never clears.
STOP_ON = {
"plan_limit_feature",
"plan_limit_premium",
"plan_limit_browser_daily",
"plan_limit_credits",
"plan_limit_bandwidth",
}
def wait_seconds(resp, attempt):
header = resp.headers.get("Retry-After")
if header and header.isdigit():
return int(header)
try:
body = resp.json()
except ValueError:
return 2 ** attempt
return body.get("retry_after_seconds") or body.get("retryAfter") or 2 ** attempt
def fetch(url, api_key, max_retries=5):
for attempt in range(max_retries):
resp = requests.post(
"https://eu.api.foura.ai/api/single/",
headers={"X-API-Key": api_key, "Content-Type": "application/json"},
json={"method": "GET", "url": url},
)
limit = resp.headers.get("X-FourA-Limit")
if limit in STOP_ON:
raise RuntimeError(f"stopped by plan limit {limit}: {resp.json().get('error')}")
if resp.status_code in (429, 503):
time.sleep(wait_seconds(resp, attempt))
continue
return resp
raise RuntimeError("Max retries exceeded")
Ein Tageskontingent steht erst nach Stunden wieder zur Verfügung und ein Periodenkontingent erst nach Tagen. Betrachte sie daher als Stopp und nicht als kurze Pause. Lies resets_at aus dem Body aus, wenn du den nächsten Durchlauf planen möchtest.
Tipps
- Begrenze die Anzahl der parallelen Requests, anstatt einen abgelehnten Batch sofort wiederholen zu lassen. Ein Retry-Sturm macht aus einem einzelnen 429 viele weitere.
- Lies zuerst
X-FourA-Limitaus. Der Wert zeigt dir direkt, ob das Limit von deinem Tarif oder der Plattform stammt. Plattform-Ablehnungen setzen diesen Wert nicht. - Hardcode keine Grenzwerte. Jede Tariflimit-Response enthält das Limit, an dem die Anfrage abgewiesen wurde. Nutzung & Limits listet alle Werte auf.
retryAfterist bei Plattform-Limits je nach Typ fest vorgegeben: 2 Sekunden bei Nebenläufigkeit, 5 bei RPM, 60 bei Wartungsarbeiten.- Prüfe
error, um die beiden 503-Typen zu unterscheiden. Beide Formate enthaltencurrentundlimits. Eine reine Existenzprüfung dieser Felder würde Wartungen fälschlicherweise als Problem mit der Nebenläufigkeit interpretieren. - Ein 403 mit
X-FourA-Limitbetrifft deinen Tarif, nicht die Zielseite. Das Ziel hat nie geantwortet.
Der Proxy-Port hat eigene Grenzwerte
Alles oben Genannte gilt für die JSON API. Traffic über proxy.foura.ai unterliegt separaten Tarifwerten in anderen Einheiten: gleichzeitig geöffnete Tunnel, Tunnelöffnungen pro Minute und das Standard-Trafficvolumen des Abrechnungszeitraums. Diese Ablehnungen erfolgen über einen HTTP-Status mit X-Foura-Error Header statt über einen JSON-Body, da ein CONNECT keinen Body hat. Die Statustabelle findest du unter Proxy-Port. Details dazu, aus welchem Pool die Gigabytes des Ports stammen, bietet Tarifabrechnung und Zählung.
Verwandte Themen
- Parallele Requests ausführen: Ein praktisches Pattern für begrenzte Nebenläufigkeit
- Nutzung & Limits: Alle Tariflimits im Vergleich zu deiner aktuellen Nutzung
- API-Endpoints: Vollständige Parameter-Referenz
- Fehlerbehandlung: Alle Fehlertypen und Responses
- Response-Header:
X-FourA-Limit,Retry-Afterund weitere - Fehlerbehebung: Häufige Probleme und Lösungen