> ## 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.

# Tareas asíncronas

> API de tareas asíncronas de AIHubMix: async en imágenes, video asíncrono y recuperación de LLM tras interrupción. Estado, resultados y webhooks en /ai/v1/tasks.

La generación de video y la generación de imágenes por lotes suelen tardar más de lo que resulta razonable esperar en una sola conexión HTTP; y si el cliente se desconecta durante una generación de texto largo, la respuesta ya producida tampoco se puede recuperar.

Las **tareas asíncronas** (Async Tasks) unifican estos tres escenarios en un mismo objeto de tarea: imagen y video crean una tarea mediante los endpoints de generación y devuelven de inmediato un `task_id`; las solicitudes de LLM interrumpidas por el cliente las completa la plataforma, que guarda la respuesta final. Los tres comparten los mismos estados de tarea, el mismo endpoint de consulta y el mismo flujo de descarga de resultados.

<Note>
  Consulta las tareas y descarga los resultados con la misma API Key con la que creaste la tarea. Las tareas están aisladas por API Key: aunque dos Keys pertenezcan a la misma cuenta, no pueden leer las tareas de la otra.
</Note>

<Card title="Activa las tareas asíncronas en la consola" icon="list-check" href="https://console.aihubmix.com/support" horizontal>
  Antes de crear imágenes o videos asíncronos, activa la función de tareas asíncronas para tu cuenta. Si la consola aún no muestra esta opción, contacta con el soporte técnico de AIHubMix.
</Card>

<Warning>
  Si la función de tareas asíncronas no está activada, las solicitudes de creación de tareas multimedia devuelven `403 async_not_enabled`. Las solicitudes de LLM no fallan por este motivo, pero la respuesta final no se podrá recuperar tras una interrupción del cliente.
</Warning>

***

<h2 id="quickstart">
  Inicio rápido
</h2>

El flujo completo de las tareas asíncronas de imagen y video consta de tres pasos:

```text theme={null}
1. Enviar la tarea -> obtener task_id
2. Consultar el estado -> esperar a que la tarea termine
3. Obtener el resultado -> descargar el archivo o leer el contenido de la respuesta
```

<CodeGroup>
  ```shell curl theme={null}
  # Paso 1: enviar una tarea asíncrona de video
  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 cat playing jazz on a piano, warm lighting, cinematic shot",
      "seconds": "5",
      "size": "1280x720"
    }'

  # Paso 2: consultar cada 15 segundos hasta que la tarea se complete, falle o se cancele
  curl https://aihubmix.com/ai/v1/tasks/{task_id} \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY"

  # Paso 3: descargar un resultado individual
  curl https://aihubmix.com/ai/v1/tasks/{task_id}/content \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
    --output result.mp4
  ```

  ```json Respuesta de creación theme={null}
  {
    "id": "task_01K0...",
    "object": "video",
    "model": "wan2.6-t2v",
    "status": "in_progress",
    "output": [],
    "error": null,
    "created_at": 1784707200,
    "completed_at": null,
    "expires_at": null
  }
  ```
</CodeGroup>

***

<h2 id="sync-vs-async">
  Comparación entre llamadas síncronas y tareas asíncronas
</h2>

| Tipo de solicitud           | Comportamiento por defecto              | Modo asíncrono                                                                                          |
| --------------------------- | --------------------------------------- | ------------------------------------------------------------------------------------------------------- |
| Generación de imágenes      | Devuelve el resultado de forma síncrona | Con `async: true` en el cuerpo devuelve `task_id` de inmediato                                          |
| Generación de video         | Siempre asíncrona                       | Tras la creación devuelve `task_id` y el resultado se obtiene por el endpoint de tareas                 |
| Generación de texto con LLM | Respuesta síncrona o en streaming       | Si el cliente se interrumpe y se cumplen las condiciones, la respuesta final se guarda como tarea `llm` |

Las llamadas síncronas devuelven el resultado dentro de una única respuesta HTTP y el resultado no se puede recuperar si la conexión se corta. Las tareas asíncronas guardan el resultado en la plataforma, y el `task_id` permite volver a consultarlo y descargarlo con la misma API Key antes de que el resultado expire, lo que resulta útil para solicitudes de generación de larga duración y para salidas de texto largo cuya respuesta final se necesita recuperar tras una interrupción.

***

<h2 id="api-overview">
  Resumen de endpoints
</h2>

| Operación                         | Método | Ruta                                         | Descripción                                          |
| --------------------------------- | ------ | -------------------------------------------- | ---------------------------------------------------- |
| Crear imagen asíncrona            | POST   | `/ai/v1/images/generations`                  | Añade `async: true` al cuerpo de la solicitud        |
| Crear video asíncrono             | POST   | `/ai/v1/videos`                              | Las tareas de video son asíncronas por defecto       |
| Consultar la lista de tareas      | GET    | `/ai/v1/tasks`                               | Busca las tareas creadas por la API Key actual       |
| Consultar el detalle de una tarea | GET    | `/ai/v1/tasks/{task_id}`                     | Consulta el estado unificado y la salida de la tarea |
| Obtener un resultado individual   | GET    | `/ai/v1/tasks/{task_id}/content`             | Válido para tareas de un solo resultado o de LLM     |
| Obtener un resultado concreto     | GET    | `/ai/v1/tasks/{task_id}/content/{result_id}` | Válido para tareas con varios resultados             |

Base URL: `https://aihubmix.com`, con autenticación mediante Bearer Token:

```bash theme={null}
Authorization: Bearer $AIHUBMIX_API_KEY
```

<Note>
  `/ai/v1/tasks` es un punto de consulta unificado de solo lectura y no ofrece `POST /ai/v1/tasks`. Las imágenes y los videos se crean con sus respectivos endpoints de generación; las solicitudes que cumplen las condiciones de [recuperación de LLM tras interrupción](#llm-interruption-recovery) se registran automáticamente como tareas `llm` cuando el cliente se interrumpe.
</Note>

***

<h2 id="supported-models">
  Modelos compatibles
</h2>

Las tareas asíncronas definen su alcance de compatibilidad según el tipo de tarea, y la llamada no requiere parámetros adicionales.

<h3 id="supported-models-image">
  Imágenes asíncronas
</h3>

| Modelo           |
| ---------------- |
| `qwen-image-2.0` |

<h3 id="supported-models-video">
  Videos asíncronos
</h3>

| Modelo       |
| ------------ |
| `wan2.6-t2v` |

<h3 id="supported-models-llm">
  Recuperación de LLM tras interrupción
</h3>

| Modelo           |
| ---------------- |
| `gpt-5.5-pro`    |
| `claude-fable-5` |

El alcance admitido se seguirá ampliando y esta tabla se actualizará en consecuencia.

***

<h2 id="create-async-task">
  Cómo crear tareas asíncronas
</h2>

<h3 id="create-async-image">
  Imágenes asíncronas
</h3>

El endpoint de imágenes devuelve el resultado de forma síncrona por defecto. Al establecer `async` en `true`, el endpoint devuelve de inmediato el objeto de tarea y la generación continúa en segundo plano.

```bash theme={null}
curl -X POST https://aihubmix.com/ai/v1/images/generations \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "qwen-image-2.0",
    "prompt": "A flower shop with delicate windows, warm sunlight streaming in",
    "n": 2,
    "size": "1024x1024",
    "async": true
  }'
```

`async` debe ser un valor booleano. Si se omite o se establece en `false`, el endpoint de imágenes mantiene el comportamiento síncrono.

<h3 id="create-async-video">
  Videos asíncronos
</h3>

El endpoint de video es siempre asíncrono. Tras una creación correcta devuelve el estado `pending` o `in_progress`, y no admite el cambio a espera síncrona mediante `Prefer: wait`.

```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",
    "seconds": "5",
    "size": "1280x720"
  }'
```

<h3 id="common-parameters">
  Parámetros comunes
</h3>

En los ejemplos, `model`, `prompt`, `n`, `seconds` y `size` son parámetros habituales de los modelos; los campos y valores admitidos por cada modelo se rigen por la documentación de API del modelo correspondiente, y para los modelos de video puedes consultar la [documentación de generación de video](/es/api/Video-Gen). La siguiente tabla describe únicamente los parámetros comunes a todas las tareas asíncronas.

| Parámetro               | Tipo      | Obligatorio                                 | Descripción                                                                         |
| ----------------------- | --------- | ------------------------------------------- | ----------------------------------------------------------------------------------- |
| `async`                 | boolean   | Imagen: sí; video: no es necesario enviarlo | El endpoint de imágenes se ejecuta de forma asíncrona cuando se establece en `true` |
| `webhook_url`           | string    | No                                          | Dirección de callback HTTPS de la tarea actual, hasta 512 caracteres                |
| `webhook_events_filter` | string\[] | No                                          | Estados finales que se quieren recibir, entre `completed`, `failed` y `cancelled`   |

<Note>
  Las tareas de imagen solo pueden usar Webhook cuando se envían con `async: true`. Si se omite `webhook_events_filter`, la plataforma envía los tres estados finales `completed`, `failed` y `cancelled`; si se incluye, debe usarse junto con `webhook_url`, no puede estar vacío ni contener valores repetidos.
</Note>

***

<h2 id="llm-interruption-recovery">
  Cómo funciona la recuperación de LLM tras interrupción
</h2>

La recuperación de LLM tras interrupción sirve para obtener la respuesta final después de que el cliente cierre la conexión. Esta capacidad reutiliza la forma actual de llamar al LLM, mantiene el mismo comportamiento de streaming y el mismo formato de respuesta, no requiere llamar a un endpoint de creación adicional y tampoco devuelve un `task_id` por adelantado.

<h3 id="recovery-conditions">
  Condiciones de aplicación
</h3>

Se deben cumplir todas las condiciones siguientes:

| Condición                                                    | Descripción                                                                                                            |
| ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------- |
| La cuenta tiene activadas las tareas asíncronas              | Se activa para la cuenta actual en la consola de AIHubMix                                                              |
| El modelo utilizado admite la recuperación tras interrupción | Consulta [Recuperación de LLM tras interrupción](#supported-models-llm); la llamada no requiere parámetros adicionales |
| Se llama a un endpoint de LLM admitido                       | La solicitud usa alguno de los endpoints de generación de texto listados abajo                                         |
| El cliente se interrumpe                                     | El cliente cancela, la red se corta o quien realiza la llamada cancela la solicitud                                    |

Endpoints admitidos:

| Endpoint                                           | Descripción                                        |
| -------------------------------------------------- | -------------------------------------------------- |
| `POST /v1/chat/completions`                        | OpenAI Chat Completions, con y sin streaming       |
| `POST /v1/messages`                                | Anthropic Messages, con y sin streaming            |
| `POST /v1/responses`                               | OpenAI Responses API                               |
| Gemini `generateContent` / `streamGenerateContent` | Endpoints nativos de generación de texto de Gemini |

<Note>
  No es necesario enviar campos adicionales en la llamada. El alcance admitido se indica en [Recuperación de LLM tras interrupción](#supported-models-llm); para los modelos que no figuran en la tabla, puedes verificar la recuperación tras interrupción con una solicitud de bajo coste antes de la integración definitiva, y esa solicitud de verificación se factura con normalidad. Si alguna condición no se cumple, la solicitud se ejecuta igualmente y no se genera una tarea `llm` cuando el cliente se interrumpe.
</Note>

<h3 id="recovery-flow">
  Flujo de ejecución tras la interrupción
</h3>

```text theme={null}
1. El cliente envía la solicitud de LLM con normalidad
2. El cliente se desconecta o cancela antes de que la respuesta termine
3. AIHubMix sigue procesando la solicitud, que se factura con normalidad
4. La respuesta final en JSON o SSE se guarda como una tarea de tipo llm
5. Consulta la lista de tareas con la API Key original y lee la respuesta guardada
```

Las solicitudes de LLM que se completan correctamente y se devuelven al cliente no crean tareas ni aparecen en la lista de tareas. Las solicitudes interrumpidas aparecen en la lista una vez guardada la respuesta final, por lo que durante el procesamiento es posible que todavía no se encuentren en la consulta.

<h3 id="locate-interrupted-request">
  Localizar la solicitud interrumpida correspondiente
</h3>

Las respuestas de LLM devuelven la cabecera `X-Aihubmix-Request-Id`. El cliente debe guardar ese valor en cuanto reciba las cabeceras de respuesta; tras una interrupción, puedes usar ese ID de solicitud en la lista de tareas asíncronas de la consola de AIHubMix para localizar la tarea correspondiente.

La API pública de tareas todavía no admite el filtrado por ID de solicitud. Si no has guardado el ID de solicitud, la búsqueda solo puede hacerse con la misma API Key usada al crear la solicitud, por modelo y fecha de creación:

```bash theme={null}
# Consultar las tareas de LLM interrumpidas más recientes
curl "https://aihubmix.com/ai/v1/tasks?object=llm&model={model}&order=desc&limit=20" \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"

# Una vez localizado el task_id, consulta el detalle y obtén la respuesta original
curl https://aihubmix.com/ai/v1/tasks/{task_id} \
  -H "Authorization: Bearer $AIHUBMIX_API_KEY"

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

<Warning>
  Cuando la misma API Key lanza varias solicitudes concurrentes al mismo modelo, el modelo y la fecha de creación no bastan para garantizar una correspondencia exacta. Si necesitas una recuperación fiable, guarda `X-Aihubmix-Request-Id` y localiza la tarea desde la consola; si no dispones de las cabeceras de respuesta, evita dar por hecho que la tarea más reciente de la lista corresponde a esa solicitud.
</Warning>

<Warning>
  Las tareas de recuperación de LLM tras interrupción todavía no envían Webhook; consulta el resultado a través de la lista de tareas. La interrupción del cliente no detiene el procesamiento en la plataforma, y esa llamada se factura según las reglas del endpoint de LLM original.
</Warning>

***

<h2 id="task-object">
  Objeto de tarea y estados
</h2>

Todas las tareas usan una estructura de respuesta unificada:

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

| Campo          | Tipo         | Descripción                                                                                       |
| -------------- | ------------ | ------------------------------------------------------------------------------------------------- |
| `id`           | string       | ID de la tarea en la plataforma, es decir, el `task_id` que se usa en las solicitudes posteriores |
| `object`       | string       | Tipo de tarea: `llm`, `image` o `video`                                                           |
| `model`        | string       | Modelo utilizado al crear la tarea                                                                |
| `status`       | string       | Estado unificado de la tarea                                                                      |
| `output`       | array        | Resultados disponibles; array vacío cuando la tarea no ha producido resultados                    |
| `error`        | object/null  | Información del fallo, normalmente con `code` y `message`                                         |
| `created_at`   | integer      | Fecha de creación, en segundos Unix                                                               |
| `completed_at` | integer/null | Momento en que la tarea se completó, falló o se canceló, en segundos Unix                         |
| `expires_at`   | integer/null | Fecha de expiración del primer resultado que caduca, en segundos Unix                             |

Campos de los resultados dentro de `output`:

| Campo          | Descripción                                                                                    |
| -------------- | ---------------------------------------------------------------------------------------------- |
| `index`        | Posición del resultado dentro de la tarea actual, empezando en 0                               |
| `result_id`    | ID del resultado; se usa al descargar un resultado concreto de una tarea con varios resultados |
| `type`         | Tipo de resultado: `file` para archivos y `response` para respuestas de LLM                    |
| `content_type` | Tipo de archivo del resultado (MIME), por ejemplo `video/mp4` o `application/json`             |
| `content_url`  | Dirección de descarga del resultado; el acceso requiere la API Key con la que se creó la tarea |
| `b64_json`     | Resultado codificado en Base64 que algunos modelos de imagen pueden devolver directamente      |
| `truncated`    | Indica si la respuesta de LLM se truncó por el límite de tamaño                                |

<h3 id="task-status">
  Descripción de los estados
</h3>

| Estado        | ¿Es final? | Descripción                                                             |
| ------------- | ---------- | ----------------------------------------------------------------------- |
| `pending`     | No         | La plataforma ha recibido la tarea y espera para empezar a ejecutarla   |
| `in_progress` | No         | La tarea se está ejecutando                                             |
| `completed`   | Sí         | La tarea se ha completado y el resultado puede obtenerse desde `output` |
| `failed`      | Sí         | La tarea ha fallado; el motivo está en `error`                          |
| `cancelled`   | Sí         | La tarea se ha cancelado                                                |

Se recomienda consultar cada **15 segundos** hasta que el estado pase a `completed`, `failed` o `cancelled`.

<Note>
  Las tareas `failed` o `cancelled` también pueden contener resultados parciales ya generados. Para determinar si hay resultados, además del estado conviene comprobar si `output` está vacío.
</Note>

***

<h2 id="query-tasks">
  Cómo consultar las tareas
</h2>

<h3 id="query-task-detail">
  Consultar el detalle de una tarea
</h3>

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

Este endpoint devuelve la información más reciente de la tarea en el momento de la consulta. La consulta no modifica la tarea; el estado lo actualiza la plataforma automáticamente.

<h3 id="query-task-list">
  Consultar la lista de tareas
</h3>

Si se pierde la respuesta de creación, o se necesita revisar tareas históricas por lotes, el endpoint de lista permite recuperar el `task_id`:

```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"
```

| Parámetro | Tipo    | Valor por defecto | Descripción                                                     |
| --------- | ------- | ----------------- | --------------------------------------------------------------- |
| `object`  | string  | -                 | Filtra por tipo: `llm`, `image`, `video`                        |
| `status`  | string  | -                 | Filtra por el estado unificado de la tarea                      |
| `model`   | string  | -                 | Filtra por coincidencia exacta del nombre del modelo            |
| `after`   | string  | -                 | Cursor de paginación, usa el `next_after` de la página anterior |
| `limit`   | integer | `20`              | Elementos por página, de 1 a 100                                |
| `order`   | string  | `desc`            | `asc` o `desc`                                                  |

Ejemplo de respuesta:

```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"
}
```

| Campo        | Descripción                                                            |
| ------------ | ---------------------------------------------------------------------- |
| `object`     | Siempre `list`, indica que se trata de una respuesta de lista          |
| `data`       | Array de tareas de la página actual                                    |
| `has_more`   | Indica si existe una página siguiente                                  |
| `next_after` | Cursor de la página siguiente; solo se devuelve cuando hay más páginas |

Para solicitar la página siguiente:

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

***

<h2 id="get-task-results">
  Cómo obtener los resultados de una tarea
</h2>

<h3 id="single-artifact">
  Tareas con un solo resultado
</h3>

Cuando `output` contiene un único archivo, se puede acceder directamente:

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

También puedes usar directamente `output[0].content_url`. El `Content-Type` de la respuesta de descarga coincide con `output[0].content_type`.

<h3 id="multiple-artifacts">
  Tareas con varios resultados
</h3>

Cuando `output` contiene varios archivos, hay que indicar el `result_id` correspondiente:

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

Si en una tarea con varios resultados no se indica `result_id`, el endpoint devuelve `400 result_id_required`.

<h3 id="llm-response-task">
  Tareas de respuesta de LLM
</h3>

Cuando se cumplen las condiciones de [recuperación de LLM tras interrupción](#llm-interruption-recovery) y la respuesta se ha guardado, el campo `object` de la tarea es `llm` y el `type` del elemento de `output` es `response`. El tipo de contenido puede ser:

* `application/json`: respuesta JSON normal
* `text/event-stream`: respuesta SSE en streaming guardada

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

La marca de truncado se encuentra en `output[0].truncated` dentro del detalle de la tarea. Cuando su valor es `true`, la respuesta guardada se truncó por el límite de tamaño. `GET /ai/v1/tasks/{task_id}/content` devuelve el contenido JSON o SSE original, sin envolverlo en un campo `truncated`, por lo que conviene consultar primero el detalle de la tarea y leer el contenido después.

<Warning>
  Los resultados pueden expirar y también puede existir un límite de descargas. Guárdalos antes de `expires_at`. Un resultado expirado devuelve `410 artifact_expired` y superar el límite de descargas devuelve `429 too_many_downloads`.
</Warning>

***

<h2 id="webhooks">
  Cómo usar Webhook
</h2>

Actualmente se admite el envío de un Webhook a nivel de tarea durante la creación de tareas asíncronas. Si quieres que AIHubMix te notifique al terminar la tarea, incluye `webhook_url` y, opcionalmente, `webhook_events_filter` en el cuerpo de la solicitud de imagen o video asíncronos:

```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 Japanese garden at sunrise",
    "seconds": "5",
    "webhook_url": "https://example.com/webhooks/aihubmix",
    "webhook_events_filter": ["completed", "failed"]
  }'
```

La dirección de callback debe usar HTTPS y no puede apuntar a la máquina local, a redes privadas ni a otras direcciones restringidas.

<h3 id="webhook-payload">
  Solicitud de callback
</h3>

AIHubMix envía una solicitud `POST` a la dirección de callback:

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

| Campo                | Descripción                                                                          |
| -------------------- | ------------------------------------------------------------------------------------ |
| `event_id`           | ID único de este evento de callback, sirve para identificar notificaciones repetidas |
| `event_type`         | Estado final de la tarea: `completed`, `failed` o `cancelled`                        |
| `created_at`         | Fecha de creación del evento de callback                                             |
| `data.task_id`       | ID de la tarea, se puede usar para consultar el detalle                              |
| `data.status`        | Estado actual de la tarea                                                            |
| `data.model`         | Modelo utilizado al crear la tarea                                                   |
| `data.results[].url` | Dirección de descarga de los resultados ya generados                                 |
| `data.error.code`    | Código de error del fallo, solo puede aparecer en eventos de fallo                   |
| `data.error.message` | Motivo del fallo, solo puede aparecer en eventos de fallo                            |

Las URL de `results` siguen requiriendo la API Key con la que se creó la tarea para poder accederse.

<h3 id="webhook-retry">
  Reintentos y deduplicación
</h3>

La plataforma intenta entregar el callback al menos una vez, por lo que un mismo evento puede enviarse de forma repetida:

* HTTP `2xx` indica recepción correcta.
* HTTP `5xx`, los errores de red y los tiempos de espera agotados provocan un reintento.
* HTTP `3xx` y `4xx` no se reintentan.
* Se entrega como máximo 6 veces, con intervalos de reintento de 1, 4, 16, 64 y 256 segundos.

El receptor debe guardar el `event_id`. Al recibir de nuevo el mismo `event_id`, omite la lógica de negocio y devuelve directamente `2xx`.

<Warning>
  El Webhook a nivel de tarea todavía no ofrece credenciales de firma independientes configurables. Al recibir la notificación, solicita `GET /ai/v1/tasks/{task_id}` con la API Key usada al crear la tarea y toma el resultado de la consulta como referencia.
</Warning>

***

<h2 id="error-codes">
  Respuestas de error y códigos de error
</h2>

Las respuestas de error usan una estructura unificada:

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

| Campo           | Descripción                                                              |
| --------------- | ------------------------------------------------------------------------ |
| `error.message` | Motivo del error                                                         |
| `error.type`    | Tipo de error                                                            |
| `error.code`    | Código de error identificable por el programa                            |
| `error.tid`     | ID de traza de la solicitud; facilítalo al contactar con soporte técnico |

| Código de estado HTTP | Código de error                 | Descripción                                                                              |
| --------------------- | ------------------------------- | ---------------------------------------------------------------------------------------- |
| 400                   | `invalid_request`               | Tipo o valor de parámetro incorrecto                                                     |
| 400                   | `result_id_required`            | Tarea con varios resultados sin `result_id` indicado                                     |
| 400                   | `webhook_invalid`               | URL de Webhook no válida                                                                 |
| 400                   | `webhook_events_filter_invalid` | Lista de eventos de Webhook no válida                                                    |
| 401                   | `authentication_failed`         | API Key ausente o no válida                                                              |
| 403                   | `async_not_enabled`             | La cuenta no tiene activadas las tareas asíncronas                                       |
| 404                   | `task_not_found`                | La tarea no existe o no pertenece a la API Key actual                                    |
| 404                   | `result_not_found`              | El resultado no existe o no está disponible en este momento                              |
| 410                   | `artifact_expired`              | El resultado ha expirado                                                                 |
| 429                   | `too_many_downloads`            | Se ha superado el límite de descargas del resultado                                      |
| 503                   | `async_unavailable`             | El servicio de imágenes asíncronas no está disponible temporalmente, inténtalo más tarde |

***

<h2 id="full-example">
  Ejemplo completo
</h2>

Flujo completo para crear una tarea de video, sondear el estado y descargar todos los resultados:

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

  import requests

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

  # 1. Crear la tarea
  response = requests.post(
      f"{BASE_URL}/ai/v1/videos",
      headers=HEADERS,
      json={
          "model": "wan2.6-t2v",
          "prompt": "A cat playing jazz on a piano",
          "seconds": "5",
          "size": "1280x720",
      },
      timeout=60,
  )
  response.raise_for_status()
  task = response.json()
  task_id = task["id"]

  # 2. Sondear hasta que la tarea se complete, falle o se cancele
  while task["status"] not in {"completed", "failed", "cancelled"}:
      time.sleep(15)
      response = requests.get(
          f"{BASE_URL}/ai/v1/tasks/{task_id}",
          headers=HEADERS,
          timeout=30,
      )
      response.raise_for_status()
      task = response.json()
      print("status:", task["status"])

  # 3. Obtener los resultados
  if task["output"]:
      for index, item in enumerate(task["output"]):
          if encoded := item.get("b64_json"):
              with open(f"result-{index}.bin", "wb") as file:
                  file.write(base64.b64decode(encoded))
              continue
          result = requests.get(
              item["content_url"],
              headers=HEADERS,
              timeout=120,
          )
          result.raise_for_status()
          with open(f"result-{index}.bin", "wb") as file:
              file.write(result.content)
  elif task["status"] == "failed":
      raise RuntimeError(task.get("error"))
  ```

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

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

  // 1. Crear la tarea
  const created = await fetch(`${BASE_URL}/ai/v1/videos`, {
    method: "POST",
    headers: HEADERS,
    body: JSON.stringify({
      model: "wan2.6-t2v",
      prompt: "A cat playing jazz on a piano",
      seconds: "5",
      size: "1280x720",
    }),
  });
  let task = await created.json();

  // 2. Sondear hasta que la tarea se complete, falle o se cancele
  const finished = new Set(["completed", "failed", "cancelled"]);
  while (!finished.has(task.status)) {
    await new Promise((resolve) => setTimeout(resolve, 15_000));
    const polled = await fetch(`${BASE_URL}/ai/v1/tasks/${task.id}`, {
      headers: HEADERS,
    });
    task = await polled.json();
    console.log("status:", task.status);
  }

  // 3. Obtener los resultados
  if (task.output?.length) {
    for (const [index, item] of task.output.entries()) {
      if (item.b64_json) {
        await writeFile(`result-${index}.bin`, Buffer.from(item.b64_json, "base64"));
        continue;
      }
      const result = await fetch(item.content_url, { headers: HEADERS });
      await writeFile(`result-${index}.bin`, Buffer.from(await result.arrayBuffer()));
    }
  } else if (task.status === "failed") {
    throw new Error(JSON.stringify(task.error));
  }
  ```

  ```shell curl theme={null}
  # 1. Crear la tarea y anotar el id devuelto
  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 cat playing jazz on a piano",
      "seconds": "5",
      "size": "1280x720"
    }'

  # 2. Consultar el estado cada 15 segundos
  curl https://aihubmix.com/ai/v1/tasks/task_01K0ABCDEF \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY"

  # 3. Descargar el resultado cuando el estado sea completed
  curl https://aihubmix.com/ai/v1/tasks/task_01K0ABCDEF/content \
    -H "Authorization: Bearer $AIHUBMIX_API_KEY" \
    --output result.mp4
  ```
</CodeGroup>

***

<h2 id="faq">
  Preguntas frecuentes
</h2>

**¿Con qué frecuencia conviene consultar el estado de la tarea?**

Se recomienda consultar cada 15 segundos y evitar el sondeo de alta frecuencia. Si usas Webhook, conviene mantener también una consulta de baja frecuencia como respaldo.

**¿Cómo recupero la tarea si he perdido la respuesta de creación?**

Solicita `GET /ai/v1/tasks` con la misma API Key con la que creaste la tarea; puedes acotar la búsqueda con `object`, `model` y `status`.

**¿Por qué otra API Key de la misma cuenta no encuentra la tarea?**

Las tareas están aisladas por API Key. Las solicitudes de consulta, descarga y lista deben usar la misma Key con la que se creó la tarea.

**¿Por qué la tarea ha fallado pero `output` no es un array vacío?**

Algunos modelos pueden haber generado resultados aprovechables antes del fallo o la cancelación global. Siempre que exista `content_url` o `b64_json` en `output`, el resultado puede obtenerse por la vía correspondiente.

**¿Qué hago si no recibo el Webhook?**

Comprueba que la dirección de callback sea accesible públicamente, que use HTTPS y que devuelva `2xx` en menos de 10 segundos. Uses o no Webhook, siempre puedes consultar el estado final con `GET /ai/v1/tasks/{task_id}`.

**¿La recuperación de LLM tras interrupción requiere cambiar el código actual?**

No. La forma de hacer la solicitud, el comportamiento de streaming y el formato de respuesta se mantienen. Se recomienda guardar la cabecera de respuesta `X-Aihubmix-Request-Id` para poder localizar la tarea correspondiente en la consola tras una interrupción.

***

Última actualización: 2026-07-28
