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 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.
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#
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.
{
"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.
{
"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.
4. Typisierter Konvertierungs-Envelope. {"error", "code", "detail"}, mit einem maschinenlesbaren code. Wird nur von den drei V1-URL-Konvertierungs-Endpunkten ausgegeben. Siehe Browser-Konvertierungsfehler.
5. Unbehandelte Exception. Ein 500, der nicht von einem Konverter stammt, hat überhaupt kein detail:
{
"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:
{
"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, 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.
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, 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.
| 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.
detail, kein Top-Level-Objekt. Lies body.detail.max_size.
{
"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, und die Upload-Pfade, für die das gilt, stehen unter Datei-Ingestion.
Browser-Konvertierungsfehler (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:
{
"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.
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.
{
"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. |
POST /v2/perceive/batch gibt einen 422 zurück, dessen detail eine reine Liste von {"loc", "msg"}-Objekten ist, ohne type-Schlüssel und ohne Top-Level-Array errors. Parser, die davon ausgehen, dass errors immer vorhanden ist, brechen dort.
Ein 422 mit dem Code selector_not_found ist etwas anderes: eine fehlgeschlagene Rendering-Vorbedingung, behandelt unter Browser-Konvertierungsfehler.
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; 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.
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:
{
"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 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, discover, lookup, distill, ingest) belasten diesen einen Zähler zusammen mit V1-Konvertierungen. |
402 |
Das Limit aktiver Watcher (max_watchers) ist erreicht (watch). 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-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 beschrieben.
| Endpunkt | Bedingung |
|---|---|
| perceive | proxy_url, geolocation oder action_chain wurde gesendet; diese Felder sind für ein späteres Release reserviert. |
| distill | 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 | frequency_minutes unter der stündlichen Untergrenze von 60 Minuten; ein leerer PATCH-Body. |
| ingest | Der mode passt nicht zur Quelle (urls-Modus ohne urls, oder sitemap/crawl ohne Seed-url). |
Such-Provider (502 / 503)#
Der lookup-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 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 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.
.jsonfür json-to-xml,.docxfür doc-to-pdf). - Bekommst du 413? Deine Datei überschreitet das Größenlimit des Plans. Lies
detail.max_sizeaus 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.
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.
- Bekommst du 402 an einem V2-Endpunkt, ohne dass es um Kontingente geht? V2-Endpunkt-Gates antworten mit
402, nicht mit403. 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.