> ## Documentation Index
> Fetch the complete documentation index at: https://docs.aihubmix.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Génération de vidéos

> Créez des tâches vidéo asynchrones avec le protocole natif AIHubMix, consultez leur état et téléchargez les résultats.

<Note>
  [API Schema du modèle](/fr/api/async-tasks#model-schema)
</Note>

## Démarrage rapide

La génération vidéo est toujours asynchrone. Cet exemple utilise `wan2.6-t2v` et un entier `duration` en secondes.

<CodeGroup>
  ```bash Créer la tâche theme={null}
  curl -X POST https://aihubmix.com/ai/v1/videos \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "model": "wan2.6-t2v",
      "prompt": "Ocean waves crashing on rocky cliffs at sunset",
      "duration": 5,
      "size": "1280x720"
    }'
  ```

  ```json Réponse de création theme={null}
  {
    "id": "task_01K0ABCDEF",
    "object": "video",
    "model": "wan2.6-t2v",
    "status": "in_progress",
    "output": [],
    "error": null,
    "created_at": 1784707200,
    "completed_at": null,
    "expires_at": null
  }
  ```

  ```bash Consulter la tâche theme={null}
  curl https://aihubmix.com/ai/v1/videos/{id} \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY"
  ```

  ```bash Télécharger le résultat theme={null}
  curl https://aihubmix.com/ai/v1/videos/{id}/content \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
    --output result.mp4
  ```
</CodeGroup>

<h2 id="model-schema">
  Comment découvrir les modèles média asynchrones et obtenir leurs schémas ?
</h2>

La découverte se déroule en deux étapes. Récupérez d'abord dans le catalogue public les modèles texte-image ou texte-vidéo compatibles avec les API asynchrones. Utilisez ensuite le `model_id` du modèle pour obtenir le schéma de requête de ses endpoints.

<h3 id="async-media-model-list">
  Lister les modèles compatibles avec les API asynchrones
</h3>

Le catalogue de modèles utilise la même source de données que Playground. Utilisez `type=image_generation` pour les modèles texte-image et `type=video` pour les modèles texte-vidéo. Le paramètre `schema_checked=true` limite la liste aux modèles dont le schéma de requête a été publié et vérifié.

```bash theme={null}
# Modèles texte-image
curl "https://aihubmix.com/api/v1/models?type=image_generation&schema_checked=true&sort_by=order"

# Modèles texte-vidéo
curl "https://aihubmix.com/api/v1/models?type=video&schema_checked=true&sort_by=order"
```

Les deux requêtes utilisent le même endpoint. Le filtre `type` accepte actuellement une seule valeur. Interrogez donc chaque type de modèle séparément.

La réponse suit la forme `{success, message, data}`. Les champs de `data` utiles aux intégrations média asynchrones sont les suivants.

| Champ                     | Description                                                                     |
| ------------------------- | ------------------------------------------------------------------------------- |
| `data[].model_id`         | ID du modèle utilisé pour la génération et les requêtes de schéma suivantes     |
| `data[].model_name`       | Nom d'affichage du modèle                                                       |
| `data[].types`            | Types séparés par des virgules, avec éventuellement `image_generation` et `llm` |
| `data[].input_modalities` | Modalités d'entrée séparées par des virgules                                    |
| `data[].schema_checked`   | `true` lorsque le schéma de requête a été publié et vérifié                     |

```json theme={null}
{
  "success": true,
  "message": "",
  "data": [
    {
      "model_id": "qwen-image-2.0",
      "model_name": "Qwen Image 2.0",
      "types": "image_generation",
      "input_modalities": "text,image",
      "schema_checked": true
    }
  ]
}
```

<h3 id="single-model-schema">
  Obtenir le schéma de requête d'un modèle
</h3>

Les champs, les valeurs d'énumération et les plages numériques pris en charge peuvent varier selon le modèle. Avant d'envoyer une requête d'image ou de vidéo, utilisez l'endpoint public ci-dessous pour récupérer les endpoints disponibles et les schémas JSON de requête du modèle sélectionné.

```bash theme={null}
# Modèle texte-image
curl "https://aihubmix.com/call/schema/models/qwen-image-2.0/endpoints"

# Modèle texte-vidéo
curl "https://aihubmix.com/call/schema/models/wan2.6-t2v/endpoints"
```

La valeur `modality` de la réponse est `image` ou `video`. Chaque élément du tableau `endpoints` décrit un protocole d'appel disponible.

| Champ                        | Description                                                                                                            |
| ---------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `default_endpoint`           | Identifiant de l'endpoint par défaut du modèle                                                                         |
| `endpoints[].endpoint`       | Identifiant de l'endpoint                                                                                              |
| `endpoints[].method`         | Méthode HTTP, par exemple `POST`                                                                                       |
| `endpoints[].path`           | Chemin de la requête                                                                                                   |
| `endpoints[].content_types`  | Types de contenu acceptés par l'endpoint                                                                               |
| `endpoints[].lifecycle`      | Mode synchrone ou asynchrone, chemin d'interrogation et valeurs de statut                                              |
| `endpoints[].request.schema` | Schéma JSON complet de la requête pour ce modèle et cet endpoint, avec les champs requis et les contraintes de valeurs |

Un modèle peut renvoyer des endpoints `/ai/v1` ainsi que des endpoints `/v1` compatibles avec OpenAI. Les endpoints compatibles avec OpenAI peuvent ne pas encore prendre en charge les modèles les plus récents. Utilisez donc de préférence les endpoints `/ai/v1`. Pour les API de tâches asynchrones, sélectionnez l'élément dont le `path` est `/ai/v1/images/generations` ou `/ai/v1/videos`, puis utilisez son `request.schema`. Ne dépendez pas de la position d'un élément dans le tableau `endpoints`.

Les commandes suivantes extraient directement le schéma de requête de chaque endpoint de tâche asynchrone.

```bash theme={null}
# Texte-image
curl -s "https://aihubmix.com/call/schema/models/qwen-image-2.0/endpoints" \
  | jq '.endpoints[] | select(.path == "/ai/v1/images/generations") | .request.schema'

# Texte-vidéo
curl -s "https://aihubmix.com/call/schema/models/wan2.6-t2v/endpoints" \
  | jq '.endpoints[] | select(.path == "/ai/v1/videos") | .request.schema'
```

L'endpoint renvoie `404 model_not_found` si le modèle n'existe pas ou ne dispose d'aucun endpoint détectable. Il renvoie `500 endpoints_unavailable` lorsque les données des endpoints sont temporairement indisponibles.

***

<h2 id="create-async-video">
  Comment créer une tâche vidéo ?
</h2>

Les requêtes vidéo sont toujours asynchrones et `Prefer: wait` ne permet pas d'attendre en mode synchrone. Le protocole standard utilise l'entier `duration` exprimé en secondes :

```bash theme={null}
curl -X POST https://aihubmix.com/ai/v1/videos \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan2.6-t2v",
    "prompt": "Ocean waves crashing on rocky cliffs at sunset",
    "duration": 5,
    "size": "1280x720"
  }'
```

<h3 id="video-parameters">
  Champs standard des vidéos
</h3>

| Champ                   | Type         | Obligatoire | Description                                                       |
| ----------------------- | ------------ | ----------- | ----------------------------------------------------------------- |
| `model`                 | string       | Oui         | Nom du modèle                                                     |
| `prompt`                | string       | Oui         | Description de la vidéo, non vide                                 |
| `duration`              | integer/null | Non         | Durée en secondes, plage définie par le modèle                    |
| `aspect_ratio`          | string/null  | Non         | Rapport largeur-hauteur, valeur par défaut du protocole `16:9`    |
| `resolution`            | string/null  | Non         | `480p`, `720p`, `1080p`, `1K`, `2K` ou `4K`                       |
| `size`                  | string/null  | Non         | `{width}x{height}`, peut remplacer `resolution` et `aspect_ratio` |
| `seed`                  | integer/null | Non         | Graine aléatoire                                                  |
| `input_references`      | array/null   | Non         | Ressources de référence sous forme d'image, de vidéo ou d'audio   |
| `frame_images`          | array/null   | Non         | Image de première ou de dernière frame                            |
| `generate_audio`        | boolean/null | Non         | Indique si une piste audio doit être générée                      |
| `webhook_url`           | string       | Non         | Adresse de rappel HTTPS, 512 caractères maximum                   |
| `webhook_events_filter` | string\[]    | Non         | Sous-ensemble non vide de `completed`, `failed`, `cancelled`      |
| `extra`                 | object/null  | Non         | Paramètres étendus propres au modèle                              |

Structure d'un élément `input_references` :

```json theme={null}
{
  "type": "image_url",
  "url": "https://example.com/reference.png"
}
```

`type` peut valoir `image_url`, `video_url` ou `audio_url`.

Structure d'un élément `frame_images` :

```json theme={null}
{
  "frame_type": "first_frame",
  "image_url": {
    "url": "https://example.com/first-frame.png"
  }
}
```

`frame_type` peut valoir `first_frame` ou `last_frame`.

***

<h2 id="task-object">
  Objet de tâche média
</h2>

Les API propres aux images et aux vidéos renvoient la structure suivante :

```json theme={null}
{
  "id": "task_01K0ABCDEF",
  "object": "video",
  "model": "wan2.6-t2v",
  "status": "completed",
  "output": [
    {
      "index": 0,
      "type": "file",
      "b64_json": null,
      "content_url": "https://aihubmix.com/ai/v1/videos/task_01K0ABCDEF/content"
    }
  ],
  "error": null,
  "created_at": 1784707200,
  "completed_at": 1784707320,
  "expires_at": null
}
```

| Champ          | Type         | Description                                                                   |
| -------------- | ------------ | ----------------------------------------------------------------------------- |
| `id`           | string       | ID de tâche de la plateforme                                                  |
| `object`       | string       | `image` ou `video`                                                            |
| `model`        | string       | Nom du modèle                                                                 |
| `status`       | string       | Statut actuel de la tâche                                                     |
| `output`       | array        | Résultats générés, tableau vide s'il n'y en a pas encore                      |
| `error`        | object/null  | Informations d'échec, pouvant contenir `code`, `message` et `upstream_detail` |
| `created_at`   | integer      | Date de création, en secondes Unix                                            |
| `completed_at` | integer/null | Date du statut final, en secondes Unix                                        |
| `expires_at`   | null         | Les API propres aux médias renvoient actuellement `null`                      |

Élément `output` d'un média :

| Champ         | Type        | Description                           |
| ------------- | ----------- | ------------------------------------- |
| `index`       | integer     | Ordre du résultat, à partir de `0`    |
| `type`        | string      | Vaut actuellement `file`              |
| `content_url` | string/null | Adresse de téléchargement du résultat |
| `b64_json`    | string/null | Résultat d'image encodé en Base64     |

<h3 id="task-status">
  Description des statuts
</h3>

| Statut        | Terminé | Description                                           |
| ------------- | ------- | ----------------------------------------------------- |
| `pending`     | Non     | La plateforme a reçu la tâche, en attente d'exécution |
| `in_progress` | Non     | La tâche est en cours d'exécution                     |
| `completed`   | Oui     | La tâche est terminée, `output` est disponible        |
| `failed`      | Oui     | La tâche a échoué, consulter `error`                  |
| `cancelled`   | Oui     | La tâche a été annulée                                |

Le client peut interroger la tâche toutes les 15 secondes jusqu'au statut `completed`, `failed` ou `cancelled`. Cet intervalle de 15 secondes est une recommandation pour le polling côté client, pas une restriction du protocole serveur.

***

<h2 id="query-tasks">
  Comment consulter les tâches média ?
</h2>

<h3 id="query-task-detail">
  Consulter le détail d'un média
</h3>

```bash theme={null}
# Image
curl https://aihubmix.com/ai/v1/images/{task_id} \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"

# Vidéo
curl https://aihubmix.com/ai/v1/videos/{task_id} \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

Les API de détail média peuvent renvoyer un statut actualisé. Utilisez donc l'API de détail d'image ou de vidéo correspondante pour le polling.

<h3 id="query-task-list">
  Lister les médias
</h3>

Si la réponse de création est perdue, retrouvez l'ID de tâche dans la liste du média correspondant :

```bash theme={null}
curl "https://aihubmix.com/ai/v1/videos?limit=20&order=desc" \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

| Paramètre | Type    | Valeur par défaut | Description                                                             |
| --------- | ------- | ----------------- | ----------------------------------------------------------------------- |
| `after`   | string  | -                 | Curseur de pagination, utiliser le `next_after` de la page précédente   |
| `limit`   | integer | `20`              | Nombre d'éléments par page, maximum `100`                               |
| `order`   | string  | `desc`            | Ordre croissant avec `asc`, toute autre valeur est traitée comme `desc` |

```json theme={null}
{
  "object": "list",
  "data": [
    {
      "id": "task_01K0ABCDEF",
      "object": "video",
      "model": "wan2.6-t2v",
      "status": "in_progress",
      "output": [],
      "error": null,
      "created_at": 1784707200,
      "completed_at": null,
      "expires_at": null
    }
  ],
  "has_more": true,
  "next_after": "task_01K0ABCDEF"
}
```

La liste média renvoie un instantané au moment de la consultation et n'actualise pas activement le statut des tâches.

***

<h2 id="unified-tasks">
  Comment utiliser l'API de tâches unifiées ?
</h2>

L'API de tâches unifiées accepte les filtres suivants :

```bash theme={null}
curl "https://aihubmix.com/ai/v1/tasks?object=video&status=in_progress&limit=20&order=desc" \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

| Paramètre | Type    | Valeur par défaut | Description                                                    |
| --------- | ------- | ----------------- | -------------------------------------------------------------- |
| `object`  | string  | -                 | `llm`, `image` ou `video`                                      |
| `status`  | string  | -                 | `pending`, `in_progress`, `completed`, `failed` ou `cancelled` |
| `model`   | string  | -                 | Filtre exact par nom de modèle                                 |
| `after`   | string  | -                 | Curseur de pagination                                          |
| `limit`   | integer | `20`              | Plage de `1` à `100`                                           |
| `order`   | string  | `desc`            | `asc` ou `desc`                                                |

Détail d'une tâche unifiée :

```bash theme={null}
curl https://aihubmix.com/ai/v1/tasks/{task_id} \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"
```

Élément `output` unifié d'une tâche média :

```json theme={null}
{
  "index": 0,
  "result_id": "result_01K0XYZ",
  "type": "file",
  "content_type": "video/mp4",
  "content_url": "https://aihubmix.com/ai/v1/tasks/task_01K0ABCDEF/content"
}
```

Pour un résultat unique, demandez directement `/ai/v1/tasks/{id}/content`. Pour plusieurs résultats, demandez `/ai/v1/tasks/{id}/content/{result_id}`. Sans ID de résultat, l'API renvoie `400 result_id_required`.

<Note>
  Les API de liste, de détail et de contenu des tâches unifiées sont isolées
  selon le Bearer Token qui a créé la tâche. Une autre clé API du même compte ne
  peut pas lire cette tâche.
</Note>

***

<h2 id="get-task-results">
  Télécharger les résultats média
</h2>

<h3 id="single-artifact">
  Télécharger une vidéo
</h3>

```bash theme={null}
curl https://aihubmix.com/ai/v1/videos/{task_id}/content \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  --output result.mp4
```

<Warning>
  Les résultats peuvent expirer et une limite de téléchargements peut
  s'appliquer. Une expiration renvoie `410 artifact_expired`. Le dépassement de
  la limite renvoie `429 too_many_downloads`.
</Warning>

***

<h2 id="webhooks">
  Utiliser un Webhook
</h2>

Les images asynchrones et les vidéos prennent en charge les Webhooks au niveau de la tâche :

```bash theme={null}
curl -X POST https://aihubmix.com/ai/v1/videos \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "wan2.6-t2v",
    "prompt": "A tranquil garden at sunrise",
    "duration": 5,
    "size": "1280x720",
    "webhook_url": "https://example.com/webhooks/aihubmix",
    "webhook_events_filter": ["completed", "failed"]
  }'
```

`webhook_url` est limité à 512 caractères et ne peut pas pointer vers la machine locale, un réseau privé ou une autre adresse restreinte. Lorsque `webhook_events_filter` est omis, la plateforme envoie `completed`, `failed` et `cancelled`. Lorsqu'il est fourni, le tableau ne peut pas être vide ni contenir de doublons, et doit être utilisé avec `webhook_url`.

Si `webhook_url` est absent de la requête, les images asynchrones et les vidéos tentent d'utiliser l'adresse de rappel par défaut du compte. Une adresse par défaut non valide est ignorée et ne bloque pas la création de la tâche.

<h3 id="webhook-payload">
  Requête de rappel
</h3>

```json theme={null}
{
  "event_id": "evt_01K0ABCDEF",
  "event_type": "completed",
  "created_at": "2026-08-12T12:00:00Z",
  "data": {
    "task_id": "task_01K0ABCDEF",
    "status": "completed",
    "model": "wan2.6-t2v",
    "results": [
      {
        "url": "https://aihubmix.com/ai/v1/tasks/task_01K0ABCDEF/content"
      }
    ]
  }
}
```

| Champ                | Description                                                   |
| -------------------- | ------------------------------------------------------------- |
| `event_id`           | ID de l'événement de rappel, utilisé pour la déduplication    |
| `event_type`         | `completed`, `failed` ou `cancelled`                          |
| `created_at`         | Date de l'événement au format RFC 3339                        |
| `data.task_id`       | ID de tâche de la plateforme                                  |
| `data.status`        | Statut final actuel                                           |
| `data.model`         | Nom du modèle                                                 |
| `data.results[].url` | Adresse de téléchargement éventuellement renvoyée à la fin    |
| `data.error`         | Informations d'erreur éventuellement renvoyées en cas d'échec |

`results` n'apparaît que si le résultat a été archivé. Le téléchargement nécessite toujours un Bearer Token.

<h3 id="webhook-retry">
  Nouvelles tentatives et déduplication
</h3>

La plateforme utilise une livraison au moins une fois. Un même événement peut être envoyé plusieurs fois :

* HTTP `2xx` indique une réception réussie.
* HTTP `5xx`, une erreur réseau ou un délai dépassé déclenchent une nouvelle tentative.
* HTTP `3xx` et `4xx` ne déclenchent pas de nouvelle tentative.
* Six livraisons au maximum, avec des intervalles successifs de 1, 4, 16, 64 et 256 secondes.

Le destinataire doit enregistrer `event_id` et renvoyer immédiatement `2xx` s'il reçoit à nouveau le même événement.

<Warning>
  Le Webhook au niveau de la tâche n'a pas de clé de signature indépendante. Si
  une vérification de signature est nécessaire, configurez un abonnement Webhook
  au niveau du compte et conservez la consultation du détail de la tâche comme
  méthode de confirmation du résultat.
</Warning>

***

<h2 id="error-codes">
  Réponses et codes d'erreur
</h2>

```json theme={null}
{
  "error": {
    "message": "Task not found.",
    "type": "invalid_request_error",
    "code": "task_not_found",
    "tid": "req_01K0ABCDEF"
  }
}
```

| Statut HTTP | Code d'erreur                   | Description                                                                                                  |
| ----------- | ------------------------------- | ------------------------------------------------------------------------------------------------------------ |
| 400         | `invalid_request`               | Type ou valeur de paramètre incorrect                                                                        |
| 400         | `result_id_required`            | La tâche unifiée contient plusieurs résultats, mais aucun `result_id` n'a été précisé pour le téléchargement |
| 400         | `webhook_invalid`               | URL de Webhook non valide ou filtre fourni sans URL                                                          |
| 400         | `webhook_events_filter_invalid` | Liste d'événements Webhook non valide                                                                        |
| 401         | `authentication_failed`         | Clé API absente ou non valide                                                                                |
| 403         | `async_not_enabled`             | Tâches asynchrones non activées pour le compte                                                               |
| 404         | `task_not_found`                | Tâche ou curseur de pagination inexistant                                                                    |
| 404         | `result_not_found`              | Résultat inexistant ou actuellement indisponible au téléchargement                                           |
| 410         | `artifact_expired`              | Résultat expiré                                                                                              |
| 413         | `request_too_large`             | Corps de requête supérieur à 32 MiB                                                                          |
| 429         | `too_many_downloads`            | Limite de téléchargements du résultat dépassée                                                               |
| 503         | `async_unavailable`             | Service d'images asynchrones temporairement indisponible                                                     |

`error.tid` est l'ID de traçage de la requête. Fournissez-le au support technique lors d'un diagnostic.

***

## Exemple complet

Ces exemples créent une tâche, l'interrogent et téléchargent le résultat MP4.

<CodeGroup>
  ```python Python theme={null}
  import os
  import time

  import requests

  base_url = "https://aihubmix.com"
  headers = {
      "Authorization": f"Bearer {os.environ['AIHUBMIX_API_KEY']}",
      "Content-Type": "application/json",
  }

  response = requests.post(
      f"{base_url}/ai/v1/videos",
      headers=headers,
      json={
          "model": "wan2.6-t2v",
          "prompt": "A cat playing jazz on a piano",
          "duration": 5,
          "size": "1280x720",
      },
      timeout=60,
  )
  response.raise_for_status()
  task = response.json()

  while task["status"] not in {"completed", "failed", "cancelled"}:
      time.sleep(15)
      response = requests.get(
          f"{base_url}/ai/v1/videos/{task['id']}",
          headers=headers,
          timeout=30,
      )
      response.raise_for_status()
      task = response.json()

  if task["status"] == "completed":
      result = requests.get(
          f"{base_url}/ai/v1/videos/{task['id']}/content",
          headers=headers,
          timeout=120,
      )
      result.raise_for_status()
      with open("result.mp4", "wb") as file:
          file.write(result.content)
  else:
      raise RuntimeError(task.get("error") or task["status"])
  ```

  ```typescript TypeScript theme={null}
  import { writeFile } from "node:fs/promises";

  const baseUrl = "https://aihubmix.com";
  const headers = {
    Authorization: `Bearer ${process.env.AIHUBMIX_API_KEY}`,
    "Content-Type": "application/json",
  };

  const created = await fetch(`${baseUrl}/ai/v1/videos`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      model: "wan2.6-t2v",
      prompt: "A cat playing jazz on a piano",
      duration: 5,
      size: "1280x720",
    }),
  });
  if (!created.ok) throw new Error(await created.text());
  let task = await created.json();

  const finished = new Set(["completed", "failed", "cancelled"]);
  while (!finished.has(task.status)) {
    await new Promise((resolve) => setTimeout(resolve, 15_000));
    const polled = await fetch(`${baseUrl}/ai/v1/videos/${task.id}`, { headers });
    if (!polled.ok) throw new Error(await polled.text());
    task = await polled.json();
  }

  if (task.status === "completed") {
    const result = await fetch(`${baseUrl}/ai/v1/videos/${task.id}/content`, {
      headers,
    });
    if (!result.ok) throw new Error(await result.text());
    await writeFile("result.mp4", Buffer.from(await result.arrayBuffer()));
  } else {
    throw new Error(JSON.stringify(task.error ?? task.status));
  }
  ```
</CodeGroup>
