# Erreurs

Chaque point de terminaison échoue de la même façon : un statut HTTP et une enveloppe JSON.

```json
{
  "error": {
    "type": "invalid_request",
    "code": "invalid_input",
    "message": "duration must be one of 5, 10.",
    "param": "duration",
    "details": [ { "param": "duration", "message": "duration must be one of 5, 10." } ],
    "request_id": null,
    "doc_url": "https://doitong.com/developers/docs/errors#invalid_input"
  }
}
```

| Champ | Signification |
|---|---|
| `type` | Classe générale de l’erreur. Décidez quoi faire à partir de celle-ci. |
| `code` | Raison exacte, stable et lisible par une machine. Chaque code a une section ci-dessous; `doc_url` y mène. |
| `message` | Explication lisible par un humain, sûre à journaliser ou à afficher à un développeur. |
| `param` | Paramètre d’entrée ou en-tête en cause, s’il y en a un. |
| `details` | Pour les erreurs d’entrée, chaque problème trouvé : `[{ "param", "message" }]`. |
| `request_id` | La requête concernée, lorsqu’il y en a une. |

Aucun appel qui renvoie une erreur n’est facturé. Une requête qui échoue *après* avoir été acceptée conserve le statut
`failed`, contient `error: { "type", "code", "message" }` dans l’objet de requête et est remboursée automatiquement.

## Types

| Type | Statut HTTP | Marche à suivre |
|---|---|---|
| `invalid_request` | 400, 413 ou 422 | Corrigez la requête. Réessayer le même appel échouera de nouveau. |
| `authentication_error` | 401 | Envoyez une clé valide dans `Authorization: Bearer <key>`. |
| `permission_error` | 403 | Utilisez une clé avec la portée nécessaire. |
| `not_found` | 404 | Vérifiez l’identifiant du modèle ou de la requête. |
| `insufficient_credits` | 402 | Rechargez le solde API (`top_up_url` dans l’erreur). |
| `budget_exceeded` | 402 | Le budget propre à la clé est épuisé. Décision finale : demandez à son propriétaire de l’augmenter. |
| `conflict` | 409 | La ressource n’est pas dans un état qui permet cet appel. |
| `rate_limited` | 429 | Attendez `Retry-After` secondes, puis réessayez. |
| `upstream_error` | 502 | Le service principal du modèle a échoué. Vous pouvez réessayer avec la même `Idempotency-Key` : l’exécution recommencera; rien ne vous a été facturé. |
| `service_unavailable` | 503 | L’API est en pause ou une dépendance est indisponible. Réessayez plus tard. |
| `internal_error` | 500 | Il s’agit d’un bogue de notre côté. Réessayez; si le problème persiste, contactez le soutien avec l’heure et le `request_id`. |

## Codes

### `invalid_request`

Requête mal formée générique (400).

### `invalid_json`

Le corps n’est pas un JSON valide (400).

### `invalid_body`

Le corps est un JSON valide, mais pas un objet; l’entrée du modèle doit être un objet JSON (400).

### `body_too_large`

Le corps dépasse 16 MB (413). Téléversez les fichiers volumineux et transmettez plutôt leur URL (voir [Fichiers](https://doitong.com/developers/docs/files)).

### `invalid_parameter`

Un paramètre de requête a une valeur incorrecte, par exemple `limit` en dehors de 1 à 100, `wait` qui n’est pas un nombre, un
`status` ou une `category` inconnue, ou `storage` autre que `permanent` / `temporary` (400). `param` l’identifie.

### `invalid_category`

`GET /openapi.json?category=` désigne une catégorie qui n’existe pas (400). `GET https://api.doitong.com/v1/categories` les répertorie.

### `invalid_cursor`

Le `cursor` d’un appel de liste n’appartient pas à cette liste (400). Recommencez sans curseur.

### `invalid_idempotency_key`

L’en-tête `Idempotency-Key` est vide ou compte plus de 255 caractères (400).

### `invalid_arguments`

Un appel d’outil MCP contient un argument manquant ou mal formé (MCP seulement). `param` identifie l’argument.

### `invalid_input`

L’entrée du modèle ne passe pas la validation (422) : paramètre inconnu (le message suggère le nom valide le plus proche),
paramètre requis manquant, mauvais type, valeur hors de la liste ou de la plage autorisée, ou nom canonique et nom
natif fournis avec des valeurs différentes. `param` est le premier paramètre fautif et `details` les répertorie tous.
Aucun frais n’est facturé.

### `unsupported_file`

Un fichier possède un type que nous n’acceptons pas (422), par exemple une extension non prise en charge ou un `content_type`
qui ne correspond pas à l’extension.

### `invalid_webhook_url`

`webhook_url` n’est pas une URL publique `https://` (422). Les adresses privées, locales et simples `http://` sont refusées.

### `missing_api_key`

Le point de terminaison nécessite une clé API et aucune n’a été envoyée (401).

### `invalid_api_key`

La clé est inconnue, révoquée ou expirée (401).

### `insufficient_scope`

La clé ne possède pas la portée nécessaire à cet appel (403), par exemple `models:run` pour une exécution ou `models:read` pour lire
les requêtes et le solde. Voir [Authentification](https://doitong.com/developers/docs/authentication#scopes).

### `account_disabled`

Le compte est fermé ou suspendu (403). Ses clés ne fonctionnent plus.

### `not_found`

Le chemin n’existe pas (404).

### `model_not_found`

Aucun modèle public ne possède cet identifiant (404). Répertoriez les modèles avec `GET https://api.doitong.com/v1/models`.

### `request_not_found`

Aucune requête avec cet identifiant n’existe dans votre compte (404). Les requêtes des autres comptes ne sont jamais visibles.

### `insufficient_credits`

Le **solde API** du compte (crédits API, 1 000 crédits API = 1 $ — et non les crédits des applications Doitong) ne couvre pas le
prix de cet appel (402). La réponse est envoyée avant toute facturation. L’erreur contient `top_up_url`; ajoutez des fonds
à [https://doitong.com/developers/dashboard#balance](https://doitong.com/developers/dashboard#balance), puis réessayez.

```json
{ "error": { "type": "insufficient_credits", "code": "insufficient_credits",
             "message": "This request costs 560 API credits ($0.56); the API balance is 120 API credits ($0.12). Top up at https://doitong.com/developers/dashboard#balance",
             "top_up_url": "https://doitong.com/developers/dashboard#balance", "doc_url": "https://doitong.com/developers/docs/errors#insufficient_credits" } }
```

### `budget_exceeded`

L’appel dépasserait le budget propre à la clé API en crédits API (402). Le budget est défini par le propriétaire de la clé; réessayer
n’aidera pas tant qu’il ne l’aura pas augmenté.

### `conflict`

L’appel entre en conflit avec l’état actuel de la ressource (409).

### `idempotency_mismatch`

L’`Idempotency-Key` a déjà été utilisée avec un corps différent (409). Utilisez une nouvelle clé pour une nouvelle opération.

### `idempotency_in_progress`

Une requête utilisant la même `Idempotency-Key` est en cours de création (409). Réessayez dans un instant pour la récupérer.

### `request_active`

La requête est encore `queued` ou `running`, donc elle n’a pas encore de fichiers à supprimer (409). Supprimez-les une fois terminée.

### `not_cancelable`

La requête est déjà `succeeded` ou `failed` et ne peut pas être annulée (409).

### `rate_limited`

La clé a effectué trop de requêtes pendant la fenêtre actuelle (429). Consultez les en-têtes `X-RateLimit-*` et `Retry-After`.

### `too_many_inflight`

Le compte possède déjà 10 requêtes `queued` ou `running` (429). Lancez la suivante lorsqu’une d’elles sera terminée.

### `upstream_error`

Le service principal du modèle a refusé ou n’a pas pu traiter la requête (502 lors de l’exécution, ou `failed` avec ce code dans la requête). Les crédits API sont
remboursés. Si le service principal a lui-même rejeté l’entrée, l’appel renvoie plutôt `422 invalid_input` avec son message.

### `upstream_lost`

Le service principal du modèle ne connaît plus la requête; aucun résultat n’arrivera donc. Elle se termine par
`failed` avec ce code (type `upstream_error`) et est remboursée. Exécutez-la de nouveau.

### `timeout`

La requête a dépassé sa limite (15 minutes pour les images, 60 pour la vidéo, 30 autrement) et a été arrêtée. Elle se termine par
`failed` avec ce code et est remboursée.

### `service_unavailable`

L’API est temporairement en pause ou une dépendance, comme le téléversement de fichiers, est indisponible (503). Réessayez plus tard.

### `internal_error`

Un problème est survenu de notre côté (500). Réessayez; si le problème persiste, contactez le soutien.

### `charge_failed`

Le compte n’a pas pu être débité en raison d’un problème interne (500). La requête est marquée `failed`; rien n’a été prélevé. Réessayez.

### `pricing_unavailable`

Le prix du modèle n’est pas configuré; il ne peut donc pas être chiffré ni exécuté pour le moment (500).
