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

# Generación de vídeo

> Genera vídeos a partir de texto o imágenes con la cola asíncrona de Venice: envía la tarea, consulta su estado y descarga el resultado.

La generación de vídeo es asíncrona. Envía un trabajo, guarda `queue_id` y haz polling de `/video/retrieve` hasta que la respuesta sea `video/mp4`.

## Endpoints

| Endpoint               | Propósito                            | Obligatorio |
| ---------------------- | ------------------------------------ | ----------- |
| `POST /video/quote`    | Obtén precio en USD antes de generar | No          |
| `POST /video/queue`    | Envía la solicitud de generación     | Sí          |
| `POST /video/retrieve` | Consulta estado o descarga el vídeo  | Sí          |
| `POST /video/complete` | Elimina el vídeo del almacenamiento  | No          |

## Paso 1: encola la generación

**Solicitud:**

```bash theme={"system"}
POST https://api.venice.ai/api/v1/video/queue
Authorization: Bearer $VENICE_API_KEY
Content-Type: application/json

{
  "model": "wan-2.5-preview-text-to-video",
  "prompt": "A gondola gliding through Venice canals at sunset",
  "duration": "5s",
  "resolution": "720p",
  "aspect_ratio": "16:9"
}
```

**Respuesta (200):**

```json theme={"system"}
{
  "model": "wan-2.5-preview-text-to-video",
  "queue_id": "123e4567-e89b-12d3-a456-426614174000"
}
```

Para los modelos Grok Imagine Private, la respuesta de la cola incluye un campo extra `download_url`:

```json theme={"system"}
{
  "model": "grok-imagine-text-to-video-private",
  "queue_id": "123e4567-e89b-12d3-a456-426614174000",
  "download_url": "https://private-share.venice.ai/v1/share/read/..."
}
```

`download_url` es una URL pre-firmada que usas para descargar el vídeo terminado en lugar de leerlo desde la respuesta de retrieve. Solo se devuelve una vez en la respuesta de la cola, así que persístela junto con `queue_id`. Esto se aplica a las cuatro variantes Grok Imagine Private:

* `grok-imagine-text-to-video-private`
* `grok-imagine-image-to-video-private`
* `grok-imagine-reference-to-video-private`
* `grok-imagine-video-to-video-private`

A diferencia de las variantes públicas `grok-imagine-*-video`, los modelos Grok Imagine Private no se facturan por rechazos de moderación de contenido, por lo que solo pagas por generaciones exitosas.

Guarda `model`, `queue_id` y `download_url` (si está presente) para todas las llamadas posteriores.

### Enlaces de descarga privados

Para los modelos privados, `download_url` es la forma de obtener el archivo terminado una vez completado el trabajo. El enlace es **de corta duración y de un solo propósito**: está ahí para entregarte el MP4, no para servir como URL de larga duración o ampliamente compartida.

Si una descarga se interrumpe, puedes **reintentar el mismo `GET` unas cuantas veces** desde el mismo entorno hasta que el archivo termine. Esos reintentos son para recuperarse de cortes de red — no para hacer polling indefinido del mismo enlace, compartirlo entre muchos clientes o incrustarlo como una URL de medios permanente. Patrones así suelen aparecer como **`429`** o **`410`**, lo que puede ser sorprendente si esperabas que el enlace se comportara como hosting de archivos normal.

Para fiabilidad, **las solicitudes `GET` deben originarse desde una sola red de cliente**. Hay cierta flexibilidad si tu IP cambia una vez (por ejemplo, desconectas una VPN y vuelves a intentarlo), pero una gran variación de IPs de origen normalmente no funcionará.

La URL es válida durante hasta **24 horas**, o hasta que el objeto sea eliminado.

<Note>
  Si necesitas una URL estable, reproducción pública o acceso repetido en el tiempo, guarda el archivo en **tu propio almacenamiento** primero y sírvelo desde allí.
</Note>

**Privacidad: revoca el enlace con `DELETE`**

Cuando termines de descargar el archivo — o si decides no conservarlo — puedes llamar a **`DELETE`** sobre el mismo `download_url`. No se requiere API key de Venice en esa solicitud. Esto es opcional, pero **recomendado cuando la privacidad importa**, porque algunos proxies y middleboxes fuera de Venice mantienen logs de URLs completas, y eliminar el enlace es la forma más simple de reducir la ventana en la que existe la URL pre-firmada.

```bash theme={"system"}
curl -X DELETE "$DOWNLOAD_URL"
```

**Flujo:** haz polling de `/video/retrieve` hasta `COMPLETED` → `GET` del `download_url` (reintenta ligeramente si la transferencia falla) → guarda el archivo donde lo necesites → `DELETE` del `download_url` si quieres que el enlace se invalide → opcionalmente llama a `/video/complete` si aún usas la limpieza basada en cola.

## Paso 2: polling de finalización

**Solicitud:**

```bash theme={"system"}
POST https://api.venice.ai/api/v1/video/retrieve
Authorization: Bearer $VENICE_API_KEY
Content-Type: application/json

{
  "model": "wan-2.5-preview-text-to-video",
  "queue_id": "123e4567-e89b-12d3-a456-426614174000"
}
```

**La respuesta depende del estado:**

| Content-Type                         | Significado                 | Acción                                                  |
| ------------------------------------ | --------------------------- | ------------------------------------------------------- |
| `application/json`                   | Aún procesando              | Espera 5s y vuelve a hacer polling                      |
| `video/mp4`                          | Completado                  | El cuerpo de la respuesta es el archivo de vídeo        |
| `application/json` con `"COMPLETED"` | Completado, vídeo no inline | Haz `GET` del `download_url` de la respuesta de la cola |

**Respuesta en procesamiento (200, application/json):**

```json theme={"system"}
{
  "status": "PROCESSING",
  "average_execution_time": 145000,
  "execution_duration": 53200
}
```

Los tiempos están en milisegundos. Usa `average_execution_time` para estimar la espera restante.

**Respuesta completada (200, video/mp4):**
El cuerpo de la respuesta son datos binarios en bruto del vídeo. Guárdalo en un archivo.

**Respuesta completada (200, application/json con `"COMPLETED"`):**
Para los modelos que devolvieron un `download_url` en la cola, retrieve siempre devuelve JSON. Obtén el vídeo con `GET download_url` (sin cabecera de auth). Consulta [Enlaces de descarga privados](#private-download-links) para saber cómo funcionan estas URLs, los reintentos y el `DELETE` opcional.

## Paso 3: limpieza (opcional)

O auto-eliminar al recuperar:

```json theme={"system"}
{
  "model": "wan-2.5-preview-text-to-video",
  "queue_id": "123e4567-e89b-12d3-a456-426614174000",
  "delete_media_on_completion": true
}
```

O llama a `/video/complete` tras guardar:

```bash theme={"system"}
POST https://api.venice.ai/api/v1/video/complete
Authorization: Bearer $VENICE_API_KEY
Content-Type: application/json

{
  "model": "wan-2.5-preview-text-to-video",
  "queue_id": "123e4567-e89b-12d3-a456-426614174000"
}
```

**Respuesta (200):**

```json theme={"system"}
{
  "success": true
}
```

***

## Ejemplo completo

<CodeGroup>
  ```python Python theme={"system"}
  import os
  import time
  import requests

  API_KEY = os.environ.get("VENICE_API_KEY")
  BASE_URL = "https://api.venice.ai/api/v1"
  HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}

  # Queue
  resp = requests.post(f"{BASE_URL}/video/queue", headers=HEADERS, json={
      "model": "wan-2.5-preview-text-to-video",
      "prompt": "A gondola gliding through Venice canals at sunset",
      "duration": "5s",
      "resolution": "720p",
      "aspect_ratio": "16:9"
  })
  data = resp.json()
  model, queue_id = data["model"], data["queue_id"]
  download_url = data.get("download_url")

  # Poll
  while True:
      resp = requests.post(f"{BASE_URL}/video/retrieve", headers=HEADERS,
                           json={"model": model, "queue_id": queue_id})
      if "video/mp4" in resp.headers.get("Content-Type", ""):
          with open("output.mp4", "wb") as f:
              f.write(resp.content)
          break
      if resp.json().get("status") == "COMPLETED" and download_url:
          with open("output.mp4", "wb") as f:
              f.write(requests.get(download_url).content)
          break
      time.sleep(5)

  # Cleanup
  requests.post(f"{BASE_URL}/video/complete", headers=HEADERS,
                json={"model": model, "queue_id": queue_id})
  ```

  ```javascript Node.js theme={"system"}
  const API_KEY = process.env.VENICE_API_KEY;
  const BASE_URL = "https://api.venice.ai/api/v1";
  const headers = {"Authorization": `Bearer ${API_KEY}`, "Content-Type": "application/json"};

  // Queue
  const queueResp = await fetch(`${BASE_URL}/video/queue`, {
      method: "POST", headers,
      body: JSON.stringify({
          model: "wan-2.5-preview-text-to-video",
          prompt: "A gondola gliding through Venice canals at sunset",
          duration: "5s", resolution: "720p", aspect_ratio: "16:9"
      })
  });
  const {model, queue_id, download_url} = await queueResp.json();

  // Poll
  while (true) {
      const resp = await fetch(`${BASE_URL}/video/retrieve`, {
          method: "POST", headers,
          body: JSON.stringify({model, queue_id})
      });
      if (resp.headers.get("Content-Type")?.includes("video/mp4")) {
          const fs = await import("fs");
          fs.writeFileSync("output.mp4", Buffer.from(await resp.arrayBuffer()));
          break;
      }
      const status = await resp.json();
      if (status.status === "COMPLETED" && download_url) {
          const fs = await import("fs");
          const video = await fetch(download_url);
          fs.writeFileSync("output.mp4", Buffer.from(await video.arrayBuffer()));
          break;
      }
      await new Promise(r => setTimeout(r, 5000));
  }

  // Cleanup
  await fetch(`${BASE_URL}/video/complete`, {
      method: "POST", headers,
      body: JSON.stringify({model, queue_id})
  });
  ```
</CodeGroup>

***

## Parámetros de solicitud

### Solicitud Queue

| Parámetro         | Tipo    | Obligatorio              | Predeterminado                                                 | Descripción                                                                                                                                      |
| ----------------- | ------- | ------------------------ | -------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------ |
| `model`           | string  | Sí                       | -                                                              | ID del modelo. Usa `wan-2.5-preview-text-to-video` para text-to-video, `wan-2.5-preview-image-to-video` para image-to-video                      |
| `prompt`          | string  | Sí                       | -                                                              | Qué generar. Máx. 2500 caracteres                                                                                                                |
| `negative_prompt` | string  | No                       | `"low resolution, error, worst quality, low quality, defects"` | Qué evitar                                                                                                                                       |
| `duration`        | string  | Sí                       | -                                                              | `"5s"` o `"10s"`                                                                                                                                 |
| `resolution`      | string  | No                       | `"720p"`                                                       | `"480p"`, `"720p"` o `"1080p"`                                                                                                                   |
| `aspect_ratio`    | string  | Condicional              | -                                                              | Depende del modelo. Obligatorio para modelos que exponen opciones de aspect ratio; omítelo para modelos que no admiten selección de aspect ratio |
| `audio`           | boolean | Condicional              | `true` (cuando se admite)                                      | Solo válido para modelos con `supportsAudioConfig: true`; omítelo para modelos sin soporte de configuración de audio                             |
| `image_url`       | string  | Solo para image-to-video | -                                                              | URL o data URL en base64 de la imagen fuente                                                                                                     |
| `audio_url`       | string  | Condicional              | -                                                              | URL o data URL en base64 del audio de referencia para modelos que admiten entrada de audio                                                       |

La validación de la cola es específica del modelo. Comprueba `/models?type=video` para ver los campos de solicitud admitidos por cada modelo antes de llamar a `/video/queue`.

### Solicitud Quote

| Parámetro      | Tipo    | Obligatorio | Predeterminado            | Descripción                                                                         |
| -------------- | ------- | ----------- | ------------------------- | ----------------------------------------------------------------------------------- |
| `model`        | string  | Sí          | -                         | ID del modelo para cotizar                                                          |
| `duration`     | string  | Sí          | -                         | `"5s"` o `"10s"`                                                                    |
| `resolution`   | string  | No          | `"720p"`                  | `"480p"`, `"720p"` o `"1080p"`                                                      |
| `aspect_ratio` | string  | Condicional | -                         | Inclúyelo cuando el modelo seleccionado admita o requiera selección de aspect ratio |
| `audio`        | boolean | Condicional | `true` (cuando se admite) | Solo válido para modelos con `supportsAudioConfig: true`                            |

### Solicitud Retrieve

| Parámetro                    | Tipo    | Obligatorio | Predeterminado | Descripción                                    |
| ---------------------------- | ------- | ----------- | -------------- | ---------------------------------------------- |
| `model`                      | string  | Sí          | -              | De la respuesta de la cola                     |
| `queue_id`                   | string  | Sí          | -              | De la respuesta de la cola                     |
| `delete_media_on_completion` | boolean | No          | `false`        | Eliminar el vídeo tras la recuperación exitosa |

### Solicitud Complete

| Parámetro  | Tipo   | Obligatorio | Descripción                |
| ---------- | ------ | ----------- | -------------------------- |
| `model`    | string | Sí          | De la respuesta de la cola |
| `queue_id` | string | Sí          | De la respuesta de la cola |

***

## Imagen a vídeo

Para los modelos image-to-video, pasa la imagen fuente vía `image_url`. El prompt describe el movimiento deseado, no el contenido de la imagen.

```json theme={"system"}
{
  "model": "wan-2.5-preview-image-to-video",
  "prompt": "Camera slowly zooms in as leaves rustle in the wind",
  "image_url": "https://example.com/image.jpg",
  "duration": "5s"
}
```

O con base64:

```json theme={"system"}
{
  "model": "wan-2.5-preview-image-to-video",
  "prompt": "Camera slowly zooms in as leaves rustle in the wind",
  "image_url": "data:image/jpeg;base64,/9j/4AAQ...",
  "duration": "5s"
}
```

***

## Cotización de precio

Obtén el coste exacto antes de generar. Envía solo entradas de precio (`model`, `duration` y los opcionales `resolution`, `aspect_ratio`, `audio`):

**Solicitud:**

```json theme={"system"}
{
  "model": "wan-2.5-preview-text-to-video",
  "duration": "10s",
  "resolution": "1080p"
}
```

**Respuesta:**

```json theme={"system"}
{
  "quote": 0.085
}
```

La cotización es en USD.

***

## Errores

| Estado | Devuelto por                             | Significado                                                                          | Acción                                                                                                                                                                                              |
| ------ | ---------------------------------------- | ------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400    | `queue`, `quote`, `retrieve`, `complete` | Parámetros no válidos                                                                | Verifica el cuerpo de la solicitud contra el schema                                                                                                                                                 |
| 401    | `queue`, `retrieve`, `complete`          | Auth fallida                                                                         | Comprueba la API key                                                                                                                                                                                |
| 402    | `queue`                                  | Saldo insuficiente                                                                   | Añade fondos                                                                                                                                                                                        |
| 404    | `retrieve`, `download_url`               | Media no encontrado (no válido, expirado o eliminado)                                | Verifica `model`/`queue_id` o vuelve a encolar                                                                                                                                                      |
| 410    | `download_url`                           | URL pre-firmada expirada, totalmente usada o revocada (por ejemplo, tras `DELETE`)   | Inicia una nueva generación si necesitas otro archivo; cada enlace es intencionadamente de corta duración                                                                                           |
| 429    | `download_url`                           | Rate-limited — a menudo por muchos reintentos o descargas repetidas del mismo enlace | Termina la descarga (algunos reintentos están bien si la conexión cae), guarda una copia local y usa `DELETE` si quieres limpiar el enlace; mantén el acceso continuado en tu propio almacenamiento |
| 413    | `queue`                                  | Payload demasiado grande                                                             | Reduce el tamaño de imagen/audio                                                                                                                                                                    |
| 422    | `queue`, `retrieve`                      | Infracción de contenido                                                              | Modifica el prompt                                                                                                                                                                                  |
| 500    | `queue`, `retrieve`, `complete`          | Inferencia/procesamiento fallido                                                     | Reintenta con backoff; contacta con soporte si persiste                                                                                                                                             |
| 503    | `retrieve`                               | Modelo a capacidad máxima                                                            | Reintenta con backoff                                                                                                                                                                               |

***

## Estrategia de polling

1. Haz polling de `/video/retrieve` a intervalos (por ejemplo, cada 5 segundos)
2. Si `Content-Type` es `application/json` y `status` es `"PROCESSING"`, espera y vuelve a hacer polling. Usa `average_execution_time` y `execution_duration` (milisegundos) para estimar el tiempo restante
3. Si `Content-Type` es `video/mp4`, guarda el cuerpo de la respuesta como tu archivo de salida
4. Si `Content-Type` es `application/json` y `status` es `"COMPLETED"`, haz `GET` del `download_url` de la respuesta de la cola para obtener el vídeo (consulta [Enlaces de descarga privados](#private-download-links))
5. Si usaste `download_url`, considera hacer `DELETE` en esa URL cuando termines para reducir cuánto existe la URL pre-firmada; después, opcionalmente, establece `delete_media_on_completion: true` en retrieve o llama a `/video/complete` para limpieza basada en cola
6. Gestiona `404` como media no válido, expirado o eliminado; gestiona `500/503` con reintentos/backoff

***

## Modelos disponibles

Consulta [Modelos de vídeo](/models/video) para la lista actual de modelos y precios.
