# Requêtes

Une requête correspond à un appel d’un modèle. Elle possède un identifiant (`req_…`), un statut, son coût en crédits API (1000 = 1 USD) et, lorsqu’elle réussit, les fichiers générés. Le même objet est renvoyé par chaque point de terminaison ci-dessous, pour chaque modèle.

## Trouver un modèle

Le catalogue des 1 496 modèles est un JSON public (aucune clé requise) :

```bash
curl "https://api.doitong.com/v1/models?category=text-to-video&lab=Google&limit=20"
```

| Paramètre de requête | Signification |
|---|---|
| `q` | Mots qui doivent tous apparaître dans le nom, l’identifiant, le fabricant ou les tags, par exemple `kling 3`. |
| `category` | Un identifiant de catégorie, par exemple `text-to-video` ou `upscale`. `GET https://api.doitong.com/v1/categories` répertorie les 21 catégories avec leur nombre d’éléments. |
| `lab` | Le fabricant du modèle, par nom ou identifiant, par exemple `Google` ou `black-forest-labs`. |
| `family` | Un identifiant `family` provenant d’une ligne précédente : chaque variante d’un modèle (pro, fast, image-to-video, …). |
| `mode` | `exact` (le prix est calculé à partir de l’entrée), `measured` (à partir de la longueur ou de la taille des fichiers d’entrée), `estimate` (un prix estimé par exécution) ou `metered` (facturé selon l’utilisation réelle, jusqu’à un maximum par exécution). |
| `limit`, `cursor` | Taille de page (de 1 à 100, 50 par défaut) et `next_cursor` de la page précédente. |

Chaque ligne contient `id`, `name`, `lab`, `category`, `family`, `summary`, `tags`, `output_kind`, `docs_url` et un objet `price` (voir [Tarification](https://doitong.com/developers/docs/pricing#price-objects)). `GET https://api.doitong.com/v1/models/{model_id}` ajoute le schéma JSON complet des entrées et sorties, les noms canoniques des paramètres, les règles de tarification et un exemple d’entrée. Une `category` ou un `mode` inconnu renvoie `400 invalid_parameter`.

## Exécuter un modèle

```bash
curl -X POST "https://api.doitong.com/v1/run/{model_id}?wait=20" \
  -H "Authorization: Bearer $DOITONG_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: order-1842-cover" \
  -d '{"prompt": "..."}'
```

- Le corps contient l’entrée du modèle, sous forme d’objet JSON. Chaque page de modèle répertorie ses paramètres.
- L’entrée est vérifiée avant toute facturation. Une entrée non valide renvoie `422 invalid_input` avec le `param` concerné et ne coûte rien.
- `?wait=N` (jusqu’à 20 secondes) maintient l’appel ouvert jusqu’à la fin de la requête ou l’expiration du délai.
- `?webhook_url=https://…` envoie un POST signé à cette URL lorsque la requête se termine (voir [Webhooks](https://doitong.com/developers/docs/webhooks)).
- `?storage=permanent` ou `?storage=temporary` détermine la durée de conservation des fichiers de sortie ; sans ce paramètre, le réglage du compte s’applique (voir [Emplacement des fichiers](#storage)).

La réponse est `202 Accepted` tant que la requête est en cours, et `200 OK` lorsqu’elle s’est terminée pendant l’attente (ou lorsqu’il s’agit d’une nouvelle lecture, voir ci-dessous). Les en-têtes `Location` et `Doitong-Request-Id` contiennent l’URL et l’identifiant de la requête.

## Statuts

Cycle de vie d’une requête: `queued` → `running` → `succeeded` | `failed` | `canceled` (final ; les échecs et les annulations sont remboursés).

| Statut | Signification | Final |
|---|---|---|
| `queued` | Acceptée et facturée, en attente d’un worker. `queue_position` peut indiquer sa position dans la file. | non |
| `running` | Le modèle génère le résultat. | non |
| `succeeded` | Terminée. `outputs` répertorie les fichiers. | oui |
| `failed` | Le modèle ou une limite l’a arrêtée. `error` en indique la raison. Les crédits API sont remboursés. | oui |
| `canceled` | Annulée avant de produire un résultat. Les crédits API sont remboursés. | oui |

Une requête qui dépasse sa limite de temps échoue avec le code `timeout` et est remboursée : 15 minutes pour les images, 60 minutes pour les vidéos, 30 minutes pour l’audio et tout le reste.

## L’objet requête

```json
{
  "id": "req_8k2m4q7x1z9c3v5b6n0p2r4t",
  "object": "request",
  "model": "flux/schnell",
  "status": "succeeded",
  "created_at": "2026-10-20T12:00:00Z",
  "started_at": "2026-10-20T12:00:01Z",
  "completed_at": "2026-10-20T12:00:02Z",
  "queue_position": null,
  "cost": { "credits": 3, "usd": "0.003", "charged": 3, "refunded": 0 },
  "input": { "prompt": "..." },
  "output": { "images": [ { "url": "https://content.doitong.com/dev-api/…/0-output.jpeg", "width": 1024, "height": 768 } ] },
  "outputs": [
    { "type": "image", "url": "https://content.doitong.com/dev-api/…/0-output.jpeg", "content_type": "image/jpeg",
      "width": 1024, "height": 768, "file_size": 183920, "stored": true }
  ],
  "error": null,
  "metrics": { "inference_seconds": 1.2 },
  "storage": { "mode": "permanent", "bytes": 183920, "expires_at": null, "expired": false },
  "urls": {
    "self": "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t",
    "cancel": "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/cancel"
  }
}
```

- `outputs` est identique pour tous les modèles : une entrée par fichier généré avec `type` (`image`, `video`, `audio`, `file` ou `3d`), une `url` sur notre stockage, `content_type` et, lorsqu’elles sont connues, `file_size`, `width`, `height`, `duration`.
- `output` est l’objet de résultat propre au modèle (ses champs sont répertoriés sur chaque page de modèle), avec les mêmes URL.
- `storage` indique comment les fichiers sont conservés : `mode` (`permanent` ou `temporary`), `bytes` stockés, `expires_at` (date de suppression d’un fichier temporaire, `null` pour les fichiers permanents) et `expired` (`true` une fois les fichiers supprimés).
- `cost.credits` est le prix de l’appel en crédits API (`cost.usd` en USD), `cost.charged` le montant débité du solde API, et `cost.refunded` le montant remboursé. Pour un modèle `metered`, `cost.credits` correspond au maximum bloqué au début (`cost.held`) ; une fois l’exécution réussie, `cost.settled` indique le montant correspondant à l’utilisation et le reste du maximum figure dans `cost.refunded` (voir [Facturation selon l’utilisation](https://doitong.com/developers/docs/pricing#metered)).
- Lorsqu’une requête échoue, `error` vaut `{ "type": …, "code": …, "message": … }`.

## Lire une requête

```bash
curl "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t?wait=20" \
  -H "Authorization: Bearer $DOITONG_API_KEY"
```

- `?wait=N` (jusqu’à 20 secondes) effectue une attente longue : l’appel renvoie dès que la requête est finale, ou après N secondes avec l’état actuel. Répéter cet appel est le moyen le plus simple d’attendre un résultat.
- `?logs=1` ajoute les lignes du journal de progression du modèle (les 50 dernières) sous `logs`.

Vous pouvez uniquement lire les requêtes de votre propre compte ; tout autre identifiant renvoie `404 request_not_found`.

## Répertorier les requêtes

```bash
curl "https://api.doitong.com/v1/requests?limit=20&status=succeeded&model=flux/schnell" \
  -H "Authorization: Bearer $DOITONG_API_KEY"
```

De la plus récente à la plus ancienne. `limit` va de 1 à 100 (20 par défaut) ; `status` et `model` servent de filtres. La réponse est `{ "object": "list", "data": [ … ], "has_more": true, "next_cursor": "req_…" }` ; transmettez `cursor=<next_cursor>` pour obtenir la page suivante.

## Annuler une requête

```bash
curl -X POST "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/cancel" \
  -H "Authorization: Bearer $DOITONG_API_KEY"
```

- Annulée avant le démarrage du modèle : le statut devient `canceled`, les crédits API sont remboursés et vous recevez `200`.
- Déjà en cours de génération : l’annulation est transmise et vous recevez `202` avec `"cancel_requested": true`. Si le modèle termine malgré tout, la requête réussit normalement et est facturée.
- Déjà finale : `409 not_cancelable` (une requête déjà `canceled` renvoie simplement `200`).

## Supprimer les fichiers d’une requête

```bash
curl -X DELETE "https://api.doitong.com/v1/requests/req_8k2m4q7x1z9c3v5b6n0p2r4t/files" \
  -H "Authorization: Bearer $DOITONG_API_KEY"
```

Supprime immédiatement nos copies des fichiers de sortie de la requête et arrête leur facturation de stockage. La réponse est l’objet requête avec `storage.expired: true` ; ses URL restent dans l’enregistrement, mais ne fonctionnent plus. Un nouvel appel ne change rien (`200`). Une requête encore `queued` ou `running` n’a pas encore de fichiers : `409 request_active`. Nécessite `models:run`.

## Idempotence : réessayer sans payer deux fois

Les réseaux peuvent tomber en panne. Pour réessayer une exécution en toute sécurité, envoyez un en-tête `Idempotency-Key` (toute chaîne de 255 caractères maximum, unique par opération, par exemple votre propre identifiant de commande) :

- Même clé et même corps qu’auparavant : vous récupérez la requête d’origine (`200`, en-tête `Idempotent-Replayed: true`) et rien n’est facturé à nouveau.
- Même clé et même corps après une exécution ayant échoué avant d’atteindre le modèle (`upstream_error` ou `internal_error` lors de la soumission, `insufficient_credits`, `budget_exceeded`, `too_many_inflight`) : rien n’a été produit et rien n’est facturé ; la nouvelle tentative exécute donc à nouveau le modèle au lieu de renvoyer l’échec.
- Même clé avec un corps différent : `409 idempotency_mismatch`.
- Les clés sont limitées à la clé API qui les a envoyées.

## Emplacement des fichiers

Chaque fichier de sortie est copié dans notre stockage avant que la requête soit marquée `succeeded` ; les URL de `outputs` se trouvent donc sur nos propres hôtes et vous pouvez les utiliser directement. Vous choisissez leur durée de conservation :

| Mode | Durée | Prix |
|---|---|---|
| `permanent` (par défaut) | Jusqu’à leur suppression | 100 crédits API (0,10 $) par Go et par mois, facturés quotidiennement sur le solde API |
| `temporary` | 7 jours, puis suppression | Gratuit |

- Le réglage du compte s’applique aux nouvelles requêtes : le bouton « Conserver les fichiers indéfiniment » du [tableau de bord](https://doitong.com/developers/dashboard#balance), ou `PATCH https://api.doitong.com/v1/account/storage` avec `{"mode": "temporary"}`. `GET https://api.doitong.com/v1/account` l’affiche sous `storage`, avec les octets conservés et l’estimation mensuelle.
- `?storage=permanent|temporary` lors d’une exécution (l’argument `storage` de l’outil MCP `run`) remplace ce réglage pour cette exécution.
- Modifier le réglage ne touche jamais aux fichiers déjà présents ; supprimez-les avec [`DELETE /requests/{id}/files`](#delete-files).
- Lorsque le solde API ne peut pas payer le stockage, rien n’est facturé et vous recevez un e-mail : rechargez votre solde dans les 30 jours, sinon les fichiers conservés deviennent temporaires et sont supprimés 7 jours plus tard.

Dans le rare cas où notre copie échoue, l’entrée contient `"stored": false` et l’URL est celle d’origine, à durée de vie limitée : téléchargez-la rapidement.
