Codes d'erreur de l'API EnConvert#
Cette référence répertorie tous les codes de statut HTTP et messages d'erreur renvoyés par l'API EnConvert, de 200 OK pour les conversions synchrones et 202 Accepted pour les tâches async et batch, jusqu'aux réponses d'erreur documentées ci-dessous. Chaque section d'erreur liste les chaînes de message exactes, la condition qui déclenche chacune d'elles, et comment corriger la requête. Les corps d'erreur n'ont pas tous la même forme : il en existe six, et la section Format des réponses d'erreur les présente toutes.
Une tâche qui échoue après avoir été acceptée n'est pas une erreur HTTP. Le 202 reste valable et l'échec apparaît dans la charge utile de statut de la tâche lorsque vous l'interrogez, comme décrit dans Tâches synchrones et asynchrones.
Codes de statut HTTP#
| Code | Statut | Description |
|---|---|---|
200 |
OK | Conversion terminée avec succès (mode synchrone). |
202 |
Accepted | La tâche en lot ou asynchrone a été acceptée pour un traitement en arrière-plan. |
400 |
Bad Request | Paramètres invalides, champs obligatoires manquants, corps de requête mal formé ou contenu de fichier invalide. |
401 |
Unauthorized | Clé API ou jeton JWT manquant, invalide ou expiré. |
402 |
Payment Required | Quota mensuel d'ops épuisé, aucune période de facturation active, plafond de watchers atteint, limite de stockage atteinte, ou endpoint V2 désactivé sur votre plan. |
403 |
Forbidden | Restriction de type de clé, de domaine ou de liste d'endpoints autorisés, restriction de fonctionnalité V1 (async, webhooks, sortie ZIP, authentification de base, lot), ou accès à la ressource d'un autre projet. |
404 |
Not Found | La ressource demandée (tâche, lot, opération, fichier, watcher ou widget) n'existe pas, ou le chemin n'est pas une route. |
405 |
Method Not Allowed | Le chemin existe, mais pas pour la méthode HTTP que vous avez utilisée. |
409 |
Conflict | Un job_id fourni par le client est déjà utilisé, ou une nouvelle tentative de webhook a été demandée sur une tâche d'ingestion non terminée. |
410 |
Gone | Un artefact V2 ou une archive de lot a dépassé la fenêtre de rétention de fichiers de votre plan et n'est plus dans le stockage. |
413 |
Payload Too Large | Le fichier téléversé dépasse la limite de taille de votre plan d'abonnement. |
415 |
Unsupported Media Type | L'URL cible a renvoyé un contenu que ce convertisseur ne peut pas rendre (par ex. du JSON vers url-to-pdf). |
422 |
Unprocessable Entity | Le corps de la requête a échoué à la validation de schéma (y compris des champs inconnus sur les endpoints V2), ou une précondition de rendu a échoué, par exemple un wait_for_selector qui n'est jamais apparu. |
429 |
Too Many Requests | Une limite de débit de requêtes sur courte fenêtre a été déclenchée. Ce n'est pas le code de quota : l'épuisement du quota mensuel répond 402. |
500 |
Internal Server Error | Erreur inattendue pendant la conversion (notre moteur a rencontré une défaillance). |
502 |
Bad Gateway | Le site cible n'a pas pu être atteint, un fournisseur en amont a échoué, ou la cible a renvoyé un défi anti-bot sans contenu de page (/v2/perceive, sauf si allow_degraded est défini). |
503 |
Service Unavailable | Un convertisseur est indisponible, le pool de rendu ou le portillon d'admission des conversions est saturé, ou une dépendance en amont est en panne. |
504 |
Gateway Timeout | Le site cible a mis trop de temps à répondre ou à terminer son chargement, ou la requête a dépassé le budget de 300 secondes de la passerelle. |
Format des réponses d'erreur#
Il existe six formes de corps. Celle que vous recevez dépend de l'endroit où la défaillance s'est produite, pas du seul code de statut : vérifiez le type de detail avant de le lire.
1. detail sous forme de chaîne. Le cas courant, et la seule forme que voient la plupart des intégrations.
{
"detail": "Authentication required"
}
2. detail sous forme d'objet. Le 413 de taille de fichier lié au plan. L'objet structuré est la valeur de detail : lisez body.detail.max_size, pas body.max_size. Voir 413 Payload Too Large.
{
"detail": {
"error": "File too large",
"file_size": 10485760,
"max_size": 5242880,
"tier": "free",
"key_type": "private"
}
}
3. detail sous forme de tableau, plus errors. La validation de schéma (422) renvoie les deux : detail est la sortie brute du validateur, errors est un tableau parallèle de chaînes lisibles par un humain. Voir 422 Unprocessable Entity.
4. Enveloppe de conversion typée. {"error", "code", "detail"}, avec un code lisible par une machine. Émise uniquement par les trois endpoints de conversion d'URL V1. Voir Erreurs de conversion navigateur.
5. Exception non gérée. Un 500 qui ne provient pas d'un convertisseur n'a aucun detail :
{
"error": "Internal server error",
"event_id": "a1b2c3d4"
}
6. Délai de requête de la passerelle. Le budget propre de 300 secondes de la passerelle produit un 504 sans detail ni code :
{
"error": "Request timeout"
}
400 Bad Request#
Renvoyé lorsque la requête contient des paramètres invalides, des champs manquants ou des données mal formées.
Validation des entrées#
| Message | Condition |
|---|---|
'url' must be provided |
Champ url manquant ou vide sur les endpoints basés sur une URL. |
Invalid file format '{ext}' for {endpoint}. Allowed: {list} |
L'extension du fichier téléversé ne correspond pas aux formats acceptés par l'endpoint. |
File content does not match the '{endpoint}' input type. |
L'extension a été acceptée, mais les octets magiques du fichier correspondent à un autre format. |
Invalid pdf_options: {error} |
JSON mal formé dans le champ de formulaire pdf_options. |
Validation du lot et du mode#
| Message | Condition |
|---|---|
Public keys only support a single URL input |
Une clé publique/de tableau de bord a tenté d'envoyer plusieurs URL. |
output_format=True requires multiple URLs |
Regroupement ZIP demandé avec une seule URL. |
direct_download not supported for multiple URLs |
direct_download=true avec un tableau d'URL. |
direct_download only works in sync mode |
direct_download=true combiné avec async_mode=true. |
Validation de l'authentification, des cookies et des en-têtes#
| Message | Condition |
|---|---|
'auth' must be an object with 'username' and 'password' |
Le paramètre auth a une structure incorrecte. |
'cookies' must be an array of cookie objects |
cookies n'est pas un tableau. |
'cookies' array must not exceed 50 entries |
Plus de 50 cookies fournis. |
Cookie at index {i} must be an object |
L'entrée de cookie n'est pas un dictionnaire. |
Cookie at index {i} must have 'name' and 'value' |
Champs obligatoires manquants dans le cookie. |
Cookie at index {i} must have 'domain' or 'url' |
Le cookie est dépourvu à la fois de domain et de url. |
'headers' must be an object of header name/value pairs |
headers n'est pas un dictionnaire. |
'headers' must not exceed 20 entries |
Plus de 20 en-têtes personnalisés. |
Header '{name}' cannot be overridden |
Tentative de définir un en-tête bloqué. L'ensemble bloqué est host, content-length, transfer-encoding, connection, upgrade, te, trailer. |
Header '{name}' value must be a string |
La valeur de l'en-tête n'est pas une chaîne de caractères. |
Cannot use both 'auth' and an 'Authorization' header. Use 'auth' for HTTP Basic Auth or 'headers' for Bearer/custom auth, not both. |
L'objet auth et l'en-tête personnalisé Authorization ont tous deux été fournis. |
Sécurité des URL (SSRF)#
Chaque endpoint basé sur une URL examine l'url cible avant de la récupérer. Ces messages sont renvoyés en 400 lorsque l'URL n'est pas une adresse publique http(s).
| Message | Condition |
|---|---|
Only http:// and https:// URLs are supported. |
L'URL utilise un schéma autre que http ou https. |
URLs with embedded credentials are not allowed. Use the 'auth' field for HTTP Basic Auth. |
L'URL intègre un nom d'utilisateur/mot de passe (https://user:pass@host/). |
URL has no hostname. |
L'URL n'a pas pu être analysée en un hôte. |
This hostname is not allowed. |
L'hôte est localhost ou un nom d'hôte de métadonnées cloud. |
URLs resolving to private or internal addresses are not allowed. |
L'URL est, ou se résout vers, une IP privée, de bouclage, link-local, réservée ou autrement non publique. |
Non-standard IP address notation is not allowed. |
L'hôte utilise une notation IP octale, hexadécimale ou entier compact susceptible de se résoudre de manière ambiguë. |
Could not resolve hostname '{hostname}'. |
La résolution DNS de l'hôte a échoué. |
This URL is blocked by the site's threat policy. |
L'hôte cible figure sur la liste de blocage de la politique de menaces, vérifiée en même temps que le filtre SSRF. |
Validation des options de rendu#
| Message | Condition |
|---|---|
'wait_for_selector' must be a string |
wait_for_selector n'était pas une chaîne de caractères. |
'wait_for_selector' is too long (max 1000 chars) |
Le sélecteur dépasse 1000 caractères. |
'wait_for_selector_timeout' must be a positive integer (ms) |
Le délai est manquant, nul, négatif ou n'est pas un entier. |
'wait_for_selector_timeout' must not exceed 60000 ms |
Le délai dépasse le plafond de 60 secondes. |
'block_ads' must be a boolean / 'block_media' must be a boolean |
L'indicateur de blocage n'était pas un booléen. |
Erreurs de sitemap et de crawl#
| Message | Condition |
|---|---|
No URLs found in sitemap: {url} |
Le sitemap a été analysé mais ne contient aucune URL. |
Timeout fetching sitemap: {url} |
La récupération du sitemap a dépassé le délai de 30 secondes. |
Could not fetch sitemap: {url} returned {status} |
L'URL du sitemap a renvoyé un statut HTTP différent de 200. |
Invalid XML in sitemap: {url} |
Le XML du sitemap n'a pas pu être analysé. |
Unrecognized sitemap format at {url}: root element is <{tag}> |
L'élément racine du sitemap n'est ni <urlset> ni <sitemapindex>. |
No pages discovered on {base_url} |
Le crawl complet s'est terminé mais aucune page n'a été trouvée. |
Erreurs de contenu de conversion#
| Message | Condition |
|---|---|
Invalid JSON: {error} |
Le fichier JSON contient une syntaxe JSON invalide. |
Invalid YAML: {error} |
Le fichier YAML contient une syntaxe YAML invalide. |
Invalid TOML: {error} |
Le fichier TOML contient une syntaxe TOML invalide. |
Invalid HTML encoding (expected UTF-8) |
Le fichier HTML n'est pas encodé en UTF-8. |
Invalid Markdown encoding (expected UTF-8) |
Le fichier Markdown n'est pas encodé en UTF-8. |
JSON must be an array of objects for CSV conversion |
L'entrée json-to-csv n'est pas un tableau. |
JSON array is empty |
L'entrée json-to-csv est un tableau vide. |
CSV file is empty or has no valid rows |
Le fichier CSV n'a aucune ligne de données. |
XML structure cannot be converted to CSV |
Le XML n'est pas tabulaire (xml-to-csv). |
Turnstile verification failed |
Le défi anti-bot Cloudflare Turnstile a échoué. |
Turnstile token required |
Requête de widget sans jeton Turnstile. |
401 Unauthorized#
Renvoyé lorsque l'authentification est manquante ou invalide.
| Message | Condition |
|---|---|
Authentication required |
Aucune clé API ni jeton JWT fourni dans la requête. |
Invalid API Key format |
La clé API est trop courte ou ne commence pas par sk_ ou pk_. |
Invalid API Key |
Le hachage de la clé API est introuvable dans la base de données. |
API Key revoked |
La clé API a été désactivée depuis le tableau de bord. |
Token has expired |
Le jeton d'accès JWT a expiré (durée de vie d'1 heure). |
Invalid token |
Le JWT est mal formé, altéré ou invalide d'une autre manière. |
Refresh token has expired |
Le jeton de rafraîchissement a expiré (durée de vie de 7 jours). |
Invalid refresh token |
Le jeton de rafraîchissement est mal formé ou invalide. |
Invalid token type |
Le jeton a été décodé avec succès mais n'est pas du type attendu (refresh). |
No refresh token |
L'endpoint de rafraîchissement du widget a été appelé sans cookie refresh_token. |
Refresh token not found |
Le jeton de rafraîchissement présenté n'est stocké pour aucune session. |
User not found or invalid |
Le jeton a été décodé mais son sujet ne correspond plus à un compte utilisable. |
Project not found |
L'identifiant de projet porté par la clé ou le jeton n'a pas pu être analysé lors de la vérification du quota d'ops. |
402 Payment Required#
Renvoyé lorsqu'une limite d'utilisation est dépassée. La répartition entre 402 et 403 n'est pas symétrique, et elle prend souvent les développeurs de court. Toute condition de quota répond 402, tout comme un endpoint V2 désactivé sur votre plan. Les restrictions de fonctionnalités V1 répondent 403 (async, webhooks, sortie ZIP, authentification de base, lot). La limitation de débit est un mécanisme distinct qui répond 429, jamais 402.
| Message | Condition |
|---|---|
Monthly operations limit reached ({used}/{limit}). Upgrade your plan to continue. |
Le compteur mensuel unifié d'ops a atteint l'allocation du plan. Plan Founding : 500 ops. Chaque endpoint puise dans ce compteur unique. Sur n'importe quel plan payant avec dépassement activé, les requêtes continuent à $0.02/op au lieu d'échouer. |
This request needs {units} operations but only {remaining} of your {limit} monthly operations remain. Upgrade your plan to continue. |
La requête en lot dépasserait le quota mensuel d'ops restant. L'intégralité du lot est rejetée d'emblée. |
No active billing period found for this project. Contact support to restore your subscription. |
Le projet n'a aucune période d'utilisation et aucune n'a pu être provisionnée depuis son abonnement. Le contrôle échoue en mode fermé plutôt que d'accorder une opération gratuite. |
Storage limit reached. Delete files or upgrade your storage plan to continue. |
L'utilisation du stockage du projet a atteint l'allocation de stockage du plan. |
Active watcher limit reached ({active_count}/{limit}). Delete an existing watcher or upgrade your plan to add more. |
Le projet détient déjà le nombre maximal de watchers actifs de son plan. Les watchers ne consomment pas d'ops ; il s'agit d'un plafond sur le nombre existant simultanément. |
{Feature} is not available on your current plan. Upgrade to a V2-inclusive plan to access this endpoint. |
Un endpoint V2 est désactivé pour le plan. |
L'épuisement des crédits IA mensuels ne produit pas de 402. L'extraction de schéma se rabat sur le résultat heuristique et CSS, et la requête aboutit quand même. Les allocations, les tarifs et ce qui compte pour une opération figurent dans Limites de débit et quotas.
403 Forbidden#
Renvoyé lorsque l'accès est refusé en raison de restrictions liées au type de clé, au domaine, à une fonctionnalité de plan V1 ou à l'endpoint. Les restrictions d'endpoints V2 font exception : elles répondent 402, pas 403.
Restrictions de clé API et de jeton#
| Message | Condition |
|---|---|
Private API keys cannot be used from browsers |
Une clé privée (sk_...) a été utilisée dans une requête comportant un en-tête Origin de navigateur. Utilisez plutôt une clé publique avec JWT. |
Domain {origin} not authorized |
L'origine de la requête ne correspond à aucun domaine de la liste des domaines autorisés de la clé API. |
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. |
Une clé publique a été utilisée sur un chemin autre que /auth/token ou /auth/branding. Échangez-la d'abord contre un JWT. |
Endpoint '{path}' not allowed for this API key |
La liste allowed_endpoints de la clé API n'inclut pas le chemin demandé. |
Endpoint '{path}' not allowed for this token |
La liste allowed_endpoints du jeton JWT n'inclut pas le chemin demandé. |
Token issued for different origin |
L'origine de la requête ne correspond pas à l'origine enregistrée dans le JWT (empêche le vol de jeton). |
Parent origin does not match token |
L'en-tête X-Parent-Origin ne correspond pas à ce qui a été validé lors de l'émission du jeton. |
Restrictions de fonctionnalités du plan#
| Message | Condition |
|---|---|
Async processing is not available on your current plan. Please upgrade to access this feature. |
async_mode=true sur un plan sans accès asynchrone. |
Webhook callbacks is not available on your current plan. Please upgrade to access this feature. |
callback_url fourni sur un plan sans accès aux webhooks. |
ZIP output bundling is not available on your current plan. Please upgrade to access this feature. |
output_format=true sur un plan sans accès à la sortie ZIP. |
Basic authentication, cookies & custom headers is not available on your current plan. Please upgrade to access this feature. |
auth, cookies ou headers utilisés sur un plan sans accès à l'authentification de base. |
Batch processing is not available on your current plan. Please upgrade to access this feature. |
Plusieurs URL soumises sur un plan avec un batch_limit de 0. |
Batch size {N} exceeds your plan's limit of {M} URLs per batch. |
Le nombre d'URL dépasse la limite de taille de lot du plan. |
Website crawling is not available on your current plan. Please upgrade to access this feature. |
Endpoint de capture de site web utilisé sur un plan avec un crawl_mode "none" (plan Founding). |
Full website crawling requires a Studio plan or higher. Your plan supports sitemap-based crawling only. |
crawl_mode=full demandé sur un plan Indie qui ne prend en charge que le crawl basé sur le sitemap. |
Restrictions de widget#
| Message | Condition |
|---|---|
Widget API key has been revoked |
La clé API interne liée au widget a été désactivée. |
Domain {origin} is not authorized for this widget |
Le domaine d'intégration du widget ne figure pas dans la liste des domaines autorisés du widget. |
Refresh token does not match widget |
L'ID de projet du jeton de rafraîchissement ne correspond pas au projet du widget. |
Batch status requires a private API key |
Une clé publique ou de tableau de bord a tenté d'accéder à GET /v1/convert/batch/{batch_id}. |
Access denied |
Tentative d'accès à une ressource (statut de tâche, fichier) appartenant à un autre projet. |
Deux autres messages 403 ne concernent ni les clés ni les plans : Account suspended, renvoyé pour chaque requête dès que le compte derrière la clé ou le jeton est suspendu, et robots.txt disallows fetching this URL (request sent respect_robots=true)., renvoyé par perceive lorsque vous avez demandé le respect de robots et que la cible interdit ce chemin.
404 Not Found#
| Message | Condition |
|---|---|
Job not found |
ID de tâche de conversion introuvable dans la base de données (interrogation du statut). |
Batch not found |
L'ID de lot n'a aucune ligne d'activité correspondante pour ce projet. |
File not found |
Le fichier demandé n'existe pas dans le stockage (endpoint de téléchargement). |
Widget not found |
ID de widget introuvable ou widget désactivé. |
Operation not found, Ingest job not found, Watcher not found |
Un identifiant de ressource V2 qui n'existe pas, ou qui appartient à un autre projet. L'existence n'est jamais divulguée entre projets. |
Not Found |
Le chemin n'est pas une route de l'API. Vérifiez le chemin et le préfixe de version. |
409 Conflict#
| Message | Condition |
|---|---|
job_id already in use |
Un job_id fourni par le client est déjà revendiqué par un autre projet. Choisissez un autre identifiant, ou laissez l'API en générer un. |
A completion webhook is only delivered for completed jobs. |
Une nouvelle tentative de webhook a été demandée pour une tâche d'ingestion qui n'a pas atteint l'état completed. |
410 Gone#
L'artefact a existé, mais il a dépassé la fenêtre de rétention de fichiers de votre plan et n'est plus dans le stockage. La rétention dépend du plan ; voir Limites de débit et quotas.
| Message | Condition |
|---|---|
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. |
Téléchargement d'artefact sur GET /v2/perceive/{operation_id}. |
The batch archive is no longer in storage (it may have passed your plan's file-retention window). |
Téléchargement ZIP sur GET /v2/perceive/batch/{job_id}. |
Considérez 410 comme définitif pour cet objet. Relancer la requête produit un nouvel artefact ; réessayer le téléchargement n'y changera rien.
413 Payload Too Large#
Renvoyé lorsque le fichier téléversé dépasse la taille de fichier maximale du plan.
detail, pas un objet de premier niveau. Lisez body.detail.max_size.
{
"detail": {
"error": "File too large",
"file_size": 10485760,
"max_size": 5242880,
"tier": "free",
"key_type": "private"
}
}
| Champ | Description |
|---|---|
error |
Toujours "File too large". |
file_size |
La taille du fichier téléversé en octets. |
max_size |
La taille de fichier maximale autorisée pour votre plan, en octets. |
tier |
Le slug de votre plan d'abonnement (par ex. "free", "starter", "pro"), avec repli sur "free" lorsqu'aucun plan n'est résolu. Les slugs sont des identifiants API stables ; les noms commerciaux sont Founding (free), Indie (starter), Studio (pro) et Production (business). |
key_type |
Le type de clé API utilisé : "private", "public" ou "unknown". |
La limite est vérifiée sur le nombre exact d'octets de la partie téléversée, avant tout début de travail de conversion. Un fichier dont la taille vaut exactement max_size est accepté ; seul un fichier plus grand est rejeté. L'en-tête Content-Length sert de repli pour les anciens points d'appel qui ne transmettent pas leur objet d'upload à la vérification.
POST /v2/ingest/files n'utilise pas cette forme. Il répond 413 avec un detail sous forme de simple chaîne : File '{filename}' exceeds the {max_size}-byte limit.
Les plafonds par plan sont listés dans Limites de débit et quotas, et les chemins d'upload concernés dans Ingestion de fichiers.
Erreurs de conversion navigateur (415 / 422 / 502 / 504)#
Les conversions d'URL distinguent une défaillance du site cible ou de l'entrée (un 4xx, 502 ou 504 sur lequel vous pouvez agir) d'une défaillance de notre moteur (un 500). Les trois endpoints de conversion d'URL V1 (url-to-pdf, url-to-screenshot, url-to-markdown) renvoient ces échecs typés avec un code lisible par une machine à côté de detail :
{
"error": "Gateway Timeout",
"code": "upstream_timeout",
"detail": "The target site took too long to respond while rendering PDF for https://example.com."
}
| Code | champ code |
Condition |
|---|---|---|
415 |
unsupported_content_type |
La cible a renvoyé un contenu que le convertisseur ne peut pas rendre, par exemple application/json envoyé vers url-to-pdf ou url-to-screenshot. Utilisez url-to-markdown pour le JSON. |
422 |
selector_not_found |
Un wait_for_selector fourni par l'appelant n'est jamais apparu dans le délai wait_for_selector_timeout. |
502 |
upstream_unreachable |
Le site cible n'a pas pu être atteint (échec DNS ou de connexion). |
502 |
empty_render |
La navigation s'est terminée mais la page n'a produit aucun contenu capturable. |
504 |
upstream_timeout |
Le site cible a mis trop de temps à répondre ou à terminer son chargement. |
Ces cinq valeurs constituent tout le vocabulaire. Aucune autre famille d'endpoints n'émet de code, V2 comprise : un échec V2 revient sous forme de simple chaîne detail. La classe de base de l'enveloppe définit un sixième slug, conversion_error, mais rien ne le déclenche, donc il ne vous parvient jamais. Branchez votre code sur les cinq valeurs ci-dessus et traitez toute autre valeur comme inconnue.
Un 504 peut aussi arriver sous deux formes non typées : {"error": "Request timeout"} lorsque la requête dépasse le budget de 300 secondes de la passerelle, et un detail sous forme de simple chaîne portant le message de délai lorsqu'une conversion de document (LibreOffice) expire. Ni l'une ni l'autre ne porte de code.
422 Unprocessable Entity#
Les échecs de validation de schéma renvoient deux tableaux parallèles. detail est la sortie brute du validateur, c'est ce que vous remappez sur vos champs de formulaire. errors contient une chaîne lisible par un humain par problème, c'est ce que vous affichez à l'utilisateur.
{
"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')"
]
}
Trois valeurs de type méritent d'être traitées nommément :
type |
Signification |
|---|---|
extra_forbidden |
Champ inconnu. Les schémas de requête V2 rejettent les clés inconnues au lieu de les ignorer : un paramètre mal orthographié devient un 422 qui nomme le champ, plutôt qu'une option silencieusement abandonnée. |
missing |
Un champ obligatoire n'a pas été envoyé. |
json_invalid |
Le corps de la requête n'était pas du JSON valide. |
POST /v2/perceive/batch renvoie un 422 dont le detail est une simple liste d'objets {"loc", "msg"}, sans clé type ni tableau errors de premier niveau. Les analyseurs qui supposent que errors est toujours présent échoueront à cet endroit.
Un 422 accompagné du code selector_not_found est autre chose : une précondition de rendu qui a échoué, traitée dans Erreurs de conversion navigateur.
429 Too Many Requests#
La limitation de débit est un contrôle d'équité sur une courte fenêtre, distinct du quota mensuel d'ops. L'épuisement du quota répond 402 ; seul le limiteur de débit répond 429.
| Message | Condition |
|---|---|
Rate limit exceeded. Please slow down and retry shortly. |
Une fenêtre de débit de requêtes du projet a été dépassée. Les compteurs sont par projet et cloisonnés par type de clé : le trafic public et le trafic privé n'en partagent donc pas un seul. |
Un 429 porte quatre en-têtes :
| En-tête | Signification |
|---|---|
RateLimit-Limit |
Nombre de requêtes autorisées dans la fenêtre déclenchée. |
RateLimit-Remaining |
Requêtes restantes dans cette fenêtre, 0 en cas de rejet. |
RateLimit-Reset |
Nombre de secondes avant la réinitialisation de la fenêtre. |
Retry-After |
La même valeur que RateLimit-Reset. Attendez ce délai avant de réessayer. |
Ces en-têtes n'apparaissent que sur le 429. Les réponses réussies ne portent aucun en-tête de limite de débit ni d'ops restantes : vous ne pouvez donc pas lire votre budget restant sur une réponse, consultez votre utilisation dans le tableau de bord. Voir Limites de débit et quotas.
500 Internal Server Error#
| Message | Condition |
|---|---|
Conversion failed: {error} |
Une erreur inattendue pendant une conversion de fichier téléversé. Les conversions d'URL n'utilisent pas ce message : elles remontent via l'enveloppe typée ci-dessus, ou via le corps générique ci-dessous. |
Perception failed. Reference operation_id '{id}' when contacting support. |
Une défaillance inattendue au cours d'une exécution /v2/perceive. Les autres endpoints V2 ont leurs équivalents, comme Distillation failed. Reference operation_id ... et Could not start ingest job. Reference job_id .... Citez l'identifiant lorsque vous contactez le support. |
Toute défaillance survenant en dehors d'un convertisseur ne vous parvient jamais sous forme de texte. Elle revient sans aucun detail :
{
"error": "Internal server error",
"event_id": "a1b2c3d4"
}
Un cas surprend souvent : un corps JSON mal formé envoyé à un endpoint d'URL V1 (url-to-pdf, url-to-screenshot, url-to-markdown, website-to-pdf, website-to-screenshot) renvoie ce 500 plutôt qu'un 422, car ces endpoints lisent le corps brut. Le même corps mal formé sur un endpoint V2 renvoie un 422 avec type: json_invalid.
Si vous rencontrez des erreurs 500 persistantes, le problème vient probablement du fichier ou de l'URL d'entrée. Essayez avec une entrée différente pour isoler le problème.
503 Service Unavailable#
| Message | Condition |
|---|---|
Converter not available: {endpoint} |
Le convertisseur demandé n'est pas enregistré ou n'est pas en cours d'exécution. |
Converter not available |
Le convertisseur basé sur l'URL pour l'endpoint demandé n'est pas disponible. |
The conversion service is at capacity. Please retry shortly. |
Le pool de rendu navigateur n'a plus de créneau libre. Envoyé avec Retry-After: 30. |
Server is at capacity. Please retry shortly. |
Le portillon d'admission des conversions CPU est plein : trop de conversions de fichiers, ou trop d'octets, déjà en cours. Envoyé avec Retry-After: 10. |
Search is temporarily unavailable. Please try again later. |
Le fournisseur de recherche en amont derrière lookup est injoignable ou mal configuré. |
Turnstile verification unavailable |
Le service de vérification Cloudflare Turnstile est injoignable. |
Deux portillons de capacité distincts existent et ils demandent des attentes différentes : lisez Retry-After plutôt que d'en supposer une. Ces erreurs sont par ailleurs transitoires, réessayez après un court délai.
Erreurs des endpoints V2#
Les endpoints d'intelligence web V2 réutilisent les codes de statut ci-dessus, avec quelques conditions spécifiques à la V2 qui méritent d'être signalées.
Quota et plan (402 / 403)#
Les opérations V2 sont décomptées sur le même quota mensuel unifié d'ops que les conversions V1 : une op par unité de travail. N'importe quel plan payant avec dépassement activé ($0.02/op) permet d'aller au-delà de l'allocation ; sinon, la limite est stricte.
| Code | Condition |
|---|---|
402 |
Le quota mensuel d'ops est épuisé. Tous les endpoints V2 (perceive, discover, lookup, distill, ingest) facturent ce compteur unique aux côtés des conversions V1. |
402 |
La limite de watchers actifs (max_watchers) est atteinte (watch). Les watchers sont un plafond séparé et ne consomment jamais d'ops. |
402 |
L'endpoint est désactivé pour le plan. Les restrictions V2 répondent 402, contrairement aux restrictions de fonctionnalités V1, qui répondent 403. |
403 |
L'endpoint ne figure pas dans la liste d'autorisation allowed_endpoints de la clé API. |
Deux comportements V2 ne sont délibérément pas des erreurs. L'épuisement du solde de crédits IA ne fait pas échouer la requête : l'extraction de schéma se rabat sur le résultat heuristique et CSS. Et une exécution distill multi-URL qui franchit la limite d'ops en cours de route ne renvoie pas non plus de 402 : elle s'arrête là, renvoie les URL qu'elle a terminées et ajoute un avertissement indiquant combien ont été ignorées.
Validation (422)#
Chaque schéma de requête V2 rejette les clés inconnues : un paramètre mal orthographié devient un 422 qui nomme le champ. La forme du corps est décrite dans 422 Unprocessable Entity.
| Endpoint | Condition |
|---|---|
| perceive | proxy_url, geolocation ou action_chain a été envoyé ; ces champs sont réservés pour une version ultérieure. |
| distill | Ni schema ni prompt n'a été fourni (envoyer les deux est acceptable, schema l'emporte) ; aucun ou les deux de urls et discover_from fournis ; un champ CSS invalide, un type de champ non pris en charge ou une regex présentant un risque de backtracking catastrophique. |
| watch | frequency_minutes en dessous du plancher horaire de 60 minutes ; un corps PATCH vide. |
| ingest | Le mode ne correspond pas à la source (mode urls sans urls, ou sitemap/crawl sans url de départ). |
Fournisseur de recherche (502 / 503)#
L'endpoint lookup dépend d'un fournisseur de recherche en amont. Le texte d'erreur brut du fournisseur n'atteint jamais le client.
| Code | Message | Condition |
|---|---|---|
502 |
The search provider returned an error. Please try again. |
Le fournisseur a renvoyé une réponse d'erreur ou une panne de transport non réessayable. |
503 |
Search is temporarily unavailable. Please try again later. |
Le fournisseur est mal configuré (clé manquante) ou temporairement injoignable. Réessayez plus tard. |
Non trouvé (404)#
GET et DELETE sur un operation_id, job_id ou watcher_id V2 qui n'existe pas, ou qui appartient à un autre projet, renvoient 404. L'existence n'est jamais divulguée entre projets.
Accepté (202)#
Ingest est toujours asynchrone : POST /v2/ingest répond 202 avec un job_id que vous interrogez. Les lots perceive de plus de 10 URL répondent 202 avec le statut queued. Un lot de 10 URL ou moins répond normalement en ligne, mais s'il dépasse la fenêtre en ligne il bascule en 202 avec le statut processing et un avertissement : gérez donc 202 quelle que soit la taille du lot.
Un 202 signifie aussi que les échecs ultérieurs ne sont pas des erreurs HTTP. Interrogez la tâche et lisez sa charge utile de statut, comme décrit dans Tâches synchrones et asynchrones.
Dépannage#
Problèmes d'authentification#
- Vous obtenez un 401 ? Vérifiez que votre clé API est valide et active dans le tableau de bord. Si vous utilisez un JWT, assurez-vous que le jeton n'a pas expiré (durée de vie d'1 heure).
- Vous obtenez un 403 concernant l'utilisation depuis un navigateur ? Vous utilisez une clé privée (
sk_...) depuis du code côté client. Passez à une clé publique avec JWT pour les requêtes basées sur un navigateur. - Vous obtenez un 403 concernant le domaine ? Ajoutez votre domaine à la liste des domaines autorisés de la clé API dans le tableau de bord.
Problèmes de conversion#
- Vous obtenez un 400 concernant le format de fichier ? Assurez-vous que l'extension du fichier téléversé correspond à l'endpoint (par ex.
.jsonpour json-to-xml,.docxpour doc-to-pdf). - Vous obtenez un 413 ? Votre fichier dépasse la limite de taille du plan. Lisez
detail.max_sizedans la réponse, puis vérifiez la taille de fichier maximale de votre plan ou passez à un plan supérieur. - Vous obtenez un 402 ? Vous avez atteint votre quota mensuel d'ops, le plafond de watchers ou la limite de stockage, ou bien le projet n'a aucune période de facturation active. Vérifiez votre utilisation dans le tableau de bord et consultez Limites de débit et quotas.
Problèmes d'accès aux fonctionnalités#
- Vous obtenez un 403 concernant les fonctionnalités du plan ? La fonctionnalité V1 que vous essayez d'utiliser (async, lot, webhooks, sortie ZIP, authentification de base) nécessite un niveau de plan supérieur. Consultez le tableau de restriction des fonctionnalités.
- Vous obtenez un 402 sur un endpoint V2 qui n'a rien à voir avec le quota ? Les restrictions d'endpoints V2 répondent
402, pas403. Le message est... is not available on your current plan. Upgrade to a V2-inclusive plan to access this endpoint.
Questions fréquentes#
Pourquoi l'API renvoie-t-elle 402 Payment Required pour une conversion de fichier ?#
Une 402 signifie qu'une limite d'utilisation est épuisée : votre quota mensuel unifié d'ops (500 ops sur le plan Founding), le plafond de watchers actifs, ou l'allocation de stockage de votre projet. Elle couvre aussi deux cas hors quota : un projet sans période de facturation active, et un endpoint V2 désactivé sur votre plan. Les requêtes en lot qui dépasseraient le quota mensuel d'ops restant sont rejetées d'emblée avec une 402 pour le lot entier. Les conversions V1 et les opérations V2 puisent dans le même quota ; n'importe quel plan payant avec dépassement activé ($0.02/op) permet d'aller au-delà. La limitation de débit est un mécanisme différent et répond 429.
Comment corriger une erreur 401 Unauthorized de l'API de conversion ?#
Vérifiez que la clé API est présente, commence par sk_ ou pk_, et est toujours active dans le tableau de bord, car les clés révoquées renvoient API Key revoked. Si vous vous authentifiez avec un JWT, notez que les jetons d'accès expirent après 1 heure (Token has expired) et les jetons de rafraîchissement après 7 jours.
Pourquoi est-ce que j'obtiens 413 Payload Too Large lors de l'envoi d'un fichier ?#
Le fichier téléversé dépasse la taille de fichier maximale de votre plan, mesurée sur le nombre exact d'octets de la partie téléversée avant tout début de travail de conversion. Un fichier exactement à la limite est accepté. Le corps du 413 imbrique un objet structuré sous detail, avec file_size, max_size (tous deux en octets), tier et key_type : lisez-le donc comme detail.max_size et non comme un champ de premier niveau.
Puis-je utiliser une clé API privée depuis du JavaScript navigateur ?#
Non. Une clé privée (sk_...) utilisée dans une requête comportant un en-tête Origin de navigateur renvoie 403 Private API keys cannot be used from browsers. Échangez une clé publique contre un JWT sur /v1/auth/token et utilisez ce jeton pour les appels API depuis un navigateur.
Une erreur 503 Service Unavailable de l'API est-elle permanente ?#
Non, les erreurs 503 telles que Converter not available: {endpoint} ou Turnstile verification unavailable sont généralement transitoires. Réessayez la requête après un court délai.