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:
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):
{
"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:
{
"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.
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í.
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.
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:
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):
{
"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 para saber cómo funcionan estas URLs, los reintentos y el DELETE opcional.
Paso 3: limpieza (opcional)
O auto-eliminar al recuperar:
{
"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:
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):
Ejemplo completo
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})
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.
{
"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:
{
"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:
{
"model": "wan-2.5-preview-text-to-video",
"duration": "10s",
"resolution": "1080p"
}
Respuesta:
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
- Haz polling de
/video/retrieve a intervalos (por ejemplo, cada 5 segundos)
- 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
- Si
Content-Type es video/mp4, guarda el cuerpo de la respuesta como tu archivo de salida
- 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)
- 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
- Gestiona
404 como media no válido, expirado o eliminado; gestiona 500/503 con reintentos/backoff
Modelos disponibles
Consulta Modelos de vídeo para la lista actual de modelos y precios.