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

  1. 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.
  2. Globales Plattformlimit. Alles, was der von dir aufgerufene API-Host in diesem Moment verarbeitet, unabhängig vom Endpoint. Eine Ablehnung hier meldet "service": "api".
  3. 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-Limit aus. 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.
  • retryAfter ist 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 enthalten current und limits. Eine reine Existenzprüfung dieser Felder würde Wartungen fälschlicherweise als Problem mit der Nebenläufigkeit interpretieren.
  • Ein 403 mit X-FourA-Limit betrifft 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

Aktualisiert: 30. September 2026