HiAPI
Blog

Tutorial

Cómo usar la API de texto a vídeo de Ray 3.2: curl, Python y una solicitud lista para ejecutar

Oct 20, 2026
Cómo usar la API de texto a vídeo de Ray 3.2: curl, Python y una solicitud lista para ejecutar

Ray 3.2 es un modelo de texto a vídeo del catálogo de modelos de hiapi y, como todos los demás modelos de vídeo, se invoca mediante la API unificada de tareas asíncronas: el id del modelo es ray-3.2/text-to-video y se envía a POST /v1/tasks. A diferencia de algunos modelos de vídeo cuyo único parámetro ajustable es el prompt, Ray 3.2 ofrece tres controles de salida realmente utilizables —duration, resolution y aspect_ratio— y cada uno de ellos se valida estrictamente en el servidor.

Esta guía te permite enviar solicitudes que funcionen a la primera: el esquema de entrada exacto (verificado contra la API en producción el 2026-10-19), una llamada curl que puedes copiar y pegar, un script completo de Python para enviar, consultar y descargar, y detalles para producción —callbacks, reintentos idempotentes y las respuestas de error que realmente verás.

Qué vas a construir y qué necesitas

Objetivo: enviar un prompt de texto, consultar la tarea y descargar un clip .mp4 sin audio (de 5 o 10 segundos).

Requisitos previos:

  • Una clave de API de hiapi — obtenla desde tu consola. La clave tiene la forma sk-... y se coloca en la cabecera Authorization: Bearer. ¿Es tu primera vez con la API de tareas? Empieza por la guía de inicio rápido.
  • Cualquier cliente HTTP. Mostraremos curl y Python (requests).

La salida de Ray 3.2 se cobra por clip, y el precio aumenta considerablemente según tus elecciones — consulta las tarifas actuales en la página de precios. Mientras iteres con prompts, empieza con 540p / 5 segundos; un clip de 1080p y 10 segundos puede costar muchas veces más que una renderización de imagen de presupuesto ajustado, así que no dejes tu ciclo de desarrollo funcionando siempre con los ajustes más altos.

El esquema de entrada exacto (un campo obligatorio, tres enumeraciones estrictas)

Todo va dentro de un objeto input. Verificado campo por campo contra la API en producción:

Campo Tipo Obligatorio Valores permitidos Valor predeterminado
prompt string Sí Descripción de la escena, hasta 6000 caracteres —
duration integer No 5 o 10 5
resolution string No 540p, 720p, 1080p 540p
aspect_ratio string No 16:9, 9:16, 1:1, 4:3, 3:4, 21:9 16:9

Antes de escribir código, hay tres cosas que conviene tener presentes:

  1. duration es un entero, no una cadena. Envía el número sin comillas — "duration": 5. Esto es lo contrario de lo que ocurre con otros modelos de vídeo de la API de tareas (por ejemplo, hailuo-2.3 exige "duration": "6" como cadena). Si trasladas un cuerpo de solicitud de un modelo a otro, vuelve a revisar este campo; es el error entre modelos más frecuente.
  2. Los valores de enumeración se validan, no se truncan. Los valores fuera de rango se rechazan con 400 en lugar de redondearse silenciosamente. No existe 2k, ni 480p, ni 2:1.
  3. No hay prompt_optimizer, seed ni negative_prompt. La composición se controla exclusivamente mediante aspect_ratio más el prompt. Si envías campos que el esquema no reconoce, espera recibir un 400 — el esquema de entrada de /v1/tasks varía según el modelo, así que no supongas que las claves que funcionan en otro sitio sirven aquí.

Qué devuelve realmente la validación

A continuación se muestran respuestas reales del endpoint en producción (se enviaron valores no válidos a propósito; no se creó ninguna tarea ni se facturó nada):

// POST with "resolution": "2k"
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
 "message":"invalid input: resolution: value must be one of '540p', '720p', '1080p'"}

// POST with "duration": 7
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
 "message":"invalid input: duration: value must be one of 5, 10"}

// POST with "aspect_ratio": "2:1"
{"code":400,"data":null,"error_code":"INVALID_REQUEST",
 "message":"invalid input: aspect_ratio: value must be one of '16:9', '9:16', '1:1', '4:3', '3:4', '21:9'"}

El message indica el campo exacto y el conjunto exacto de valores permitidos, así que si olvidas algún valor de enumeración, la API te lo dirá. Fíjate en que los valores de duration 5, 10 no llevan comillas (son números), mientras que el valor de resolution '540p' es una cadena entre comillas: esa diferencia de comillas es la pista de qué campo es entero.

Ejemplo mínimo funcional: curl

Crear la tarea:

curl -s -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer sk-YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "ray-3.2/text-to-video",
    "input": {
      "prompt": "En una noche lluviosa, una bailarina callejera gira bajo las luces de neón, los charcos reflejan luces rosas y azules, su chaqueta ondea al girar, la cámara la rodea en ángulo bajo, estilo cinematográfico",
      "duration": 5,
      "resolution": "540p",
      "aspect_ratio": "9:16"
    }
  }'

La respuesta de creación incluye un id de tarea (truncado):

{ "data": { "taskId": "task_01k..." } }

Consúltala hasta que alcance un estado terminal:

curl -s https://api.hiapi.ai/v1/tasks/task_01k... \
  -H "Authorization: Bearer sk-YOUR_KEY"

Mientras la tarea se ejecuta, data.status informa de un estado en curso. Los dos estados terminales son success y fail. En caso de éxito (truncado):

{
  "data": {
    "taskId": "task_01k...",
    "status": "success",
    "output": [ { "url": "https://.../clip.mp4" } ]
  }
}

Descarga data.output[0].url de inmediato. Las URL de salida son firmadas y caducan; guarda los bytes en tu propio almacenamiento en lugar de enlazar directamente la URL de la tarea. Ray 3.2 devuelve un MP4 sin audio (sin pista de sonido), así que no esperes un flujo de audio que nunca llegará.

Script completo de Python (enviar → consultar → descargar)

import time
import requests

API_BASE = "https://api.hiapi.ai/v1"
API_KEY = "sk-YOUR_KEY"
HEADERS = {"Authorization": f"Bearer {API_KEY}", "Content-Type": "application/json"}


def create_task(prompt: str, duration: int = 5,
                resolution: str = "540p", aspect_ratio: str = "9:16") -> str:
    resp = requests.post(
        f"{API_BASE}/tasks",
        headers=HEADERS,
        json={
            "model": "ray-3.2/text-to-video",
            "input": {
                "prompt": prompt,
                "duration": duration,          # 5 or 10 — an INTEGER, not a string
                "resolution": resolution,      # "540p" | "720p" | "1080p"
                "aspect_ratio": aspect_ratio,  # "16:9" | "9:16" | "1:1" | "4:3" | "3:4" | "21:9"
            },
        },
        timeout=30,
    )
    resp.raise_for_status()
    return resp.json()["data"]["taskId"]


def wait_task(task_id: str, timeout_s: int = 900, poll_interval: int = 5) -> dict:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        resp = requests.get(f"{API_BASE}/tasks/{task_id}", headers=HEADERS, timeout=30)
        resp.raise_for_status()
        task = resp.json()["data"]
        if task["status"] == "success":
            return task
        if task["status"] == "fail":
            err = task.get("error") or {}
            raise RuntimeError(f"task failed: {err.get('code')}: {err.get('message')}")
        time.sleep(poll_interval)  # any non-terminal status = still running
    raise TimeoutError(f"task {task_id} not finished after {timeout_s}s")


task_id = create_task(
    "Un barco de papel flota por un desagüe lleno de agua de lluvia, las gotas formsan ondas en la superficie, "
    "hojas de otoño giran y pasan flotando, cámara a baja altura cerca del agua, luz suave de día nublado"
)
print("task created:", task_id)

task = wait_task(task_id)
video_url = task["output"][0]["url"]

# Output URLs expire — download right away and store the bytes yourself.
video = requests.get(video_url, timeout=120).content
with open("ray32-clip.mp4", "wb") as f:
    f.write(video)
print(f"saved ray32-clip.mp4 ({len(video) / 1e6:.1f} MB)")

Instala la dependencia con pip install requests, pon tu clave y tendrás un .mp4 en disco cuando termine la tarea. Las tareas de vídeo tardan minutos, no segundos — da a tu bucle de consulta un plazo generoso (en el ejemplo, 15 minutos) en lugar de suponer que responderá rápido.

Consideraciones para producción: callbacks, idempotencia y errores

Prefiere callbacks en lugar de consultas periódicas

Para cualquier uso que no sea un script, registra un webhook al crear la tarea en lugar de consultar periódicamente:

{
  "model": "ray-3.2/text-to-video",
  "input": { "prompt": "...", "duration": 10, "resolution": "720p" },
  "callback": { "url": "https://your-app.example.com/hooks/hiapi", "when": "final" }
}

Con "when": "final", hiapi llamará a tu endpoint una vez cuando la tarea alcance un estado terminal — sin tráfico de consultas ni notificaciones de finalización perdidas entre dos intervalos. Tu manejador ejecuta después GET /v1/tasks/<id> (o lee el cuerpo de la respuesta entregada) para obtener output[0].url. Las consultas periódicas siguen siendo válidas para CLI y notebooks que no pueden exponer un endpoint HTTPS.

Haz que los reintentos sean idempotentes

Persiste taskId en el momento en que la llamada de creación devuelve la respuesta. Si tu proceso falla a mitad de la generación, recupéralo consultando el id almacenado — no vuelvas a crear la tarea, o pagarás por una segunda renderización. Vuelve a crearla solo si la solicitud de creación original falló antes de devolver el id de tarea. Como Ray 3.2 se cobra por clip y los clips en alta resolución no son baratos, duplicar la creación es un error de coste real, no solo una pérdida de tiempo.

Errores que realmente verás

Cada fila de la siguiente tabla es una forma de respuesta verificada en producción:

Síntoma Respuesta Solución
Clave ausente/no válida 401, anidado {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"..."}} Comprueba la cabecera Authorization: Bearer sk-... y que la clave tenga permiso de acceso. Proporciona el request_id al contactar con soporte.
Valor de enumeración incorrecto 400 INVALID_REQUEST, plano {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: <field>: value must be one of ..."} Lee el campo indicado en message; enumera el conjunto exacto de valores permitidos.
duration enviado como cadena 400 INVALID_REQUEST Envía el entero sin comillas 5 o 10, no "5".
Id de modelo desconocido 400, error_code: "MODEL_UNAVAILABLE", "model not available via /v1/tasks" Usa exactamente ray-3.2/text-to-video — consulta el id canónico en la página del modelo.
Id de tarea incorrecto al consultar 404, plano {"code":404,"data":null,"message":"task not found"} (nota: en 404 no hay error_code) El id es incorrecto, o consultaste con la clave de otra cuenta.
status: "fail" al consultar Estado terminal de la tarea, con detalles en data.error Lee data.error.code / data.error.message. Las tareas fallidas se reembolsan; aquí aparecen las marcas de políticas de contenido y los problemas de capacidad del proveedor — para marcas de contenido, reintenta con un prompt reformulado.

Recursos relacionados

Preguntas frecuentes

¿Cuál es el id del modelo y qué endpoint debo llamar? ray-3.2/text-to-video, enviado como model de nivel superior a POST https://api.hiapi.ai/v1/tasks, con los parámetros bajo input. Es asíncrono — recibirás un taskId y luego consultarás GET /v1/tasks/<id> (o registrarás un callback).

¿duration está en segundos y por qué falla "5"? Los clips duran 5 o 10 segundos, y el campo es un entero: envía 5 o 10. Una cadena entre comillas, o cualquier otro número como 7, falla con 400 INVALID_REQUEST: duration: value must be one of 5, 10.

¿Puedo establecer la resolución y la relación de aspecto? Sí — precisamente en esto se diferencia Ray 3.2 de los modelos de vídeo que solo admiten prompt. resolution es 540p, 720p o 1080p; aspect_ratio es uno de 16:9, 9:16, 1:1, 4:3, 3:4, 21:9. Ambos son opcionales (por defecto 540p y 16:9) y ambos rechazan los valores fuera de rango con un 400.

¿Cuánto cuesta un clip? Ray 3.2 se cobra por clip, y la resolución es la palanca más importante — con la misma duración, un clip en 1080p cuesta varias veces más que uno en 540p, y un clip de 10 segundos cuesta aproximadamente tres veces más que uno de 5 segundos. Las tarifas cambian, así que consulta la página de precios en lugar de codificar un número fijo, y haz prototipos en 540p/5 segundos.

¿Los clips tienen audio? No — el texto a vídeo de Ray 3.2 devuelve un MP4 sin audio. Si necesitas sonido, añádelo en posproducción o usa un modelo de audio aparte.

¿Ray 3.2 admite imagen a vídeo? Sí, como un id de modelo independiente en la misma API de tareas: ray-3.2/image-to-video. Su esquema de entrada es distinto (recibe una imagen de referencia), así que sondea antes de reutilizar este cuerpo de solicitud — consulta la página del modelo de imagen a vídeo.

Mi generación va lenta o parece atascada. ¿Qué es normal? Las tareas de vídeo tardan varios minutos. Mantén los valores no terminales de data.status en tu bucle de consulta y espera — reserva un plazo de 10–15 minutos, o usa un callback con "when": "final" para que hiapi te notifique en el estado terminal en lugar de que tú adivines un intervalo.

Artículos relacionados

Ver todos los artículos →

Empieza a crear con artefactos de IA persistentes

Consigue tu API key y llama a modelos de imagen, vídeo y audio a través de una única API basada en tasks.

Leer la documentación de la API