HiAPI
Blog

Tutorial

Llamar a la API de texto a vídeo de HappyHorse 1.1 a través de HiAPI: un tutorial funcional con curl + Python

Jun 27, 2026
Llamar a la API de texto a vídeo de HappyHorse 1.1 a través de HiAPI: un tutorial funcional con curl + Python
Modelo
happyhorse-1.1

HappyHorse 1.1 es el modelo de texto a vídeo de Alibaba: admite clips de vídeo en 720p / 1080p, con una duración de 3 a 15 segundos, y genera audio nativo en una sola llamada (sin necesidad de un paso de música independiente). HiAPI expone este modelo a través del mismo endpoint asíncrono unificado que todos los demás modelos generativos, así que si ya has llamado a modelos de imagen en /v1/tasks, lo único que cambia es el id del modelo y algunos campos de input.

Esta página ofrece el mínimo necesario para entregar una integración funcional: el esquema exacto, curl que puedes copiar directamente, un cliente de sondeo en Python y el patrón de callback para producción. También señala dos cosas poco obvias que el modelo no acepta (un interruptor audio y un seed), para que no desperdicies una solicitud por un 400.

Requisitos previos. Obtén una clave desde la consola de HiAPI y expórtala como HIAPI_API_KEY. Cada solicitud se autentica mediante Authorization: Bearer sk-…; si necesitas un repaso, consulta Authentication.

Endpoint y estructura de la solicitud

Todo pasa por el mismo endpoint:

POST https://api.hiapi.ai/v1/tasks
Authorization: Bearer sk-<your-key>
Content-Type: application/json

El cuerpo de la solicitud tiene tres claves de nivel superior:

  • model — happyhorse-1.1/text-to-video (el id del modelo literal — conserva la barra).
  • input — campos específicos del modelo. Para HappyHorse 1.1 T2V:
    • prompt (cadena, obligatorio) — describe el clip de vídeo.
    • resolution (720p | 1080p, predeterminado 1080p).
    • aspect_ratio (16:9 | 9:16 | 3:4 | 4:3 | 4:5 | 5:4 | 1:1 | 9:21 | 21:9, predeterminado 16:9).
    • duration (entero, 3–15, predeterminado 5). El coste aumenta con los segundos.
  • callback (opcional, objeto) — endpoint HTTPS en callback.url + callback.when: "final". HiAPI enviará exactamente un POST con el resultado final a esa dirección por cada tarea.

Dos cosas que parecen deberían funcionar pero en realidad no:

  • ❌ No existe el campo audio. El audio se genera de forma nativa junto con el vídeo; no hay interruptor. Enviar "audio": true devuelve additional properties 'audio' not allowed.
  • ❌ No existe el campo seed. También devuelve 400. Si necesitas determinismo por lote ahora mismo, genera varias versiones y elige entre ellas — no hay ninguna palanca de seed que ajustar.

Un cuerpo de solicitud mínimo válido:

{
  "model": "happyhorse-1.1/text-to-video",
  "input": {
    "prompt": "A golden retriever running on a beach, slow motion, gentle waves, warm sunset tones",
    "resolution": "1080p",
    "aspect_ratio": "16:9",
    "duration": 5
  }
}

Ejemplo mínimo funcional: curl

Crear la tarea — la respuesta se devuelve de inmediato y solo contiene un taskId:

curl -sS -X POST https://api.hiapi.ai/v1/tasks \
  -H "Authorization: Bearer $HIAPI_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "happyhorse-1.1/text-to-video",
    "input": {
      "prompt": "A snow mountain lake in morning mist, slow camera push-in, warm cinematic light",
      "resolution": "1080p",
      "aspect_ratio": "16:9",
      "duration": 5
    }
  }'
# => {"code":200,"data":{"taskId":"tk-hiapi-01KW3..."},"message":"success"}

Luego sondea hasta llegar a un estado terminal:

TASK_ID=tk-hiapi-01KW3...

curl -sS "https://api.hiapi.ai/v1/tasks/$TASK_ID" \
  -H "Authorization: Bearer $HIAPI_API_KEY"
# while .data.status is "handling", sleep a few seconds and retry.
# On success:
# {
#   "code": 200,
#   "data": {
#     "status": "success",
#     "model": "happyhorse-1.1/text-to-video",
#     "output": [
#       {"type":"video","url":"https://temp.hiapi.ai/.../...-0.mp4","expireAt":1783130616}
#     ],
#     ...
#   }
# }

La URL del mp4 es temporal (expireAt es una marca de tiempo Unix de aproximadamente 7 días después). Descarga y guarda de forma persistente en cuanto la tarea tenga éxito — no enlaces en caliente. Si prefieres que HiAPI gestione el almacenamiento a largo plazo, consulta la documentación de Output Storage para saber cómo promover las salidas de almacenamiento temporal a persistente.

Python: un cliente pequeño con forma de producción

Un cliente real necesita tres cosas: create_task que devuelva el id, wait_task que sondee con una fecha límite y un paso de descarga. Este esqueleto incluye las tres y se acerca al punto de partida de la página del SDK de Python de HiAPI — mantenlo pequeño y amplíalo a partir de ahí.

# pip install requests
import os, time, json, requests

API_BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": f"Bearer {os.environ['HIAPI_API_KEY']}"}


def create_task(prompt: str, *, resolution="1080p", aspect_ratio="16:9", duration=5) -> str:
    body = {
        "model": "happyhorse-1.1/text-to-video",
        "input": {
            "prompt": prompt,
            "resolution": resolution,
            "aspect_ratio": aspect_ratio,
            "duration": duration,
        },
    }
    r = requests.post(API_BASE, headers={**HEADERS, "Content-Type": "application/json"},
                      data=json.dumps(body), timeout=60)
    r.raise_for_status()
    data = r.json()
    if data.get("code") != 200:
        raise RuntimeError(f"create failed: {data}")
    return data["data"]["taskId"]


def wait_task(task_id: str, *, timeout_s: int = 600, poll: int = 5) -> dict:
    deadline = time.time() + timeout_s
    while time.time() < deadline:
        r = requests.get(f"{API_BASE}/{task_id}", headers=HEADERS, timeout=30)
        r.raise_for_status()
        task = r.json().get("data") or {}
        status = task.get("status")
        if status == "success":
            return task
        if status == "fail":
            raise RuntimeError(f"task {task_id} failed: {task.get('error')}")
        time.sleep(poll)
    raise TimeoutError(f"task {task_id} did not finish within {timeout_s}s")


def download(url: str, path: str) -> None:
    with requests.get(url, stream=True, timeout=120) as r:
        r.raise_for_status()
        with open(path, "wb") as f:
            for chunk in r.iter_content(1 << 14):
                f.write(chunk)


if __name__ == "__main__":
    task_id = create_task(
        "A neon street at night after rain, reflections on the ground, "
        "cyberpunk mood, slow pan",
        resolution="720p", aspect_ratio="9:16", duration=5,
    )
    task = wait_task(task_id)
    url = task["output"][0]["url"]
    download(url, "out.mp4")
    print("saved out.mp4")

Algunas consideraciones para producción:

  • Campo de estado. Trata cualquier valor distinto de success o fail como en curso (la plataforma usa actualmente handling).
  • raise_for_status no es suficiente. Para algunos errores de validación, HiAPI devuelve HTTP 200 pero code no es 200 — comprueba siempre también data["code"]. Para integraciones nuevas, lo más común es 401 permission_denied, lo que significa que el token bearer es incorrecto o falta — vuelve a exportar HIAPI_API_KEY y confírmalo en la consola.

Producción: preferir callbacks en lugar de sondeo

Para cualquier escenario más allá de un inicio rápido, proporciona a HiAPI un webhook para que te llame cuando la tarea se complete:

{
  "model": "happyhorse-1.1/text-to-video",
  "input": {
    "prompt": "A snow mountain lake in morning mist, slow camera push-in, warm cinematic light",
    "resolution": "1080p",
    "aspect_ratio": "16:9",
    "duration": 5
  },
  "callback": {
    "url": "https://your-domain.com/hiapi/callback",
    "when": "final"
  }
}

Asegúrate de que tu manejador de callbacks haga lo siguiente:

  • Deduplicar por taskId. Tanto success como fail son estados terminales — tu servicio debe tratar recibir el mismo taskId dos veces como una no-operación (escritura idempotente con clave taskId).
  • Devolver 2xx rápidamente. Pon el trabajo pesado (descargar el mp4, persistir, notificar al usuario) en una cola. El manejador del webhook debe confirmar en pocos segundos.
  • Mantener GET /v1/tasks/:id como respaldo. Si el webhook se pierde (despliegue, fluctuaciones de red), una tarea programada de reconciliación que obtenga por id las tareas atascadas y aplique el mismo manejador es la red de seguridad más sencilla.

Si tienes que elegir un camino: el sondeo es adecuado para scripts puntuales y depuración local, mientras que cualquier lugar con tráfico real debería usar callbacks.

Elegir los parámetros correctos (resolution × aspect_ratio × duration)

Necesidad resolution aspect_ratio duration
Clip vertical corto para redes sociales, coste más bajo 720p 9:16 5
Vista previa cuadrada / bucle de miniatura 720p 1:1 3
Toma narrativa horizontal / anuncio 1080p 16:9 5–8
Clip de imagen principal en pantalla ancha 1080p 21:9 8–12

El coste aumenta con la resolución y la duración — consulta los precios exactos por segundo en Precios de HiAPI. Cuando no estés seguro de los valores correctos, no los rellenes: resolution toma 1080p por defecto, aspect_ratio toma 16:9 por defecto y duration toma 5 por defecto.

Preguntas frecuentes

¿El texto a vídeo de HappyHorse 1.1 tiene un parámetro seed? No. La API rechaza seed con additional properties 'seed' not allowed. Si necesitas varias opciones entre las que elegir, envía varias tareas con el mismo prompt — ejecuciones distintas producirán variaciones de forma natural.

¿Cómo se activa o desactiva el audio? No puedes hacerlo — HappyHorse 1.1 genera la pista de audio de forma nativa en la misma llamada. No hay ningún interruptor audio en el esquema; enviar uno devuelve 400. Si necesitas un clip sin sonido, elimina el audio en posproducción.

¿Cuáles son las duraciones válidas? Un entero de 3 a 15 (segundos). Cualquier valor fuera de ese rango devuelve duration: minimum: got 0, want 3 o duration: maximum: got 20, want 15. Los decimales también se rechazan (el tipo del campo es entero).

¿Qué relaciones de aspecto admite? Nueve: 16:9, 9:16, 3:4, 4:3, 4:5, 5:4, 1:1, 9:21, 21:9. El valor predeterminado es 16:9.

¿Cuánto tiempo sigue siendo válida output[].url? Alrededor de una semana — la respuesta incluye una marca de tiempo Unix expireAt. Descarga el mp4 de inmediato y vuelve a alojarlo (S3, R2, tu CDN), o promuévelo a almacenamiento persistente mediante la API de Output Storage.

¿Y el texto a vídeo desde imagen? HappyHorse 1.1 tiene una variante I2V en el mismo endpoint — consulta HappyHorse 1.1 I2V. La misma autenticación, el mismo ciclo de vida asíncrono, un esquema de input distinto.

¿Dónde está la referencia completa de la API asíncrona? Consulta Create Task para el sobre de la solicitud, Get Task Detail para el endpoint de sondeo y la página del modelo HappyHorse 1.1 T2V para el esquema de entrada canónico. Si empiezas desde cero, Quickstart te guía de principio a fin en tu primera llamada.

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