Tutorial
Cómo usar veo-3.1-lite/image-to-video mediante la API de hiapi
- Modelo
- veo-3.1-lite
Veo 3.1 Lite convierte una sola imagen de referencia más un prompt de texto en un vídeo corto y, en hiapi, se expone a través de la misma API de tareas asíncronas que comparten todos los modelos de la plataforma. Esta guía recorre el flujo de peticiones tal como funciona en la práctica: obtener la clave, llamar a POST /v1/tasks, recuperar el resultado y los detalles que debes tener en cuenta cuando llevas este flujo de un script puntual a un entorno de producción (callbacks, idempotencia, gestión de errores).
Qué vas a construir y qué preparar antes
Envías una URL de imagen y un prompt al modelo veo-3.1-lite/image-to-video y recibes de vuelta una URL .mp4 alojada externamente. Todo se ejecuta a través del endpoint unificado de tareas de hiapi, así que la misma estructura de petición sirve para todos los modelos de vídeo e imagen de la plataforma; solo cambian el id de model y los campos de input.
Antes de empezar:
- Crea una cuenta de hiapi y obtén una clave de API desde el panel de control. La clave tiene el formato
sk-.... - Prepara una URL de imagen accesible públicamente: la API la descarga en el servidor, así que una ruta
localhosto un bucket privado no funcionarán. - Antes de ejecutar peticiones reales (no de prueba), consulta el precio actual de
veo-3.1-lite/image-to-videoen la página de precios, ya que el coste depende de la duración y la resolución.
No hay capa gratuita ni modo sin clave: cada llamada requiere Authorization: Bearer sk-<your-key>.
Ejemplo mínimo funcional
La API de tareas de hiapi son dos llamadas: crear la tarea y luego o bien consultarla repetidamente, o bien dejar que un callback te avise cuando termine. A continuación tienes la versión con sondeo en Python, que solo usa requests y time:
import time
import requests
API_KEY = "sk-your-key-here"
BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}
payload = {
"model": "veo-3.1-lite/image-to-video",
"input": {
"prompt": "the camera slowly pushes in as steam rises from the cup",
"image_url": "https://example.com/your-reference-image.jpg",
"duration": 6,
"aspect_ratio": "16:9",
},
}
# 1. Create the task
resp = requests.post(BASE, headers=HEADERS, json=payload, timeout=60)
resp.raise_for_status()
task_id = resp.json()["data"]["taskId"]
print("task created:", task_id)
# 2. Poll until it's done
while True:
task = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=30).json()["data"]
status = task["status"]
if status == "success":
video_url = task["output"][0]["url"]
print("done:", video_url)
break
if status == "fail":
raise RuntimeError(task.get("error"))
time.sleep(5)
Si solo quieres ver el formato que viaja por la red, aquí tienes la misma operación en curl sin procesar:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-your-key-here" \
-H "Content-Type: application/json" \
-d '{
"model": "veo-3.1-lite/image-to-video",
"input": {
"prompt": "the camera slowly pushes in as steam rises from the cup",
"image_url": "https://example.com/your-reference-image.jpg",
"duration": 6,
"aspect_ratio": "16:9"
}
}'
# then poll:
curl -s https://api.hiapi.ai/v1/tasks/<taskId> \
-H "Authorization: Bearer sk-your-key-here"
Hay algunos detalles del esquema de input que conviene conocer, porque es más estricto que esos endpoints genéricos que "aceptan cualquier cosa": los campos sobrantes se rechazan directamente en lugar de ignorarse en silencio:
prompteimage_urlson los únicos dos campos obligatorios.image_urlestá en singular: este modelo acepta exactamente una imagen de referencia, no un array.durationsolo acepta4,6u8(segundos); no admite otros enteros.aspect_ratioaceptaauto,16:9o9:16.resolutionacepta720po1080p.- Opcionales adicionales:
seed(entero, para reproducibilidad),generate_audio(booleano),negative_prompt(cadena).
Ten en cuenta que el id del modelo es el id sin prefijo, es decir, veo-3.1-lite/image-to-video: no le añadas ningún prefijo ni espacio de nombres adicional.
Cuando status pasa a "success", el vídeo de salida está en data.output[0].url. Esa URL es temporal (lleva expireAt), así que descárgala o vuelve a alojarla de inmediato en lugar de guardar el enlace directo.
Consideraciones para producción: callbacks, idempotencia y errores
Consultar cada 5 segundos está bien para un script, pero es un desperdicio en un servidor que gestiona muchas tareas a la vez. Para tráfico de producción se recomienda usar callbacks: pasa un objeto callback en la misma petición de creación de tarea y hiapi hará un POST con el resultado final a tu endpoint, en lugar de que tengas que preguntar tú.
payload = {
"model": "veo-3.1-lite/image-to-video",
"input": {
"prompt": "the camera slowly pushes in as steam rises from the cup",
"image_url": "https://example.com/your-reference-image.jpg",
},
"callback": {
"url": "https://yourapp.example.com/hooks/hiapi",
"when": "final",
},
}
La configuración clave aquí es when: "final": indica que solo se te notifica una vez cuando la tarea alcanza un estado terminal (success o fail), y no en cada cambio de estado intermedio. Tu manejador de webhook debe verificar el id de la tarea y luego consultar el registro local de la tarea que creaste al llamar originalmente a POST /v1/tasks.
Idempotencia. Si tu servicio puede reintentar la llamada de creación de tarea (timeouts, entrega al menos una vez, etc.), añade una cabecera Idempotency-Key de hasta 255 bytes:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-your-key-here" \
-H "Idempotency-Key: order-42-veo-submit" \
-H "Content-Type: application/json" \
-d '{...}'
Reintentar con la misma clave bajo la misma cuenta devuelve el taskId original, en lugar de crear una segunda tarea (facturable): puedes lanzarlo con seguridad desde un bucle de reintentos sin cobrar dos veces al cliente.
Sondeo frente a callback, en resumen: para scripts, notebooks o herramientas internas de bajo tráfico, usa sondeo si de todos modos vas a esperar bloqueando el resultado. Para cualquier escenario del lado del servidor y concurrente, usa callbacks: evitan mantener conexiones abiertas y escalan a muchas tareas en curso sin necesidad de ejecutar un bucle de sondeo por tarea.
Gestión de errores. Una clave errónea o revocada devuelve HTTP 401 y error.code: "permission_denied": compruébalo específicamente, en lugar de asumir que cualquier respuesta no 2xx significa que la generación del vídeo falló. Un input mal formado (falta prompt, duration fuera del rango enumerado, campos no reconocidos) devuelve HTTP 400 y error_code: "INVALID_REQUEST", con un mensaje que señala el campo problemático concreto; conviene mostrarlo directamente en tus propios logs en lugar de tragárselo, porque el mensaje te dice exactamente qué corregir. Una vez aceptada la tarea, los fallos del lado de la generación aparecen como status: "fail" y un objeto error en la carga de sondeo/callback: trata el error como reintentable solo si el mensaje indica un problema transitorio del proveedor, no un problema de esquema.
Recursos relacionados
- Documentación del modelo veo-3.1-lite/image-to-video: referencia completa de parámetros de este modelo concreto
- Crear tarea y Obtener detalles de la tarea: los dos endpoints sobre los que se construye esta guía
- Documentación de autenticación: formato de la clave y requisitos de las cabeceras
- Veo 3.1 Image-to-Video: guía de vídeos cortos: explicación de casos de uso si quieres la salida de mayor fidelidad del modelo no lite
- Precios: tarifas actuales por segundo según duración y resolución
Preguntas frecuentes
¿Debo pasar image_url como data URI o base64?
No: image_url debe ser una URL HTTP(S) pública que los servidores de hiapi puedan descargar. Este modelo no acepta imágenes codificadas en base64.
¿Puedo generar un vídeo sin imagen de referencia?
Con veo-3.1-lite/image-to-video no: es un modelo de imagen a vídeo y image_url es obligatorio. Si quieres generación solo a partir de texto, usa un modelo de texto a vídeo; la página del modelo Veo 3.1 no lite enumera sus modos disponibles.
¿Por qué mi petición devuelve 400 aunque envíe todos los campos obligatorios?
Comprueba si hay campos adicionales: el esquema de entrada de este modelo rechaza cualquier cosa que no esté en la lista permitida (prompt, image_url, duration, aspect_ratio, resolution, seed, generate_audio, negative_prompt). El mensaje de error indica el campo exacto que no reconoce.
¿Cuánto tarda realmente la generación? Varía según la duración y la profundidad actual de la cola; por eso lo correcto es sondear a intervalos cortos o usar callbacks, en lugar de suponer un tiempo de espera fijo.
¿Puede tener audio la salida?
Sí, mediante el booleano generate_audio: consulta la documentación del modelo para conocer el valor predeterminado actual y cómo afecta al coste.
¿Qué pasa si mi endpoint de callback está caído cuando la tarea termina?
No dependas solo de que llegue el callback: conserva el taskId que devuelve la llamada de creación y, si no recibes el callback en un plazo razonable, recurre al sondeo con GET /v1/tasks/<id>.
Artículos relacionados
Ver todos los artículos →-
Tutorial
Cómo llamar a hailuo-2.3-fast/image-to-video a través de la API de HiAPI: práctica con curl y Python
La primera solicitud ejecutable del nivel rápido y de bajo coste de imagen a vídeo: del ID del modelo a la descarga del MP4
-
Tutorial
Cómo llamar a hailuo-2.3/text-to-video mediante la API de HiAPI: curl, Python y ejemplos de solicitud ejecutables
-
Tutorial
Uso de Kandinsky 6.0 Pro texto a video en HiAPI: tutorial con curl y Python
Demostración práctica centrada en la solicitud: construir la llamada de prompt a clip de video, enviar la solicitud, sondear el estado de finalización y descargar el resultado