Tutorial
Cómo llamar a la API de texto a video de Kling 2.5 Turbo: guía con curl y Python
Qué te ofrece el endpoint kling-2.5-turbo/text-to-video
kling-2.5-turbo/text-to-video es un modelo de texto a video disponible en HiAPI. Le das un prompt de texto y devuelve un video generado. El «turbo» del nombre indica hacia dónde está optimizado: mayor velocidad de respuesta que el nivel de calidad estándar, a costa de perder algo de detalle. Para renderizados de borrador, previsualizaciones de storyboard, clips para redes sociales e iteración creativa, ese intercambio suele ser el correcto.
Antes de escribir la primera línea de código, lo más importante que debes interiorizar es que este es un endpoint asíncrono. La generación de video tarda de segundos a minutos, muy por encima de cualquier timeout HTTP razonable. Por eso la API se divide en dos operaciones:
- Envío: haces POST del prompt y los parámetros y recibes de inmediato un identificador de tarea.
- Sondeo: haces GET repetidamente de la tarea con ese identificador hasta que alcanza un estado terminal y entonces lees el resultado del video desde la carga de respuesta completada.
Si intentas modelarlo como una llamada bloqueante, te encontrarás con timeouts, generaciones duplicadas al reintentar y conexiones reiniciadas bajo carga alta. El patrón de enviar y luego sondear no es una molestia que haya que evitar; es el modelo mental correcto. Todos los ejemplos de código siguientes se construyen en torno a él, y una vez que lo interiorices, el resto de la integración es directo.
También conviene fijar una expectativa: el endpoint tiene estado, pero el estado está en el servidor, no de tu lado. Las tareas existen con independencia de tu conexión HTTP. Tu script puede caerse a mitad del sondeo, reiniciarse y reconectarse a la misma tarea con el ID, siempre que hayas persistido ese ID en algún sitio. Diseña con esta idea desde el principio.
Estructura de la solicitud: prompt, preset rápido y duración flexible
Solo controlas unos pocos campos, pero cada uno afecta de forma sustancial a la tarea. Esto es lo que realmente importa.
Prompt
El prompt es la entrada creativa principal. Trátalo como una descripción de plano, no como una consulta de búsqueda. Los buenos prompts para este modelo suelen incluir:
- Sujeto: quién o qué está en pantalla.
- Acción: qué hace el sujeto durante el clip.
- Cámara: composición y movimiento, por ejemplo
slow dolly in,static wide shot,handheld follow. - Entorno e iluminación: escena, hora del día, ambiente.
- Estilo: si quieres orientar la sensación visual, puedes escribir
cinematic,anime,product photography, etc.
Mantente concreto y pon el sujeto al principio. Los prompts vagos producen movimiento vago, y el nivel turbo amplifica esto porque deja menos margen a la interpretación.
Preset fast/turbo
Esta familia de modelos admite un preset rápido que cambia algo de fineza por latencia. Al activarlo, le dices al backend que priorice la velocidad: el movimiento sigue siendo coherente, pero las texturas finas, las caras pequeñas y los fondos complejos se degradan antes que en la ruta de calidad. Úsalo en tus bucles de iteración para probar variantes de prompt; cuando finalmente renderices el plano principal, considera si la ruta de calidad es un mejor último paso. El preset es un campo de la solicitud, así que es una decisión por tarea, no una configuración global de la cuenta.
Duración flexible
La duración es flexible dentro del rango que admite el modelo, no está fijada a una sola longitud. Una duración mayor implica generar más fotogramas, por lo que el tiempo de finalización es mayor y el coste más alto: la facturación se calcula por segundos de salida. Elige la duración más corta que satisfaga el plano. Un bucle de cinco segundos para una publicación social no necesita la misma longitud que un beat narrativo.
Disciplina con los campos
Establece solo los campos que necesites. Las claves desconocidas o mal escritas son una fuente habitual de errores de configuración silenciosos, así que mantén el cuerpo JSON pequeño, explícito y bajo control de versiones junto con el resto de la configuración del pipeline.
Hacer la solicitud con curl
Cada llamada a HiAPI usa el mismo patrón de autenticación: un token bearer en la cabecera Authorization. Guarda la clave en una variable de entorno para que no aparezca en el historial del shell ni en scripts confirmados.
export HIAPI_API_KEY="your_api_key_here"
Luego envía la tarea. Los nombres exactos de los campos y la ruta del endpoint deben tomarse de la referencia del modelo; la forma siguiente es la canónica:
curl -X POST "https://api.hiapi.ai/v1/video/generations" \
-H "Authorization: Bearer $HIAPI_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kling-2.5-turbo/text-to-video",
"prompt": "A slow dolly-in on a ceramic coffee cup on a wooden table, morning light raking across the surface, steam rising, shallow depth of field, cinematic",
"duration": 5,
"fast": true
}'
Lo que debes esperar recibir no es un video, sino una confirmación que contiene el identificador de la tarea y su estado inicial, normalmente el estado queued o processing, más un campo id. Guarda ese ID; es el asa para todas las operaciones posteriores.
La respuesta mínima se parece a esto:
{
"id": "job_abc123",
"status": "queued",
"model": "kling-2.5-turbo/text-to-video"
}
La llamada de envío debe volver rápido, muy por debajo de un segundo en condiciones normales. Si se cuelga, el problema está en la conectividad o la autenticación, no en el modelo. Si devuelve 401, revisa el formato de la cabecera (el prefijo Bearer importa). Si devuelve 422, tu cuerpo JSON está mal formado o le faltan campos obligatorios.
No añadas -L, reintentos ni timeouts largos a esta llamada. El paso de envío o tiene éxito rápido o falla rápido. Toda la espera ocurre en el bucle de sondeo, que es lo que viene a continuación.
La misma solicitud en Python
La versión en Python es un envoltorio fino sobre el mismo contrato HTTP. Usa requests con una Session compartida para que el pool de conexiones funcione entre el envío y cada sondeo. Envuélvelo en funciones para que el resto de tu código nunca toque HTTP en bruto.
import os
import time
import requests
BASE = "https://api.hiapi.ai/v1"
HEADERS = {
"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}",
"Content-Type": "application/json",
}
session = requests.Session()
def submit_video(prompt: str, duration: int = 5, fast: bool = True) -> str:
body = {
"model": "kling-2.5-turbo/text-to-video",
"prompt": prompt,
"duration": duration,
"fast": fast,
}
resp = session.post(f"{BASE}/video/generations", json=body, headers=HEADERS, timeout=15)
resp.raise_for_status()
return resp.json()["id"]
def poll_video(job_id: str, timeout_s: int = 600, interval_s: float = 3.0) -> dict:
deadline = time.monotonic() + timeout_s
delay = interval_s
while time.monotonic() < deadline:
resp = session.get(f"{BASE}/video/generations/{job_id}", headers=HEADERS, timeout=15)
resp.raise_for_status()
data = resp.json()
status = data.get("status")
if status in ("succeeded", "failed", "cancelled"):
return data
time.sleep(delay)
delay = min(delay * 1.5, 15.0)
raise TimeoutError(f"job {job_id} did not finish in {timeout_s}s")
if __name__ == "__main__":
job = submit_video("A slow dolly-in on a ceramic coffee cup, morning light, steam rising, cinematic")
result = poll_video(job)
print(result)
Hay varios detalles que merece la pena conservar en lugar de recortar: el timeout en cada solicitud, para que un socket atascado no bloquee a tu worker; el backoff exponencial con un límite razonable; y un TimeoutError separado para que quien llama pueda distinguir entre «sigue en ejecución» y «se ha roto».
Si prefieres httpx, la conversión es directa: mismos métodos, URL y cuerpo JSON. La capa de transporte no es la parte interesante; el contrato sí. Antes de empezar a sondear, guarda el job_id en un sitio persistente para que un reinicio no deje huérfana una generación en curso.
Sondear la tarea y leer la respuesta
El bucle de sondeo es donde se concentran la mayoría de los bugs de integración. Tres reglas lo mantienen fiable.
Regla 1: solo los estados terminales terminan el bucle
Verás estados transitorios —queued, processing— y estados terminales como succeeded, failed y cancelled. Solo los estados terminales salen del bucle. No trates una cadena de estado desconocida como éxito ni interrumpas en processing. Registra el estado en cada iteración; cuando algo falle a las dos de la mañana, ese log será tu única evidencia.
Regla 2: backoff, no giro en vacío
Un sondeo fijo de un segundo es un desperdicio para una tarea que tarda un minuto, y con tareas en lote un sondeo agresivo puede tocar los límites de tasa. Empieza con unos dos o tres segundos, multiplica por aproximadamente 1,5 en cada ronda y pon un tope de diez a quince segundos. El total de solicitudes de una tarea de un minuto baja de sesenta a menos de quince, mientras que la latencia de detección en el peor caso sigue siendo solo el valor del tope.
Regla 3: separa el asset de los metadatos
La carga de respuesta completada contiene ambos. El video en sí se entrega como URL (y normalmente con expiración), mientras que todo lo demás —ID de tarea, modelo, duración, estado, tiempo transcurrido— son metadatos sobre cómo lo obtuviste. Lee la URL, descárgala a tiempo y almacénala tú mismo. Las URL de assets generados no son una CDN permanente; trátalas como un traspaso, no como un hogar. Persiste el ID de tarea junto con tu propia copia para poder rastrear cualquier clip hasta la solicitud exacta que lo produjo.
Nota sobre failed
El estado failed es un resultado a nivel de tarea, no un error de transporte. La llamada HTTP tuvo éxito; la generación no. Lee la carga de error: puede indicar un rechazo por políticas de contenido, una combinación de parámetros no admitida o un fallo interno. Reintentar tal cual un rechazo por políticas solo volverá a fallar, así que antes de plantearte reintentar, ramifica según la causa.
Gestionar errores, timeouts y reintentos
Distingue los dos mundos de error y trátalos por separado.
Los errores de nivel de transporte son fallos HTTP: conexiones reiniciadas, respuestas 5xx, límites de tasa 429 y timeouts del cliente. Estos no dicen si la tarea llegó a ejecutarse. Reintenta con backoff exponencial y jitter, y limita el número de intentos.
Los errores a nivel de tarea son estados terminales dentro de una respuesta HTTP exitosa. La tarea se ejecutó y produjo un resultado claro. Reintentar el sondeo no ayuda; si reintentas, es un envío nuevo, y solo si la causa del fallo es transitoria.
Reintentar lo correcto
Esta es la parte sutil. Si tu llamada de envío hace timeout, no sabes si el servidor aceptó la tarea. Reenviar a ciegas puede producir dos generaciones y dos cargos. Un patrón más seguro es hacer idempotente el envío con una clave de solicitud generada por el cliente, que envías como cabecera o campo del cuerpo, de modo que los envíos duplicados devuelvan la tarea original en lugar de iniciar una nueva. Si la superficie de API que usas no lo ofrece, entonces cuando un envío haga timeout, registra el hash del prompt y la duración, y revisa tus tareas recientes antes de reenviar.
Timeouts en cada capa
Establece tres timeouts distintos y no los confundas:
- Timeout por solicitud: corto, por ejemplo de diez a quince segundos. Limita la llamada HTTP individual, no la tarea.
- Fecha límite global de la tarea: el presupuesto en tiempo real de toda la generación. Si se supera, marca la tarea como huérfana, alerta y sigue adelante.
- Timeout de cara al cliente: si un usuario está esperando, decide si transmites el progreso o devuelves al frontend el asa de la tarea.
Estrategia de reintentos práctica
Reintenta 429 y 5xx con backoff y un tope pequeño. Nunca reintentes 400, 401, 403 ni 422: esos son bugs en tu solicitud y repetirlos solo quema cuota. Registra el cuerpo de respuesta de cada fallo; las cargas de error de HiAPI suelen señalar el campo problemático.
Seguridad en lote
Al desplegar muchas tareas en paralelo, añade un límite de concurrencia y retardos de arranque con jitter. Cien envíos simultáneos son un accidente de límite de tasa buscado. Un pool de cinco a diez workers, cada uno sondeando de forma independiente, es mucho más estable y fácil de observar.
Lista de comprobación de producción antes de salir a vivo
Antes de que esto salga del portátil, cierra estas decisiones.
- Timeouts y fechas límite. Cada llamada tiene un timeout por solicitud, hay una fecha límite global de la tarea y una política clara sobre qué ocurre cuando una tarea queda huérfana. Escríbelos como constantes, no como números mágicos.
- Persistencia de IDs. Almacena el
job_idy el hash del prompt antes de que empiece el sondeo. Esta es la clave que hace posibles los reinicios y la auditoría. - Almacenamiento de assets. Al tener éxito, descarga el video completado en tu propio bucket. Nunca envíes al frontend ni a la base de datos una URL que no controlas como referencia permanente.
- Registro de logs. Registra cada transición de estado con ID de tarea, modelo, duración, preset y tiempo transcurrido. Cuando aparezcan dudas de coste o calidad, este es el conjunto de datos que las responde.
- Conciencia de coste. La facturación es por segundos de salida, así que la duración es tu principal palanca de coste. El preset turbo mantiene baja la latencia (y por tanto la ocupación de workers). Haz seguimiento de los segundos generados por funcionalidad para que la conversación sobre costes se base en números reales y no en conjeturas.
- Idempotencia. Usa claves de solicitud generadas por el cliente al enviar y define reglas sobre qué constituye un reenvío seguro.
- UX de fallo. Decide ahora qué ve el usuario cuando una tarea falla a nivel de tarea: un botón de reintentar, un prompt de reserva o un mensaje de texto plano. El giro en vacío silencioso es la peor opción.
- Control de versiones de prompts. Mantén los prompts en configuración, no en línea dentro de los handlers, para que puedas comparar salidas de distintas variantes sin volver a desplegar.
El endpoint en sí es pequeño: un envío, un sondeo. Casi todo el esfuerzo de ingeniería está en el ciclo de vida que lo rodea, y ahí es donde se decide la calidad de producción. Empieza por la referencia del modelo kling-2.5-turbo/text-to-video en HiAPI y luego construye a su alrededor el andamiaje aquí descrito.
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