Passer au contenu principal
Un appel peut échouer à deux endroits. La requête peut être rejetée immédiatement avec une erreur HTTP, ou bien être acceptée puis se terminer plus tard avec status: "failed". Les jobs en échec et annulés ne sont pas facturés. Vous ne payez que pour les jobs terminés. Dans une node app, le job propre à l’app n’est jamais facturé. Chaque nœud de génération ou de LLM est facturé lorsque son propre job se termine. Un échec n’annule pas les nœuds parallèles ni les autres branches : un nœud qui se termine après l’échec de l’app est donc lui aussi facturé, et ces frais ne sont pas remboursés. Un nœud qui échoue, est annulé ou ne démarre jamais n’est pas facturé. Consultez Clés API et facturation.

Erreurs au moment de la requête et jobs en échec

Les erreurs au moment de la requête renvoient un statut 4xx ou 5xx. Aucun job n’est créé. Lisez le corps de la réponse comme décrit ci-dessous. Les jobs en échec renvoient un statut de succès lors de la soumission. Interrogez GET /jobs/{id} ou attendez un webhook. Lorsque le job se termine, status vaut "failed" et l’échec est décrit dans l’objet error de premier niveau. Ne lisez pas result sur un job en échec : il est omis (ou null). Il ne contient la sortie que lorsque status vaut "completed". Un job cancelled n’a ni result ni error. Basez votre logique sur error.code. message peut être omis et, pour provider_error et internal, il s’agit d’un texte libre du fournisseur. N’analysez pas message.

Corps des réponses

Sur generate, jobs, assets, styles et node apps, lisez message ?? error lorsque le corps est en JSON. L’un de ces deux champs contient le résumé. Certains corps 5xx ne sont pas en JSON, notamment un 502 dont le corps est le texte brut error code: 502. Analysez la réponse de manière défensive : si le corps n’est pas en JSON, basez votre logique sur le statut HTTP. La plupart des échecs utilisent { "message": "..." }, parfois avec des champs supplémentaires (limit, jobType, modelAccessDenial). Le JSON invalide et quelques handlers ci-dessous utilisent plutôt { "error": "..." }. Les endpoints MCP tels que /mcp renvoient des erreurs JSON-RPC, { "jsonrpc", "id", "error": { "code", "message" } }, et non les corps HTTP décrits sur cette page.

Envoyez Accept: application/json

Sans Accept: application/json, certaines erreurs sont renvoyées sous forme de page HTML et un parseur JSON échouera.
Les erreurs { "message" }, y compris 401 et 404, sont en JSON lorsque Accept vaut application/json ou */*. Lorsque Accept est absent ou vaut text/html, ces statuts renvoient une page HTML (Content-Type: text/html) et un parseur JSON échouera. Cela concerne les clients qui n’envoient pas d’en-tête Accept. Le module urllib de Python en fait partie. curl envoie Accept: */* par défaut, tout comme fetch de Node : tous deux reçoivent donc du JSON, sauf si vous remplacez Accept. Les requêtes non authentifiées POST /generate/..., GET /jobs/{id}, GET /styles et GET /assets renvoient 401 {"message":"Unauthorized"} pour */* et application/json, et une page HTML lorsque Accept est absent ou vaut text/html. Une requête authentifiée GET /jobs/{id} pour un id inconnu se comporte de la même façon avec le statut : 404 en JSON {"message":"Job not found or unauthorized"} lorsque Accept demande du JSON, et 404 text/html lorsque Accept est absent. Le JSON invalide (400) et la validation (422) utilisent { "error" } et restent en JSON même lorsque Accept est absent. Il en va de même pour le 422 de champ supprimé, le 410 de modèle retiré, le 402 de Zero Data Retention, les réponses { "error" } des node apps et les erreurs mappées de l’API d’opérations Agent. Les 402 et 429 émis lors de l’admission d’un job POST /generate/... sont également en JSON, y compris avec un Accept de navigateur. 413 et 500 utilisent { "message" } et dépendent de Accept, comme 401 et 404.

Validation (422)

details liste chaque problème. field est le chemin joint par . ("image_style_references.0.url"). Les erreurs au niveau de l’objet utilisent une chaîne vide, comme pour la clé inconnue ci-dessus. Plusieurs clés inconnues produisent Unrecognized keys: ... avec le même field vide. expected n’est ajouté que lorsque code vaut "invalid_type". Un en-tête X-Webhook-URL invalide utilise ce même 422. GET /jobs avec des paramètres de requête invalides renvoie également ce 422. Il ne s’agit pas d’un 400. Une vérification d’entrée Zero Data Retention qui échoue dans l’outil renvoie 422 avec l’explication dans message (format { "message" }, donc Accept a son importance). Consultez Zero Data Retention.

Champs supprimés et obsolètes (422)

Le champ supprimé batchSize / batch_size utilise un 422 différent. Il n’y a pas de tableau details :
batch_size est supprimé de la même façon. field correspond au nom que vous avez envoyé. Un alias de champ obsolète utilise reason "deprecated_field" ou "conflicting_fields", ainsi que replacement, sunset_date et migration_url le cas échéant. Basez votre logique sur error et reason. La phrase à afficher à une personne est message.

Modèles retirés (410)

Un modèle dont la date de retrait est passée renvoie 410 avec Deprecation: true et un en-tête Sunset (une date RFC 1123) :
error est la valeur stable "model_unavailable". replacement et migration_url sont omis lorsqu’aucun remplacement n’est recommandé. Réessayer avec le même modèle continuera de renvoyer 410. Passez à replacement lorsqu’il est défini, et consultez Dépréciations. Un modèle obsolète mais encore en service envoie Deprecation et Sunset dans chaque réponse, y compris les erreurs. L’utilisation d’un alias de champ obsolète a le même effet, y compris sur son propre 422. Lorsqu’un guide de migration existe, un en-tête Link: <migration_url>; rel="deprecation" est également envoyé.

Codes de statut

400

Le JSON invalide sur generate est toujours renvoyé en JSON, sans qu’aucun en-tête Accept ne soit nécessaire :
L’exécution d’une node app utilise { "error" } pour une URL d’entrée inutilisable : Invalid URL for input "<key>", ou Failed to download URL for <key>: …. Le message de téléchargement couvre aussi les échecs temporaires : contrairement à generate (voir Téléchargements des entrées), un échec de téléchargement de node app renvoie donc toujours 400. Réessayez une fois si l’URL est valide. Un JSON invalide sur POST /node-apps/{id}/execute ne correspond pas au 400 de generate ci-dessus. Il devient un 500 { "message": "Internal Error" }, sans texte d’exception, et dépend de Accept. Les autres réponses 400 sur les assets et les node apps sont de la forme { "message": "..." } avec une courte explication, par exemple No file provided sur un upload présigné ou Invalid pagination parameters sur les versions de node app. Un upload d’asset en échec transmet le statut du service d’upload (400, 401, 404 ou 500) et peut placer le texte de sa réponse dans message. Ce texte est parfois une chaîne JSON. Les paramètres de requête invalides sur GET /jobs renvoient 422, et non 400.

401

Generate, jobs, assets, styles et node apps :
Les uploads présignés renvoient { "message": "Presigned upload URL expired" } ou { "message": "Invalid presigned upload URL" }.

402 Paiement requis

Pour un client facturé via l’API (une clé API, ou MCP avec une clé API) dont le solde API ne couvre pas le job :
Rechargez sur krea.ai/app/api/ ↗. Les jobs en cours se terminent. Consultez Clés API et facturation. Autres valeurs de message pour 402 sur l’API publique : Un appel generate avec Zero Data Retention sur un espace de travail où cette option n’est pas activée renvoie ce corps, toujours en JSON :
L’API d’opérations Agent utilise ses propres corps 402. Ceux-ci puisent dans le solde de calcul de l’espace de travail, et non dans le solde API.

403

404

Chaque 404 est de la forme { "message" }, par exemple pour un id de job inconnu :
L’absence d’en-tête Accept rend ces réponses en HTML, à l’exception de Endpoint not found pour un modèle que votre clé ou votre plan ne peut pas utiliser, qui est toujours en JSON. Une requête authentifiée GET /jobs/{id} pour un id inconnu sans Accept renvoie 404 text/html. Une opération Agent inconnue renvoie également 404 { "message": "Endpoint not found" }, et non le format Agent { "error", "code" }.

405

Le corps est du texte brut sans en-tête Content-Type, et non du JSON, y compris lorsque Accept vaut application/json. Le texte est la méthode suivie de method not allowed, par exemple GET method not allowed. Un en-tête Allow liste les méthodes acceptées par le chemin.

413 Charge utile trop volumineuse

Un corps de requête trop volumineux est rejeté avec 413. Lorsqu’il provient de l’API elle-même, le corps dépend de Accept :
Un corps très volumineux peut être rejeté avant d’atteindre l’API, avec une page HTML 413. N’envoyez pas de fichiers en ligne. Uploadez le fichier avec POST /assets et transmettez l’URL renvoyée dans la requête generate.

Téléchargements des entrées

Un hôte qui renvoie 404 ou 410 produit un 422 permanent. Le corps est en JSON, et Accept a son importance :
Un 410 de l’hôte utilise la même phrase avec 410. Les autres rejets permanents utilisent Input file rejected: …. Un échec de téléchargement pouvant être réessayé renvoie 502 ou 504. Basez votre logique sur le code de statut, et non sur le corps, puis réessayez. Un 502 qui se répète pour la même URL signifie probablement que l’URL est bloquée ou cassée. Changez d’URL. Les échecs de conversion lors de l’export 3D renvoient également 502. Ce chemin n’a pas été testé en conditions réelles, le corps peut donc aussi arriver sous forme de texte brut Cloudflare error code: 502. Basez votre logique sur le code de statut et réessayez. Un 502 qui se répète pour la même URL de modèle signifie probablement que l’URL est bloquée ou cassée.

429 concurrence

Lorsque le job ne peut pas être mis en backlog, une requête dépassant le plafond de concurrence peut être rejetée avec 429 et Content-Type: application/json :
limit est votre plafond de concurrence pour ce type de job. Il est comptabilisé par utilisateur, et non par espace de travail. Il est approximatif : une courte rafale peut être acceptée au-delà, ne comptez donc pas sur le fait que la requête limit + 1 sera celle qui échoue. jobType est une catégorie de job interne, et non le chemin public du modèle. Ne basez pas votre logique dessus. Krea 2 peut aussi renvoyer uniquement { "message": "CONCURRENCY_LIMIT_REACHED" }, sans limit ni jobType, lorsque sa file d’attente partagée est pleine. Il ne s’agit pas de votre plafond. Patientez puis réessayez. Le backlog n’est activé que lorsque le plan l’inclut (Pro et supérieur), que le modèle le prend en charge et que la requête n’est pas en Zero Data Retention. Les requêtes Krea 2 ne sont actuellement mises en backlog sur aucun plan : elles renvoient donc 429 au-delà du plafond. Lorsqu’il est activé, le job supplémentaire est accepté avec status: "backlogged" et démarre dès qu’un emplacement se libère. Il n’existe pas de plafond distinct pour le backlog. Consultez Limites de débit. L’API n’envoie ni Retry-After ni X-RateLimit-*. La réponse inclut en revanche cf-ray. En cas de 429, réessayez avec un backoff exponentiel une fois les jobs en cours terminés (interrogez GET /jobs/{id} ou utilisez un webhook). Si un job terminé ultérieurement épuise le solde, les jobs encore en backlog échouent avec error.code "insufficient_balance". Il s’agit d’un job en échec, et non d’une réponse HTTP 402. Ces jobs n’envoient pas de webhook : interrogez donc GET /jobs/{id} pour les jobs en backlog.

API d’opérations Agent

POST /agent/{operation} et GET /agent/session/{sessionId} renvoient { "error", "code"?, "allowedModels"? }. Seul error est obligatoire. allowedModels est en camelCase. Un tour qui échoue après avoir été accepté apparaît comme status: "failed" sur la session, et non comme l’une de ces erreurs HTTP. Consultez Agent. Un code d’erreur Agent non reconnu renvoie toujours 422 avec { "error", "code" }. Le 404 d’opération inconnue et un 500 non géré utilisent { "message" } et dépendent de Accept.

error.code des jobs en échec

GET /jobs et GET /jobs/{id} ne définissent error que lorsque status vaut "failed". Il n’y a pas de result exploitable :
Basez votre logique sur error.code. N’analysez jamais message.message peut être omis. Les messages provider_error et internal sont en texte libre, et un message internal peut être un texte brut du fournisseur tel que failed to download media from the provided URL. Traitez tout code que vous ne reconnaissez pas comme internal.
Les livraisons de webhook pour un job en échec utilisent le même objet job, y compris error. Une livraison d’annulation n’a pas de error. Une charge utile supérieure à 256 Kio n’est pas envoyée, et aucune autre livraison n’est effectuée pour ce job : interrogez donc plutôt GET /jobs/{id}. Vérifiez la signature avant de faire confiance au corps. Consultez Webhooks.

Débogage

Il n’existe pas d’en-tête d’identifiant de requête Krea. Chaque réponse inclut en revanche l’en-tête cf-ray de Cloudflare. Aucun en-tête Retry-After ni X-RateLimit-* n’est envoyé. Lorsque vous écrivez à support@krea.ai, indiquez :
  • Le job_id, lorsque l’appel a créé ou ciblé un job
  • L’heure et l’endpoint
  • Pour une erreur au moment de la requête, la valeur de cf-ray
Access-Control-Allow-Origin vaut *. Sur generate, jobs, assets, styles et node apps, Access-Control-Expose-Headers n’est pas défini : le fetch du navigateur ne peut donc pas lire cf-ray, Deprecation ni Sunset. Copiez cf-ray depuis le journal réseau ou depuis un client côté serveur. Sur chaque réponse, vérifiez Deprecation et Sunset avant que le modèle ne cesse d’accepter les appels. Consultez Dépréciations.

Étapes suivantes

Cycle de vie d'un job

Interrogez le statut jusqu’à ce que le job se termine, échoue ou soit annulé

Webhooks

Vérifiez la signature d’une livraison pour un job en échec

Limites de débit

Quand les jobs supplémentaires sont mis en backlog et quand ils renvoient 429

Clés API et facturation

Rechargez le solde API après un 402