---
seo_title: API-Fehlercodes erklärt: 400, 401, 402, 403, 413 | EnConvert
meta_desc: Jeder HTTP-Statuscode der EnConvert API: 401 ungültiger API-Key, 402 monatliches Ops-Limit erreicht, 413 Datei zu groß, mit exakten Meldungen und Lösungen.
keywords: 402 payment required ops-limit erreicht api, 401 unauthorized ungültiger api key, 413 payload too large detail max_size, enconvert api fehlercodes liste, 429 too many requests rate limit api, 422 unprocessable entity unbekanntes feld, 410 gone artefakt aufbewahrung abgelaufen, api fehlerantwort format detail json
---

# EnConvert API-Fehlercodes

Diese Referenz listet die HTTP-Statuscodes und Fehlermeldungen auf, die die EnConvert API zurückgibt: von `200 OK` für synchrone Konvertierungen und `202 Accepted` für async- und Batch-Jobs bis zu den unten dokumentierten Fehlerantworten. Jeder Fehlerabschnitt listet die genauen Meldungstexte, die Bedingung, die den jeweiligen Fehler auslöst, und wie du den Request korrigierst. Fehler-Bodies haben nicht alle dieselbe Form: es gibt sechs davon, und der Abschnitt [Format der Fehlerantwort](#error-response-format) zeigt jede einzelne.

Ein Job, der *nach* seiner Annahme scheitert, ist kein HTTP-Fehler. Der `202` bleibt bestehen, und der Fehlschlag erscheint im Status-Payload des Jobs, wenn du ihn abfragst; beschrieben unter [Sync- und async-Jobs](/de/docs/concepts/sync-and-async.md).

---

## HTTP-Statuscodes

| Code | Status | Beschreibung |
|------|--------|-------------|
| `200` | OK | Konvertierung erfolgreich abgeschlossen (sync-Modus). |
| `202` | Accepted | Batch- oder async-Job wurde zur Hintergrundverarbeitung angenommen. |
| `400` | Bad Request | Ungültige Parameter, fehlende Pflichtfelder, fehlerhafter Request-Body oder ungültiger Dateiinhalt. |
| `401` | Unauthorized | Fehlender, ungültiger oder abgelaufener API-Key bzw. JWT-Token. |
| `402` | Payment Required | Monatliches Ops-Kontingent erschöpft, kein aktiver Abrechnungszeitraum, Watcher-Obergrenze erreicht, Speicherlimit erreicht oder ein V2-Endpunkt ist in deinem Plan abgeschaltet. |
| `403` | Forbidden | Beschränkung nach Key-Typ, Domain oder Endpunkt-Allowlist, ein V1-Feature-Gate (async, Webhooks, ZIP-Ausgabe, Basic Auth, Batch) oder Zugriff auf die Ressource eines anderen Projekts. |
| `404` | Not Found | Angeforderte Ressource (Job, Batch, Operation, Datei, Watcher oder Widget) existiert nicht, oder der Pfad ist keine Route. |
| `405` | Method Not Allowed | Der Pfad existiert, aber nicht für die von dir verwendete HTTP-Methode. |
| `409` | Conflict | Eine vom Client gelieferte `job_id` ist bereits in Gebrauch, oder für einen Ingest-Job, der nicht abgeschlossen ist, wurde ein Webhook-Retry angefordert. |
| `410` | Gone | Ein V2-Artefakt oder ein Batch-Archiv hat das Aufbewahrungsfenster für Dateien deines Plans überschritten und liegt nicht mehr im Speicher. |
| `413` | Payload Too Large | Hochgeladene Datei überschreitet das Größenlimit deines Abonnements. |
| `415` | Unsupported Media Type | Die Ziel-URL gab Inhalt zurück, den dieser Konverter nicht rendern kann (z. B. JSON an `url-to-pdf`). |
| `422` | Unprocessable Entity | Der Request-Body hat die Schema-Validierung nicht bestanden (einschließlich unbekannter Felder an V2-Endpunkten), oder eine Rendering-Vorbedingung schlug fehl, etwa ein `wait_for_selector`, der nie erschien. |
| `429` | Too Many Requests | Ein Request-Rate-Limit über ein kurzes Zeitfenster wurde ausgelöst. Das ist nicht der Kontingent-Code; ein erschöpftes Monatskontingent antwortet mit `402`. |
| `500` | Internal Server Error | Unerwarteter Fehler während der Konvertierung (unsere Engine ist ausgefallen). |
| `502` | Bad Gateway | Die Zielseite konnte nicht erreicht werden, ein vorgelagerter Provider ist ausgefallen, oder das Ziel lieferte eine Anti-Bot-Challenge ohne Seiteninhalt (`/v2/perceive`, sofern `allow_degraded` nicht gesetzt ist). |
| `503` | Service Unavailable | Ein Konverter ist nicht verfügbar, der Rendering-Pool oder das Zulassungs-Gate für Konvertierungen ist ausgelastet, oder eine vorgelagerte Abhängigkeit ist ausgefallen. |
| `504` | Gateway Timeout | Die Zielseite brauchte zu lange, um zu antworten oder das Laden abzuschließen, oder der Request überschritt das 300-Sekunden-Budget des Gateways. |

---

## Format der Fehlerantwort {: #error-response-format }

Es gibt sechs Body-Formen. Welche du bekommst, hängt davon ab, wo der Fehler auftrat, nicht allein vom Statuscode. Prüfe also den Typ von `detail`, bevor du ihn ausliest.

**1. `detail` als String.** Der Normalfall und die einzige Form, die die meisten Integrationen überhaupt zu sehen bekommen.

```json
{
    "detail": "Authentication required"
}
```

**2. `detail` als Objekt.** Der `413` zum Dateigrößenlimit des Plans. Das strukturierte Objekt ist der Wert von `detail`, lies also `body.detail.max_size`, nicht `body.max_size`. Siehe [413 Payload Too Large](#413-payload-too-large).

```json
{
    "detail": {
        "error": "File too large",
        "file_size": 10485760,
        "max_size": 5242880,
        "tier": "free",
        "key_type": "private"
    }
}
```

**3. `detail` als Array plus `errors`.** Die Schema-Validierung (`422`) gibt beides zurück: `detail` ist die rohe Ausgabe des Validators, `errors` ist ein paralleles Array aus menschenlesbaren Strings. Siehe [422 Unprocessable Entity](#422-unprocessable-entity).

**4. Typisierter Konvertierungs-Envelope.** `{"error", "code", "detail"}`, mit einem maschinenlesbaren `code`. Wird nur von den drei V1-URL-Konvertierungs-Endpunkten ausgegeben. Siehe [Browser-Konvertierungsfehler](#browser-conversion-errors-415-422-502-504).

**5. Unbehandelte Exception.** Ein `500`, der nicht von einem Konverter stammt, hat überhaupt kein `detail`:

```json
{
    "error": "Internal server error",
    "event_id": "a1b2c3d4"
}
```

**6. Gateway-Request-Timeout.** Das eigene 300-Sekunden-Budget des Gateways erzeugt einen `504` ohne `detail` und ohne `code`:

```json
{
    "error": "Request timeout"
}
```

---

## 400 Bad Request

Wird zurückgegeben, wenn der Request ungültige Parameter, fehlende Felder oder fehlerhafte Daten enthält.

### Eingabevalidierung

| Meldung | Bedingung |
|---------|-----------|
| `'url' must be provided` | Fehlendes oder leeres `url`-Feld bei URL-basierten Endpunkten. |
| `Invalid file format '{ext}' for {endpoint}. Allowed: {list}` | Die Erweiterung der hochgeladenen Datei passt nicht zu den vom Endpunkt akzeptierten Formaten. |
| `File content does not match the '{endpoint}' input type.` | Die Erweiterung wurde akzeptiert, aber die Magic Bytes der Datei gehören zu einem anderen Format. |
| `Invalid pdf_options: {error}` | Fehlerhaftes JSON im Formularfeld `pdf_options`. |

### Batch- und Modus-Validierung

| Meldung | Bedingung |
|---------|-----------|
| `Public keys only support a single URL input` | Public-/Dashboard-Key versuchte, mehrere URLs zu senden. |
| `output_format=True requires multiple URLs` | ZIP-Bündelung mit nur einer URL angefordert. |
| `direct_download not supported for multiple URLs` | `direct_download=true` mit einem Array von URLs. |
| `direct_download only works in sync mode` | `direct_download=true` kombiniert mit `async_mode=true`. |

### Validierung von Auth, Cookies & Headern

| Meldung | Bedingung |
|---------|-----------|
| `'auth' must be an object with 'username' and 'password'` | Der Parameter `auth` hat eine falsche Struktur. |
| `'cookies' must be an array of cookie objects` | `cookies` ist kein Array. |
| `'cookies' array must not exceed 50 entries` | Mehr als 50 Cookies angegeben. |
| `Cookie at index {i} must be an object` | Cookie-Eintrag ist kein Dictionary. |
| `Cookie at index {i} must have 'name' and 'value'` | Cookie fehlen Pflichtfelder. |
| `Cookie at index {i} must have 'domain' or 'url'` | Cookie fehlen sowohl `domain` als auch `url`. |
| `'headers' must be an object of header name/value pairs` | `headers` ist kein Dictionary. |
| `'headers' must not exceed 20 entries` | Mehr als 20 benutzerdefinierte Header. |
| `Header '{name}' cannot be overridden` | Versuch, einen gesperrten Header zu setzen. Gesperrt sind `host`, `content-length`, `transfer-encoding`, `connection`, `upgrade`, `te`, `trailer`. |
| `Header '{name}' value must be a string` | Header-Wert ist kein String. |
| `Cannot use both 'auth' and an 'Authorization' header. Use 'auth' for HTTP Basic Auth or 'headers' for Bearer/custom auth, not both.` | Sowohl ein `auth`-Objekt als auch ein benutzerdefinierter `Authorization`-Header wurden angegeben. |

### URL-Sicherheit (SSRF)

Jeder URL-basierte Endpunkt prüft die Ziel-`url`, bevor er sie abruft. Diese Meldungen werden als `400` zurückgegeben, wenn die URL keine öffentliche `http(s)`-Adresse ist.

| Meldung | Bedingung |
|---------|-----------|
| `Only http:// and https:// URLs are supported.` | Die URL verwendet ein anderes Schema als `http` oder `https`. |
| `URLs with embedded credentials are not allowed. Use the 'auth' field for HTTP Basic Auth.` | Die URL bettet einen Benutzernamen/ein Passwort ein (`https://user:pass@host/`). |
| `URL has no hostname.` | Die URL konnte nicht in einen Host geparst werden. |
| `This hostname is not allowed.` | Der Host ist `localhost` oder ein Cloud-Metadaten-Hostname. |
| `URLs resolving to private or internal addresses are not allowed.` | Die URL ist oder löst auf zu einer privaten, Loopback-, Link-Local-, reservierten oder anderweitig nicht-öffentlichen IP. |
| `Non-standard IP address notation is not allowed.` | Der Host verwendet oktale, hexadezimale oder gepackte Ganzzahl-IP-Notation, die mehrdeutig aufgelöst werden könnte. |
| `Could not resolve hostname '{hostname}'.` | Die DNS-Auflösung für den Host schlug fehl. |
| `This URL is blocked by the site's threat policy.` | Der Ziel-Host steht auf der Denylist der Threat-Policy, die zusammen mit der SSRF-Prüfung ausgewertet wird. |

### Validierung der Rendering-Optionen

| Meldung | Bedingung |
|---------|-----------|
| `'wait_for_selector' must be a string` | `wait_for_selector` war kein String. |
| `'wait_for_selector' is too long (max 1000 chars)` | Selektor überschreitet 1000 Zeichen. |
| `'wait_for_selector_timeout' must be a positive integer (ms)` | Timeout fehlt, ist null, negativ oder keine Ganzzahl. |
| `'wait_for_selector_timeout' must not exceed 60000 ms` | Timeout über der Obergrenze von 60 Sekunden. |
| `'block_ads' must be a boolean` / `'block_media' must be a boolean` | Blockierungs-Flag war kein Boolean. |

### Sitemap- und Crawl-Fehler

| Meldung | Bedingung |
|---------|-----------|
| `No URLs found in sitemap: {url}` | Sitemap geparst, enthält aber keine URLs. |
| `Timeout fetching sitemap: {url}` | Abruf der Sitemap überschritt das 30-Sekunden-Timeout. |
| `Could not fetch sitemap: {url} returned {status}` | Sitemap-URL gab einen HTTP-Status ungleich 200 zurück. |
| `Invalid XML in sitemap: {url}` | Sitemap-XML konnte nicht geparst werden. |
| `Unrecognized sitemap format at {url}: root element is <{tag}>` | Wurzelelement der Sitemap ist nicht `<urlset>` oder `<sitemapindex>`. |
| `No pages discovered on {base_url}` | Vollständiger Crawl abgeschlossen, aber keine Seiten gefunden. |

### Fehler beim Konvertierungsinhalt

| Meldung | Bedingung |
|---------|-----------|
| `Invalid JSON: {error}` | JSON-Datei enthält ungültige JSON-Syntax. |
| `Invalid YAML: {error}` | YAML-Datei enthält ungültige YAML-Syntax. |
| `Invalid TOML: {error}` | TOML-Datei enthält ungültige TOML-Syntax. |
| `Invalid HTML encoding (expected UTF-8)` | HTML-Datei ist nicht UTF-8-kodiert. |
| `Invalid Markdown encoding (expected UTF-8)` | Markdown-Datei ist nicht UTF-8-kodiert. |
| `JSON must be an array of objects for CSV conversion` | json-to-csv-Eingabe ist kein Array. |
| `JSON array is empty` | json-to-csv-Eingabe ist ein leeres Array. |
| `CSV file is empty or has no valid rows` | CSV-Datei hat keine Datenzeilen. |
| `XML structure cannot be converted to CSV` | XML ist nicht tabellarisch (xml-to-csv). |
| `Turnstile verification failed` | Cloudflare-Turnstile-Bot-Challenge fehlgeschlagen. |
| `Turnstile token required` | Widget-Request ohne Turnstile-Token. |

---

## 401 Unauthorized

Wird zurückgegeben, wenn die Authentifizierung fehlt oder ungültig ist.

| Meldung | Bedingung |
|---------|-----------|
| `Authentication required` | Kein API-Key und kein JWT-Token im Request angegeben. |
| `Invalid API Key format` | API-Key ist zu kurz oder beginnt nicht mit `sk_` oder `pk_`. |
| `Invalid API Key` | API-Key-Hash nicht in der Datenbank gefunden. |
| `API Key revoked` | API-Key wurde im Dashboard deaktiviert. |
| `Token has expired` | JWT-Access-Token ist abgelaufen (1-Stunden-Gültigkeit). |
| `Invalid token` | JWT ist fehlerhaft, manipuliert oder anderweitig ungültig. |
| `Refresh token has expired` | Refresh-Token ist abgelaufen (7-Tage-Gültigkeit). |
| `Invalid refresh token` | Refresh-Token ist fehlerhaft oder ungültig. |
| `Invalid token type` | Token erfolgreich dekodiert, ist aber nicht vom erwarteten Typ (refresh). |
| `No refresh token` | Widget-Refresh-Endpunkt ohne refresh_token-Cookie aufgerufen. |
| `Refresh token not found` | Das vorgelegte Refresh-Token ist zu keiner Session gespeichert. |
| `User not found or invalid` | Das Token wurde dekodiert, aber sein Subject löst nicht mehr zu einem nutzbaren Konto auf. |
| `Project not found` | Die Projekt-ID auf dem Key oder Token konnte bei der Prüfung des Ops-Kontingents nicht geparst werden. |

---

## 402 Payment Required

Wird zurückgegeben, wenn ein Nutzungslimit überschritten wird. Die Aufteilung zwischen `402` und `403` ist nicht symmetrisch, und sie führt regelmäßig in die Irre. **Jede Kontingent-Bedingung antwortet mit `402`**, ebenso ein V2-Endpunkt, der in deinem Plan abgeschaltet ist. **V1-Feature-Gates antworten mit `403`** (async, Webhooks, ZIP-Ausgabe, Basic Auth, Batch). Rate-Limiting ist ein separater Mechanismus und antwortet mit [`429`](#429-too-many-requests), nie mit `402`.

| Meldung | Bedingung |
|---------|-----------|
| `Monthly operations limit reached ({used}/{limit}). Upgrade your plan to continue.` | Der einheitliche monatliche Ops-Zähler hat das Kontingent des Plans erreicht. Founding-Plan: 500 Ops. Jeder Endpunkt schöpft aus diesem einen Zähler. In jedem kostenpflichtigen Plan mit aktivierter Überschreitung laufen Requests zu $0.02/Op weiter, statt zu scheitern. |
| `This request needs {units} operations but only {remaining} of your {limit} monthly operations remain. Upgrade your plan to continue.` | Batch-Request würde das verbleibende monatliche Ops-Kontingent überschreiten. Der gesamte Batch wird vorab abgelehnt. |
| `No active billing period found for this project. Contact support to restore your subscription.` | Das Projekt hat keinen Nutzungszeitraum, und aus seinem Abonnement konnte auch keiner bereitgestellt werden. Das Gate schließt im Zweifel, statt eine kostenlose Operation zu gewähren. |
| `Storage limit reached. Delete files or upgrade your storage plan to continue.` | Die Speichernutzung des Projekts hat die Speicherzuteilung des Plans erreicht. |
| `Active watcher limit reached ({active_count}/{limit}). Delete an existing watcher or upgrade your plan to add more.` | Das Projekt hält bereits die maximale Anzahl aktiver Watcher seines Plans. Watcher verbrauchen keine Ops; das ist eine Obergrenze dafür, wie viele gleichzeitig existieren. |
| `{Feature} is not available on your current plan. Upgrade to a V2-inclusive plan to access this endpoint.` | Ein V2-Endpunkt ist für den Plan deaktiviert. |

Aufgebrauchte monatliche AI-Credits erzeugen keinen `402`. Die Schema-Extraktion fällt auf das heuristische und CSS-basierte Ergebnis zurück, und der Request ist trotzdem erfolgreich. Kontingente, Preise und was als eine Operation zählt, stehen unter [Rate-Limits und Kontingente](/de/docs/reference/rate-limits.md).

---

## 403 Forbidden

Wird zurückgegeben, wenn der Zugriff aufgrund von Key-Typ, Domain, V1-Plan-Funktion oder Endpunkt-Beschränkungen verweigert wird. V2-Endpunkt-Gates sind die Ausnahme: Sie antworten mit [`402`](#402-payment-required), nicht mit `403`.

### Beschränkungen für API-Keys und Token

| Meldung | Bedingung |
|---------|-----------|
| `Private API keys cannot be used from browsers` | Ein Private-Key (`sk_...`) wurde in einem Request mit einem Browser-`Origin`-Header verwendet. Verwende stattdessen einen Public-Key mit JWT. |
| `Domain {origin} not authorized` | Der Request-Origin stimmt mit keiner Domain in der Liste der erlaubten Domains des API-Keys überein. |
| `Public API keys can only be used to generate JWT tokens or fetch widget branding. Please exchange your public key for a JWT token at /v1/auth/token, then use the token for API calls.` | Ein Public-Key wurde auf einem anderen Pfad als `/auth/token` oder `/auth/branding` verwendet. Tausche ihn zuerst gegen ein JWT ein. |
| `Endpoint '{path}' not allowed for this API key` | Die `allowed_endpoints`-Liste des API-Keys enthält nicht den angeforderten Pfad. |
| `Endpoint '{path}' not allowed for this token` | Die `allowed_endpoints`-Liste des JWT-Tokens enthält nicht den angeforderten Pfad. |
| `Token issued for different origin` | Der Request-Origin stimmt nicht mit dem im JWT erfassten Origin überein (verhindert Token-Diebstahl). |
| `Parent origin does not match token` | Der `X-Parent-Origin`-Header stimmt nicht mit dem überein, was bei der Token-Ausstellung validiert wurde. |

### Plan-Funktionsbeschränkungen

| Meldung | Bedingung |
|---------|-----------|
| `Async processing is not available on your current plan. Please upgrade to access this feature.` | `async_mode=true` bei einem Plan ohne async-Zugriff. |
| `Webhook callbacks is not available on your current plan. Please upgrade to access this feature.` | `callback_url` bei einem Plan ohne Webhook-Zugriff angegeben. |
| `ZIP output bundling is not available on your current plan. Please upgrade to access this feature.` | `output_format=true` bei einem Plan ohne ZIP-Ausgabe-Zugriff. |
| `Basic authentication, cookies & custom headers is not available on your current plan. Please upgrade to access this feature.` | `auth`, `cookies` oder `headers` bei einem Plan ohne Basic-Auth-Zugriff verwendet. |
| `Batch processing is not available on your current plan. Please upgrade to access this feature.` | Mehrere URLs bei einem Plan mit batch_limit von 0 eingereicht. |
| `Batch size {N} exceeds your plan's limit of {M} URLs per batch.` | Anzahl der URLs überschreitet das Batch-Größenlimit des Plans. |
| `Website crawling is not available on your current plan. Please upgrade to access this feature.` | Website-Capture-Endpunkt bei einem Plan mit crawl_mode "none" verwendet (Founding-Plan). |
| `Full website crawling requires a Studio plan or higher. Your plan supports sitemap-based crawling only.` | `crawl_mode=full` bei einem Indie-Plan angefordert, der nur Sitemap-basiertes Crawling unterstützt. |

### Widget-Beschränkungen

| Meldung | Bedingung |
|---------|-----------|
| `Widget API key has been revoked` | Der mit dem Widget verknüpfte interne API-Key wurde deaktiviert. |
| `Domain {origin} is not authorized for this widget` | Die einbettende Domain des Widgets ist nicht in der Liste der erlaubten Domains des Widgets. |
| `Refresh token does not match widget` | Die Projekt-ID des Refresh-Tokens stimmt nicht mit dem Projekt des Widgets überein. |
| `Batch status requires a private API key` | Public- oder Dashboard-Key versuchte, auf `GET /v1/convert/batch/{batch_id}` zuzugreifen. |
| `Access denied` | Versuch, auf eine Ressource (Job-Status, Datei) zuzugreifen, die zu einem anderen Projekt gehört. |

Zwei weitere `403`-Meldungen betreffen weder Keys noch Pläne: `Account suspended`, zurückgegeben für jeden Request, sobald das Konto hinter dem Key oder Token gesperrt ist, und `robots.txt disallows fetching this URL (request sent respect_robots=true).`, zurückgegeben von perceive, wenn du robots-Konformität angefordert hast und das Ziel den Pfad verbietet.

---

## 404 Not Found

| Meldung | Bedingung |
|---------|-----------|
| `Job not found` | Konvertierungs-Job-ID nicht in der Datenbank gefunden (Status-Polling). |
| `Batch not found` | Batch-ID hat keine passenden Aktivitätszeilen für dieses Projekt. |
| `File not found` | Angeforderte Datei existiert nicht im Speicher (Download-Endpunkt). |
| `Widget not found` | Widget-ID nicht gefunden oder Widget wurde deaktiviert. |
| `Operation not found`, `Ingest job not found`, `Watcher not found` | Eine V2-Ressourcen-ID, die nicht existiert oder zu einem anderen Projekt gehört. Existenz wird niemals projektübergreifend preisgegeben. |
| `Not Found` | Der Pfad ist keine Route der API. Prüfe den Pfad und das Versionspräfix. |

---

## 409 Conflict

| Meldung | Bedingung |
|---------|-----------|
| `job_id already in use` | Eine vom Client gelieferte `job_id` ist bereits von einem anderen Projekt belegt. Wähle eine andere ID oder lass die API eine erzeugen. |
| `A completion webhook is only delivered for completed jobs.` | Für einen Ingest-Job, der `completed` nicht erreicht hat, wurde ein Webhook-Retry angefordert. |

---

## 410 Gone

Das Artefakt existierte, hat aber das Aufbewahrungsfenster für Dateien deines Plans überschritten und liegt nicht mehr im Speicher. Die Aufbewahrung ist planabhängig; siehe [Rate-Limits und Kontingente](/de/docs/reference/rate-limits.md).

| Meldung | Bedingung |
|---------|-----------|
| `The artifact is no longer in storage (it may have passed your plan's file-retention window). Re-run the perceive request to regenerate it.` | Artefakt-Download über `GET /v2/perceive/{operation_id}`. |
| `The batch archive is no longer in storage (it may have passed your plan's file-retention window).` | ZIP-Download über `GET /v2/perceive/batch/{job_id}`. |

Behandle `410` für dieses Objekt als endgültig. Ein erneuter Lauf des Requests erzeugt ein frisches Artefakt; ein erneuter Download-Versuch nicht.

---

## 413 Payload Too Large

Wird zurückgegeben, wenn die hochgeladene Datei die maximale Dateigröße des Plans überschreitet.

<div class="alert alert-warning">
<strong>Verschachtelter Body:</strong> Das strukturierte Objekt ist der Wert von <code>detail</code>, kein Top-Level-Objekt. Lies <code>body.detail.max_size</code>.
</div>

```json
{
    "detail": {
        "error": "File too large",
        "file_size": 10485760,
        "max_size": 5242880,
        "tier": "free",
        "key_type": "private"
    }
}
```

| Feld | Beschreibung |
|-------|-------------|
| `error` | Immer `"File too large"`. |
| `file_size` | Die Größe der hochgeladenen Datei in Bytes. |
| `max_size` | Die maximal erlaubte Dateigröße für deinen Plan in Bytes. |
| `tier` | Der Slug deines Abonnements (z. B. `"free"`, `"starter"`, `"pro"`), mit Rückfall auf `"free"`, wenn kein Plan aufgelöst werden kann. Slugs sind stabile API-Bezeichner; die Anzeigenamen sind Founding (`free`), Indie (`starter`), Studio (`pro`) und Production (`business`). |
| `key_type` | Der Typ des verwendeten API-Keys: `"private"`, `"public"` oder `"unknown"`. |

Das Limit wird gegen die exakte Bytezahl des hochgeladenen Teils geprüft, bevor irgendeine Konvertierungsarbeit beginnt. Eine Datei, die exakt `max_size` groß ist, wird akzeptiert; nur eine größere Datei wird abgelehnt. Der `Content-Length`-Header ist ein Fallback für ältere Aufrufstellen, die ihr Upload-Objekt nicht an die Prüfung übergeben.

`POST /v2/ingest/files` verwendet diese Form nicht. Der Endpunkt antwortet mit `413` und einem einfachen String-`detail`: `File '{filename}' exceeds the {max_size}-byte limit.`

Die Obergrenzen pro Plan stehen unter [Rate-Limits und Kontingente](/de/docs/reference/rate-limits.md), und die Upload-Pfade, für die das gilt, stehen unter [Datei-Ingestion](/de/docs/guides/file-ingestion.md).

---

## Browser-Konvertierungsfehler (415 / 422 / 502 / 504) {: #browser-conversion-errors-415-422-502-504 }

URL-Konvertierungen unterscheiden einen Fehler in der **Zielseite oder der Eingabe** (ein `4xx`, `502` oder `504`, auf den du reagieren kannst) von einem Fehler in **unserer Engine** (ein `500`). Die drei V1-URL-Konvertierungs-Endpunkte (`url-to-pdf`, `url-to-screenshot`, `url-to-markdown`) geben diese typisierten Fehlschläge mit einem maschinenlesbaren `code` neben `detail` zurück:

```json
{
    "error": "Gateway Timeout",
    "code": "upstream_timeout",
    "detail": "The target site took too long to respond while rendering PDF for https://example.com."
}
```

| Code | `code`-Feld | Bedingung |
|------|--------------|-----------|
| `415` | `unsupported_content_type` | Das Ziel gab Inhalt zurück, den der Konverter nicht rendern kann, zum Beispiel `application/json` an `url-to-pdf` oder `url-to-screenshot`. Verwende `url-to-markdown` für JSON. |
| `422` | `selector_not_found` | Ein vom Aufrufer angegebener `wait_for_selector` erschien nie innerhalb von `wait_for_selector_timeout`. |
| `502` | `upstream_unreachable` | Die Zielseite konnte nicht erreicht werden (DNS- oder Verbindungsfehler). |
| `502` | `empty_render` | Die Navigation wurde abgeschlossen, aber die Seite erzeugte keinen erfassbaren Inhalt. |
| `504` | `upstream_timeout` | Die Zielseite brauchte zu lange, um zu antworten oder das Laden abzuschließen. |

Diese fünf sind das gesamte Vokabular. Keine andere Endpunkt-Familie gibt einen `code` aus, V2 eingeschlossen: Ein V2-Fehlschlag kommt als einfacher `detail`-String zurück. Die Basisklasse des Envelopes definiert einen sechsten Slug, `conversion_error`, aber nichts löst ihn aus, sodass er dich nie erreicht. Verzweige auf die obigen fünf und behandle jeden anderen Wert als unbekannt.

<div class="alert alert-info">
Ein `500` bedeutet jetzt, dass unsere Engine ausgefallen ist, sodass das Wiederholen eines identischen Requests wahrscheinlich nicht hilft. Ein `502`/`504` bedeutet, dass das <em>Ziel</em> sich fehlerhaft verhalten hat: wiederhole es oder prüfe die URL.
</div>

Ein `504` kann auch in zwei untypisierten Formen ankommen: `{"error": "Request timeout"}`, wenn der Request das 300-Sekunden-Budget des Gateways überdauert, und ein einfacher `detail`-String mit der Timeout-Meldung, wenn eine Dokumentkonvertierung (LibreOffice) in ein Timeout läuft. Keine der beiden trägt einen `code`.

---

## 422 Unprocessable Entity

Schema-Validierungsfehler geben zwei parallele Arrays zurück. `detail` ist die rohe Ausgabe des Validators und damit das, was du auf Formularfelder zurückmappst. `errors` ist ein menschenlesbarer String pro Problem und damit das, was du einem Nutzer anzeigst.

```json
{
    "detail": [
        {
            "loc": ["body", "max_pages"],
            "msg": "Input should be a valid integer, unable to parse string as an integer",
            "type": "int_parsing"
        }
    ],
    "errors": [
        "body.max_pages: Input should be a valid integer, unable to parse string as an integer (you sent 'ten')"
    ]
}
```

Drei `type`-Werte lohnt es sich, namentlich zu behandeln:

| `type` | Bedeutung |
|--------|-----------|
| `extra_forbidden` | Unbekanntes Feld. V2-Request-Schemata weisen unbekannte Schlüssel zurück, statt sie zu ignorieren. Ein falsch geschriebener Parameter ist also ein `422`, der das Feld benennt, und keine still verworfene Option. |
| `missing` | Ein Pflichtfeld wurde nicht gesendet. |
| `json_invalid` | Der Request-Body war kein gültiges JSON. |

<div class="alert alert-warning">
<strong>Eine Ausnahme:</strong> Die Validierung einzelner Einträge bei <code>POST /v2/perceive/batch</code> gibt einen <code>422</code> zurück, dessen <code>detail</code> eine reine Liste von <code>{"loc", "msg"}</code>-Objekten ist, ohne <code>type</code>-Schlüssel und ohne Top-Level-Array <code>errors</code>. Parser, die davon ausgehen, dass <code>errors</code> immer vorhanden ist, brechen dort.
</div>

Ein `422` mit dem Code `selector_not_found` ist etwas anderes: eine fehlgeschlagene Rendering-Vorbedingung, behandelt unter [Browser-Konvertierungsfehler](#browser-conversion-errors-415-422-502-504).

---

## 429 Too Many Requests

Rate-Limiting ist eine Fairness-Kontrolle über ein kurzes Zeitfenster und vom monatlichen Ops-Kontingent getrennt. Ein erschöpftes Kontingent antwortet mit [`402`](#402-payment-required); nur der Rate-Limiter antwortet mit `429`.

| Meldung | Bedingung |
|---------|-----------|
| `Rate limit exceeded. Please slow down and retry shortly.` | Ein Request-Rate-Fenster für das Projekt wurde überschritten. Die Buckets gelten pro Projekt und sind nach Key-Typ getrennt, sodass Public- und Private-Traffic sich keinen teilen. |

Ein `429` trägt vier Header:

| Header | Bedeutung |
|--------|-----------|
| `RateLimit-Limit` | Erlaubte Requests in dem Fenster, das ausgelöst wurde. |
| `RateLimit-Remaining` | Verbleibende Requests in diesem Fenster, bei einer Ablehnung `0`. |
| `RateLimit-Reset` | Sekunden, bis das Fenster zurückgesetzt wird. |
| `Retry-After` | Derselbe Wert wie `RateLimit-Reset`. Warte so lange, bevor du es erneut versuchst. |

Diese Header erscheinen nur beim `429`. Erfolgreiche Antworten tragen weder Rate-Limit-Header noch Header zu verbleibenden Ops. Du kannst dein Restbudget also nicht aus einer Antwort ablesen; prüfe die Nutzung im Dashboard. Siehe [Rate-Limits und Kontingente](/de/docs/reference/rate-limits.md).

---

## 500 Internal Server Error

| Meldung | Bedingung |
|---------|-----------|
| `Conversion failed: {error}` | Ein unerwarteter Fehler während einer Konvertierung per **Datei-Upload**. URL-Konvertierungen verwenden diese Meldung nicht: Sie treten als der typisierte Envelope oben oder als der generische Body unten zutage. |
| `Perception failed. Reference operation_id '{id}' when contacting support.` | Ein unerwarteter Fehler innerhalb eines `/v2/perceive`-Laufs. Die anderen V2-Endpunkte haben Entsprechungen, etwa `Distillation failed. Reference operation_id ...` und `Could not start ingest job. Reference job_id ...`. Nenne die ID, wenn du den Support kontaktierst. |

Alles, was außerhalb eines Konverters ausfällt, erreicht dich nie als Text. Es kommt ganz ohne `detail` zurück:

```json
{
    "error": "Internal server error",
    "event_id": "a1b2c3d4"
}
```

Ein Fall überrascht regelmäßig: Ein fehlerhafter JSON-Body an einen V1-URL-Endpunkt (`url-to-pdf`, `url-to-screenshot`, `url-to-markdown`, `website-to-pdf`, `website-to-screenshot`) gibt diesen `500` zurück statt eines `422`, weil diese Endpunkte den rohen Body lesen. Derselbe fehlerhafte Body an einem V2-Endpunkt gibt einen `422` mit `type: json_invalid` zurück.

Wenn du anhaltende 500-Fehler erlebst, liegt das Problem wahrscheinlich an der Eingabedatei oder URL. Versuche es mit einer anderen Eingabe, um das Problem einzugrenzen.

---

## 503 Service Unavailable

| Meldung | Bedingung |
|---------|-----------|
| `Converter not available: {endpoint}` | Der angeforderte Konverter ist nicht registriert oder läuft nicht. |
| `Converter not available` | Der URL-basierte Konverter für den angeforderten Endpunkt ist nicht verfügbar. |
| `The conversion service is at capacity. Please retry shortly.` | Der Browser-Rendering-Pool hat keinen freien Slot. Wird mit `Retry-After: 30` gesendet. |
| `Server is at capacity. Please retry shortly.` | Das CPU-Zulassungs-Gate für Konvertierungen ist voll: zu viele Dateikonvertierungen oder zu viele Bytes sind bereits in Arbeit. Wird mit `Retry-After: 10` gesendet. |
| `Search is temporarily unavailable. Please try again later.` | Der vorgelagerte Such-Provider hinter lookup ist nicht erreichbar oder falsch konfiguriert. |
| `Turnstile verification unavailable` | Der Cloudflare-Turnstile-Verifizierungsdienst ist nicht erreichbar. |

Es gibt zwei verschiedene Kapazitäts-Gates, und sie verlangen unterschiedliche Wartezeiten. Lies also `Retry-After`, statt eine Wartezeit anzunehmen. Ansonsten sind diese Fehler vorübergehend: wiederhole den Request nach kurzer Verzögerung.

---

## V2-Endpunkt-Fehler

Die [V2 Web-Intelligence-Endpunkte](/de/docs/concepts/v1-and-v2.md) verwenden die obigen Statuscodes erneut, mit einigen V2-spezifischen Bedingungen, die hervorzuheben sind.

### Quota und Plan (402 / 403)

V2-Operationen werden gegen dasselbe einheitliche monatliche Ops-Kontingent verrechnet wie V1-Konvertierungen: eine Op pro Arbeitseinheit. Jeder kostenpflichtige Plan mit aktivierter Überschreitung ($0.02/Op) erlaubt es, das Kontingent zu übersteigen; sonst ist die Grenze hart.

| Code | Bedingung |
|------|-----------|
| `402` | Das monatliche Ops-Kontingent ist erschöpft. Alle V2-Endpunkte ([perceive](/de/docs/endpoints/perceive.md), [discover](/de/docs/coming-soon/discover.md), [lookup](/de/docs/coming-soon/lookup.md), [distill](/de/docs/coming-soon/distill.md), [ingest](/de/docs/endpoints/ingest.md)) belasten diesen einen Zähler zusammen mit V1-Konvertierungen. |
| `402` | Das Limit aktiver Watcher (`max_watchers`) ist erreicht ([watch](/de/docs/coming-soon/watch.md)). Watcher sind ein separates Limit und verbrauchen nie Ops. |
| `402` | Der Endpunkt ist für den Plan abgeschaltet. V2-Gates antworten mit `402`, anders als V1-Feature-Gates, die mit `403` antworten. |
| `403` | Der Endpunkt ist nicht in der `allowed_endpoints`-Allowlist des API-Keys. |

Zwei V2-Verhalten sind bewusst keine Fehler. Ein aufgebrauchtes AI-Credit-Guthaben lässt den Request nicht scheitern: Die Schema-Extraktion fällt auf das heuristische und CSS-basierte Ergebnis zurück. Und ein [distill](/de/docs/coming-soon/distill.md)-Lauf über mehrere URLs, der mittendrin die Ops-Grenze überschreitet, gibt ebenfalls keinen `402`: Er stoppt dort, gibt die fertig verarbeiteten URLs zurück und hängt eine Warnung an, die nennt, wie viele übersprungen wurden.

### Validierung (422)

Jedes V2-Request-Schema weist unbekannte Schlüssel zurück, ein falsch geschriebener Parameter ist also ein `422`, der das Feld benennt. Die Body-Form ist unter [422 Unprocessable Entity](#422-unprocessable-entity) beschrieben.

| Endpunkt | Bedingung |
|----------|-----------|
| [perceive](/de/docs/endpoints/perceive.md) | `proxy_url`, `geolocation` oder `action_chain` wurde gesendet; diese Felder sind für ein späteres Release reserviert. |
| [distill](/de/docs/coming-soon/distill.md) | Weder `schema` noch `prompt` angegeben (beides zu senden ist in Ordnung, `schema` gewinnt); weder noch beide von `urls` und `discover_from` angegeben; ein ungültiges CSS-Feld, ein nicht unterstützter Feldtyp oder ein Regex, der katastrophales Backtracking riskiert. |
| [watch](/de/docs/coming-soon/watch.md) | `frequency_minutes` unter der stündlichen Untergrenze von 60 Minuten; ein leerer `PATCH`-Body. |
| [ingest](/de/docs/endpoints/ingest.md) | Der `mode` passt nicht zur Quelle (`urls`-Modus ohne `urls`, oder `sitemap`/`crawl` ohne Seed-`url`). |

### Such-Provider (502 / 503)

Der [lookup](/de/docs/coming-soon/lookup.md)-Endpunkt hängt von einem vorgelagerten Such-Provider ab. Roher Fehlertext des Providers erreicht den Client nie.

| Code | Meldung | Bedingung |
|------|---------|-----------|
| `502` | `The search provider returned an error. Please try again.` | Der Provider gab eine Fehlerantwort oder einen nicht wiederholbaren Transportfehler zurück. |
| `503` | `Search is temporarily unavailable. Please try again later.` | Der Provider ist falsch konfiguriert (fehlender Key) oder vorübergehend nicht erreichbar. Wiederhole es später. |

### Nicht gefunden (404)

`GET` und `DELETE` auf eine V2-`operation_id`, `job_id` oder `watcher_id`, die nicht existiert oder die zu einem anderen Projekt gehört, gibt `404` zurück. Existenz wird niemals projektübergreifend preisgegeben.

### Angenommen (202)

[Ingest](/de/docs/endpoints/ingest.md) ist immer asynchron: `POST /v2/ingest` antwortet mit `202` und einer `job_id`, die du abfragst. Perceive-Batches mit mehr als 10 URLs antworten mit `202` und Status `queued`. Ein Batch mit 10 oder weniger URLs antwortet normalerweise inline, aber wenn er das Inline-Fenster überschreitet, fällt er auf `202` mit Status `processing` und einer Warnung zurück. Behandle `202` also bei jeder Batch-Größe.

Ein `202` bedeutet außerdem, dass spätere Fehlschläge keine HTTP-Fehler sind. Frage den Job ab und lies seinen Status-Payload, wie unter [Sync- und async-Jobs](/de/docs/concepts/sync-and-async.md) beschrieben.

---

## Fehlerbehebung

### Authentifizierungsprobleme

- **Bekommst du 401?** Prüfe, ob dein API-Key gültig und im Dashboard aktiv ist. Bei Verwendung von JWT stelle sicher, dass das Token nicht abgelaufen ist (1-Stunden-Gültigkeit).
- **Bekommst du 403 zur Browser-Nutzung?** Du verwendest einen Private-Key (`sk_...`) aus clientseitigem Code. Wechsle für browserbasierte Requests zu einem Public-Key mit JWT.
- **Bekommst du 403 zur Domain?** Füge deine Domain im Dashboard zur Liste der erlaubten Domains des API-Keys hinzu.

### Konvertierungsprobleme

- **Bekommst du 400 zum Dateiformat?** Stelle sicher, dass die Erweiterung der hochgeladenen Datei zum Endpunkt passt (z. B. `.json` für json-to-xml, `.docx` für doc-to-pdf).
- **Bekommst du 413?** Deine Datei überschreitet das Größenlimit des Plans. Lies `detail.max_size` aus der Antwort und prüfe dann die maximale Dateigröße deines Plans oder führe ein Upgrade durch.
- **Bekommst du 402?** Du hast dein monatliches Ops-Kontingent, die Watcher-Obergrenze oder das Speicherlimit erreicht, oder das Projekt hat keinen aktiven Abrechnungszeitraum. Prüfe die Nutzung im Dashboard und siehe [Rate-Limits und Kontingente](/de/docs/reference/rate-limits.md).

### Probleme beim Funktionszugriff

- **Bekommst du 403 zu Plan-Funktionen?** Die V1-Funktion, die du verwenden möchtest (async, Batch, Webhooks, ZIP-Ausgabe, Basic Auth), erfordert eine höhere Plan-Stufe. Siehe die [Feature-Gating-Tabelle](/de/docs/reference/rate-limits.md#403-ein-batch-oder-v1-feature-das-dein-plan-nicht-hat).
- **Bekommst du 402 an einem V2-Endpunkt, ohne dass es um Kontingente geht?** V2-Endpunkt-Gates antworten mit `402`, nicht mit `403`. Die Meldung lautet `... is not available on your current plan. Upgrade to a V2-inclusive plan to access this endpoint.`

## Häufig gestellte Fragen

### Warum gibt die API bei einer Dateikonvertierung 402 Payment Required zurück?

Ein `402` bedeutet, dass ein Nutzungslimit ausgeschöpft ist: dein einheitliches monatliches Ops-Kontingent (500 Ops im Founding-Plan), die Obergrenze für aktive Watcher oder die Speicherzuteilung deines Projekts. Er deckt außerdem zwei Fälle ab, die nichts mit Kontingenten zu tun haben: ein Projekt ohne aktiven Abrechnungszeitraum und ein V2-Endpunkt, der in deinem Plan abgeschaltet ist. Batch-Requests, die das verbleibende monatliche Ops-Kontingent überschreiten würden, werden vorab mit einem `402` für den gesamten Batch abgelehnt. V1-Konvertierungen und V2-Operationen schöpfen aus demselben Kontingent; jeder kostenpflichtige Plan mit aktivierter Überschreitung ($0.02/Op) erlaubt es, darüber hinauszugehen. Rate-Limiting ist ein anderer Mechanismus und antwortet mit `429`.

### Wie behebe ich einen 401-Unauthorized-Fehler der Konvertierungs-API?

Prüfe, ob der API-Key vorhanden ist, mit `sk_` oder `pk_` beginnt und im Dashboard noch aktiv ist, denn widerrufene Keys geben `API Key revoked` zurück. Wenn du dich mit einem JWT authentifizierst, beachte, dass Access-Tokens nach 1 Stunde ablaufen (`Token has expired`) und Refresh-Tokens nach 7 Tagen.

### Warum bekomme ich beim Hochladen einer Datei 413 Payload Too Large?

Die hochgeladene Datei überschreitet die maximale Dateigröße deines Plans, gemessen an der exakten Bytezahl des hochgeladenen Teils, bevor irgendeine Konvertierungsarbeit beginnt. Eine Datei exakt am Limit wird akzeptiert. Der `413`-Body verschachtelt ein strukturiertes Objekt unter `detail`, mit `file_size`, `max_size` (beide in Bytes), `tier` und `key_type`. Lies es also als `detail.max_size` und nicht als Top-Level-Feld.

### Kann ich einen privaten API-Key aus Browser-JavaScript verwenden?

Nein. Ein Private-Key (`sk_...`), der in einem Request mit einem Browser-`Origin`-Header verwendet wird, gibt `403 Private API keys cannot be used from browsers` zurück. Tausche einen Public-Key unter `/v1/auth/token` gegen ein JWT ein und verwende dieses Token für browserbasierte API-Aufrufe.

### Ist ein 503-Service-Unavailable-Fehler der API dauerhaft?

Nein, `503`-Fehler wie `Converter not available: {endpoint}` oder `Turnstile verification unavailable` sind in der Regel vorübergehend. Wiederhole den Request nach kurzer Verzögerung.
