Erreurs
Chaque code métier, ce qu’il signifie et quelles erreurs valent la peine d’être réessayées.
Quand un appel échoue, la réponse vous donne un nombre (code) qui indique le type de problème et une phrase (msg) destinée à un humain. Basez votre logique sur le nombre ; affichez ou journalisez la phrase.
L’enveloppe
{ "code": 40201, "msg": "Insufficient balance", "request_id": "req_…" }codeest un code métier.200signifie succès ; toutes les autres valeurs sont listées ci-dessous.- En cas d’échec, il n’y a pas de champ
data, sauf pour quelques erreurs de la bibliothèque de ressources qui ajoutentdata.reason. - Le statut HTTP est aussi renseigné (
40201arrive avec HTTP402). Appuyez-vous sur l’un des deux, sans les mélanger — nous recommandonscode, plus précis. request_idfigure aussi dans l’en-têteX-Request-Id. Indiquez-le quand vous contactez le support.
Si une réponse n’est pas du JSON du tout — une page HTML ou texte venue du réseau intermédiaire —, traitez-la selon le statut HTTP et journalisez le début du corps.
Langue des messages d’erreur
msg et l’errorMessage d’une tâche en échec sont en anglais par défaut. Envoyez Accept-Language avec en, ja, ko, de, fr, es, pt-BR, ru, it ou pl, ou réglez la langue des erreurs API dans la console, pour les recevoir dans cette langue ; les autres langues reviennent à l’anglais. Les réponses d’erreur portent Content-Language. Les codes ne changent jamais avec la langue — une raison de plus de ne jamais analyser msg.
Quand un modèle donne une raison précise à son échec (par exemple une image de référence illisible), errorMessage la transmet en anglais, sans les détails internes.
Codes généraux
code | HTTP | Signification | Réessayer ? |
|---|---|---|---|
200 | 200 / 202 | Succès | — |
400 | 400 | La requête ou son input est invalide ; msg précise le problème | Non — corrigez |
40003 | 400 | Un envoi ne correspond pas à son ticket (taille, type ou contenu) | Non — nouveau ticket, nouvel envoi |
40004 | 400 | Requête valide, mais le modèle ne peut pas servir cette combinaison de réglages pour l’instant | Non — modifiez le réglage cité dans msg |
401 | 401 | Clé absente, inconnue ou révoquée (détails) | Non |
403 | 403 | Non autorisé (voir Autorisations) | Non |
404 | 404 | N’existe pas, ou appartient à une autre clé | Non |
409 | 409 | Conflit avec l’état actuel (quand réessayer) | Parfois |
40901 | 409 | Un devis a expiré ou le prix a changé | Redemandez un devis |
413 | 413 | Corps de requête trop volumineux | Non — envoyez les médias au lieu de les intégrer |
429 | 429 | Trop de requêtes | Oui — après Retry-After |
500 | 500 | Un problème de notre côté | Oui — avec un délai croissant |
503 | 503 | Un service d’appui est brièvement indisponible | Oui — après Retry-After |
Solde et plafonds
code | HTTP | Signification | Que faire |
|---|---|---|---|
40201 | 402 | Pas assez de crédits pour la réservation de cette tâche | Achetez des crédits, puis renvoyez |
40202 | 402 | Un plafond de dépense de la clé est atteint | Relevez-le dans la console API ou attendez sa remise à zéro |
Autorisations
code | HTTP | Signification | Que faire |
|---|---|---|---|
40301 | 403 | Cette clé ne peut pas appeler ce modèle | Ajoutez le modèle à la liste autorisée de la clé |
40302 | 403 | La requête vient d’une adresse hors de la liste d’IP autorisées | Ajoutez l’adresse ou retirez la restriction |
40303 | 403 | Le service n’est pas proposé dans cette région | Impossible à contourner |
40310 | 403 | L’adresse e-mail du compte n’est pas encore vérifiée | Ouvrez le lien de l’e-mail d’inscription ; la clé fonctionne dès la vérification |
Un simple 403 avec une clé valide signifie que le compte ne peut pas utiliser l’API pour le moment ; contactez le support avec le request_id.
Disponibilité des modèles
code | HTTP | Signification | Réessayer ? |
|---|---|---|---|
50301 | 503 | Le modèle ne peut pas prendre de tâches en ce moment | Oui, plus tard — ou choisissez un autre modèle |
40004 | 400 | Le modèle fonctionne, mais pas avec ces réglages | Non — changez le réglage |
Aucun des deux ne crée de tâche ni ne réserve de crédits.
Codes d’échec des tâches
Une tâche acceptée puis en échec a state: "failed" et l’une de ces valeurs dans errorCode. La liste est fermée : traitez toute autre valeur comme upstream_failed.
errorCode | Signification | Réessayer ? |
|---|---|---|
invalid_request | Le modèle n’a pas accepté les paramètres | Non — corrigez-les |
unsupported_combination | Cette combinaison de réglages n’est pas prise en charge pour l’instant | Non — changez un réglage |
content_rejected | Le modèle a refusé ce contenu | Non — modifiez le prompt ou la référence |
invalid_asset | Un fichier de référence est illisible ou n’est plus disponible | Renvoyez-le et créez une nouvelle tâche |
rate_limited | Le service de génération était saturé | Oui, avec un délai croissant |
upstream_unavailable | La génération est temporairement indisponible | Oui, un peu plus tard |
generation_failed | La génération a tourné mais n’a rien produit | Peut-être — la même entrée échoue souvent de la même façon |
timeout | La tâche a manqué de temps | Peut-être — essayez une sortie plus courte ou moins définie |
upstream_failed | Tout le reste | Oui, avec un délai croissant |
Une tâche en échec libère sa réservation et ne coûte donc rien (quelques modèles facturent les refus de contenu et le précisent sur leur page). errorMessage explique la raison en toutes lettres ; basez votre logique uniquement sur errorCode.
Quand un 409 vaut un nouvel essai
| Cas | Réessayer ? |
|---|---|
Deux requêtes avec le même Idempotency-Key sont arrivées ensemble | Oui, avec la même clé, après une courte pause |
L’Idempotency-Key a servi à une autre requête ou à une autre clé | Non |
| Un envoi ou un résultat est encore en traitement | Oui, après quelques secondes |
jobs/retry sur une tâche pas encore terminée | Oui, une fois qu’elle est finale |
jobs/retry sur une tâche réussie | Non — créez une nouvelle tâche |
| Un ticket d’envoi ou un fichier envoyé a expiré | Non — renvoyez le fichier |
Écrire le nouvel essai
Ne réessayez que ce qui peut réussir la deuxième fois, attendez Retry-After quand il est fourni, et sinon augmentez le délai de façon exponentielle :
const RETRYABLE = new Set([429, 500, 503, 50301]);
async function call(path, init, attempts = 4) {
for (let i = 0; i < attempts; i++) {
const res = await fetch(`https://api.popnow.ai/api/v1${path}`, init);
if (!res.headers.get('content-type')?.includes('json')) {
throw new Error(`HTTP ${res.status}: ${(await res.text()).slice(0, 200)}`);
}
const body = await res.json();
if (body.code === 200) return body.data;
if (!RETRYABLE.has(body.code)) throw new Error(`${body.code} ${body.msg} (${body.request_id})`);
const wait = Number(res.headers.get('retry-after')) * 1000 || 2 ** i * 1000 + Math.random() * 500;
await new Promise((r) => setTimeout(r, wait));
}
throw new Error('out of retries');
}import random, time, requests
RETRYABLE = {429, 500, 503, 50301}
def call(method, path, attempts=4, **kwargs):
for i in range(attempts):
res = requests.request(method, f"https://api.popnow.ai/api/v1{path}", timeout=60, **kwargs)
try:
body = res.json()
except ValueError:
raise RuntimeError(f"HTTP {res.status_code}: {res.text[:200]}")
if body["code"] == 200:
return body["data"]
if body["code"] not in RETRYABLE:
raise RuntimeError(f'{body["code"]} {body["msg"]} ({body.get("request_id")})')
retry_after = res.headers.get("retry-after")
time.sleep(float(retry_after) if retry_after else 2**i + random.random() / 2)
raise RuntimeError("out of retries")Quand vous réessayez createTask, envoyez toujours le même Idempotency-Key, pour qu’une requête qui avait en fait réussi ne soit pas exécutée ni facturée deux fois.
Diagnostic
- Notez le
request_idet lecode. - Retrouvez la tâche dans les journaux de la console API, par identifiant de tâche ou
request_id. - Toujours bloqué ? Contactez le support avec le
request_id, l’heure (UTC) et lecode. N’envoyez jamais votre clé API.

