API-Fehler

Wie du Fehler der FourA-API behandelst.

Fehlerantwort-Format

Die API gibt für alle Fehler flache JSON-Objekte zurück. Es gibt kein geschachteltes error-Objekt oder Fehlercodes.

{
  "error": "Invalid API key"
}

Einige Fehler enthalten zusätzliche Felder wie status, service, retryAfter, current oder limits auf der obersten Ebene:

{
  "error": "Rate limit exceeded",
  "status": 429,
  "service": "single",
  "retryAfter": 5,
  "current": { "concurrency": 12, "rpm": 3000 },
  "limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}

Request-Tracking

Jede API-Response (Erfolg oder Fehler) enthält einen X-Foura-Request-Id-Header mit einer UUID für diesen Aufruf. Protokolliere sie auf deiner Seite. Wenn du den Support fragen musst, was mit einem bestimmten Request passiert ist, können wir ihn anhand dieser ID finden.

curl -i -X POST https://eu.api.foura.ai/api/single/ \
  -H "X-API-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"method": "GET", "url": "https://example.com"}'
# HTTP/1.1 200 OK
# X-Foura-Request-Id: 9f1c4e6c-7b2a-4d3e-8a1f-2c9d8e4a3b15
# Content-Type: application/json
# ...

Fehlertypen

400: Bad Request

Der Request-Body enthält fehlende Pflichtfelder, ungültige Werte oder nennt ein Ziel, dessen Abruf die API verweigert.

{
  "error": "Invalid request body format"
}

Derselbe 400er-Fehler deckt auch den SSRF-Schutz ab. Wenn deine url in einen privaten, Loopback- oder anderweitig reservierten IP-Bereich auflöst (RFC 5735, RFC 6598, reservierte IPv6-Blöcke), wird der Request abgelehnt, bevor er das Netzwerk von FourA verlässt:

{
  "error": "Target <ip> resolves to a private/reserved IP"
}

Lösung: Überprüfe, ob dein Request alle erforderlichen Felder enthält, ob URLs http:// oder https:// verwenden und ob der Host in eine öffentliche Adresse auflöst.

401: Unauthorized

Dein API-Key fehlt oder ist ungültig.

Fehlender Key:

{
  "error": "Missing API key. Include X-API-Key header."
}

Ungültiger Key:

{
  "error": "Invalid API key"
}

Lösung: Überprüfe, ob dein X-API-Key-Header einen gültigen Key enthält. Erstelle bei Bedarf einen neuen Key im Dashboard.

429: Rate Limited

Du hast zu viele Requests in kurzer Zeit gesendet.

{
  "error": "Rate limit exceeded",
  "status": 429,
  "service": "single",
  "retryAfter": 5,
  "current": { "concurrency": 12, "rpm": 3000 },
  "limits": { "maxConcurrency": 500, "maxRpm": 3000 }
}

Lösung: Warte die in retryAfter angegebene Anzahl an Sekunden, bevor du weitere Requests sendest. Details findest du unter Rate Limits.

500: Server Error

Auf unserer Seite ist ein Fehler aufgetreten.

Lösung: Wiederhole den Request nach einer kurzen Verzögerung. Wenn der Fehler weiterhin besteht, überprüfe die Statusseite oder kontaktiere den Support mit der X-Foura-Request-Id aus der fehlgeschlagenen Response.

503: Service Disabled or At Capacity

Ein 503 bedeutet entweder, dass der Dienst wegen Wartungsarbeiten vorübergehend nicht verfügbar ist, oder dass du das Concurrency-Limit erreicht hast. Beide Antworten enthalten ein retryAfter-Feld. Die Variante für das Concurrency-Limit enthält zudem current und limits.

{
  "error": "Service disabled",
  "status": 503,
  "retryAfter": 60
}

Lösung: Warte retryAfter Sekunden und versuche es dann erneut. Die Statusseite listet aktive Wartungsfenster auf.

Zielseitige Fehler innerhalb von 200 OK

Nicht jeder Fehler äußert sich in einem HTTP-Status ungleich 2xx. Wenn die Zielseite HTTP 200 mit einem Fehler-Payload zurückgibt, übergibt FourA dir dennoch den Body, klassifiziert den Request jedoch als application_error. Wenn das Ziel einen Status ungleich 2xx zurückgibt, den deine validate-Regeln nicht akzeptieren, ist das Ergebnis application_fail und der Body wird unverändert durchgereicht.

Beide Fälle sind kostenpflichtig, als ob der Request auf Protokollebene erfolgreich gewesen wäre. Die Referenz zu Outcomes beschreibt die vollständige Taxonomie.

Response-Codierung

FourA decodiert Response-Bodys automatisch in UTF-8. Wenn das Ziel windows-1251, gbk, shift_jis, iso-8859-* oder einen anderen Zeichensatz ausliefert, der im Content-Type-Header oder einem HTML-Tag <meta charset> deklariert ist, erhältst du einen sauberen UTF-8-String im Feld data (single, proxy) oder body (browser).

Setze bei binären Payloads (Bilder, Protobuf, rohes Audio) returnBuffer: true im Request. Der Body wird als Base64-Buffer zurückgegeben, ohne dass eine Zeichensatz-Transcodierung angewendet wird.

Retry-Strategie

Eine praktische Retry-Policy:

import time
import requests

def make_request(url, payload, api_key, max_retries=3):
    for attempt in range(max_retries):
        resp = requests.post(
            url,
            headers={"X-API-Key": api_key, "Content-Type": "application/json"},
            json=payload,
        )
        if resp.status_code == 200:
            return resp.json()

        body = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
        retry_after = body.get("retryAfter", 2 ** attempt)
        request_id = resp.headers.get("X-Foura-Request-Id", "?")

        if resp.status_code in (429, 503):
            time.sleep(retry_after)
            continue
        if resp.status_code >= 500:
            time.sleep(2 ** attempt)
            continue

        # 400/401/404 won't fix themselves
        raise RuntimeError(f"{resp.status_code} (request {request_id}): {body.get('error')}")

    raise RuntimeError(f"Exhausted {max_retries} retries")

Verwandte Themen

Aktualisiert: 18. Juni 2026