HiAPI
Blogue

Tutorial

Como usar a API de texto para vídeo Ray 3.2: curl, Python e uma requisição pronta para executar

Oct 20, 2026
Como usar a API de texto para vídeo Ray 3.2: curl, Python e uma requisição pronta para executar

Ray 3.2 é um modelo de texto para vídeo no catálogo de modelos da hiapi e, como todos os outros modelos de vídeo, é chamado por meio da API unificada de tarefas assíncronas — o id do modelo é ray-3.2/text-to-video, enviado para POST /v1/tasks. Diferentemente de alguns modelos de vídeo cujo único ajuste é o prompt, o Ray 3.2 oferece três controles de saída realmente utilizáveis — duration, resolution e aspect_ratio — e cada um deles é rigorosamente validado no servidor.

Este guia faz você enviar requisições bem-sucedidas logo na primeira tentativa: o schema de entrada exato (validado em 2026-10-19 contra a API em produção), uma chamada curl pronta para copiar e colar, um script Python completo de envio/consulta/download e os detalhes de produção — callbacks, repetições idempotentes e as respostas de erro que você realmente verá.

O que você vai construir e o que precisa preparar

Objetivo: enviar um prompt de texto, consultar a tarefa e baixar um clipe .mp4 sem áudio (5 ou 10 segundos).

Pré-requisitos:

  • Uma chave de API da hiapi — obtenha no seu console. A chave tem o formato sk-... e vai no cabeçalho Authorization: Bearer. É novo na API de tarefas? Comece pelo Início Rápido.
  • Qualquer cliente HTTP. Mostraremos curl e Python (requests).

A saída do Ray 3.2 é cobrada por clipe, e o preço sobe bastante conforme suas escolhas — consulte as tarifas atuais na página de preços. Enquanto itera nos prompts, comece com 540p / 5 segundos; um clipe de 1080p e 10 segundos pode custar muitas vezes mais que uma renderização de imagem de orçamento modesto, então não deixe seu ciclo de desenvolvimento rodando sempre nas configurações máximas.

O schema de entrada exato (um campo obrigatório, três enums estritos)

Tudo vai dentro de um objeto input. Validado campo a campo contra a API em produção:

Campo Tipo Obrigatório Valores permitidos Valor padrão
prompt string Sim Descrição da cena, até 6000 caracteres —
duration integer Não 5 ou 10 5
resolution string Não 540p, 720p, 1080p 540p
aspect_ratio string Não 16:9, 9:16, 1:1, 4:3, 3:4, 21:9 16:9

Antes de escrever código, três coisas merecem atenção:

  1. duration é um inteiro, não uma string. Envie o número puro — "duration": 5. Isso é o oposto de alguns outros modelos de vídeo da API de tarefas (por exemplo, o hailuo-2.3 exige "duration": "6" como string). Se você portar o corpo da requisição de um modelo para outro, recheque esse campo; é o erro entre modelos mais comum.
  2. Os enums são validados, não truncados. Valores fora da faixa são rejeitados com 400, não silenciosamente arredondados. Não existe 2k, nem 480p, nem 2:1.
  3. Não há prompt_optimizer, seed nem negative_prompt. A composição é controlada inteiramente por aspect_ratio mais o prompt. Se você enviar campos que o schema não reconhece, espere um 400 — o schema de entrada de /v1/tasks varia por modelo, então não presuma que chaves válidas em outro lugar funcionarão aqui.

O que a validação realmente retorna

A seguir, respostas reais do endpoint em produção (valores inválidos enviados de propósito, sem criação de tarefa e sem cobrança):

// 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'"}

O message indica o campo exato e o conjunto exato de valores permitidos — então, se você esquecer um valor de enum, a API avisa. Observe que os 5, 10 de duration não têm aspas (números), enquanto '540p' de resolution é uma string entre aspas: essa diferença de aspas é a pista de qual campo é inteiro.

Exemplo mínimo executável: curl

Criar a tarefa:

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": "Em uma noite chuvosa, uma dançarina de rua gira sob os letreiros de neon, poças refletindo luzes rosa e azul, sua jaqueta ondulando enquanto ela gira, câmera em ângulo baixo circulando ao redor dela, estilo cinematográfico",
      "duration": 5,
      "resolution": "540p",
      "aspect_ratio": "9:16"
    }
  }'

A resposta de criação traz um id de tarefa (truncado):

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

Consulte até chegar a um estado terminal:

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

Enquanto a tarefa está em execução, data.status reporta um estado em andamento. Os dois estados terminais são success e fail. Em caso de sucesso (truncado):

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

Baixe data.output[0].url imediatamente. As URLs de saída são assinadas e expiram — salve os bytes no seu próprio armazenamento em vez de fazer hotlink direto na URL da tarefa. O Ray 3.2 retorna um MP4 sem áudio (sem faixa de áudio), então não espere um fluxo de áudio que nunca virá.

Script Python completo (enviar → consultar → baixar)

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(
    "Um barquinho de papel desce flutuando por uma sarjeta cheia de água da chuva, gotas criam ondulações na superfície, "
    "folhas de outono rodopiam à deriva, câmera baixa rente à água, luz suave de dia 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)")

Instale a dependência com pip install requests, troque a chave e, quando a tarefa terminar, você terá um .mp4 no disco. Tarefas de vídeo levam minutos, não segundos — dê ao seu loop de consulta um prazo generoso (15 minutos no exemplo acima) em vez de presumir que retornará rápido.

Considerações de produção: callbacks, idempotência, erros

Prefira callbacks à consulta por polling

Para qualquer uso além de scripts, registre um webhook na criação da tarefa em vez de fazer polling:

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

Com "when": "final", a hiapi chama seu endpoint uma vez quando a tarefa atinge o estado terminal — sem tráfego de polling e sem perder a notificação de conclusão entre dois intervalos. Seu handler então faz GET /v1/tasks/<id> (ou lê o corpo entregue) para obter output[0].url. O polling continua válido para CLIs e notebooks que não conseguem expor um endpoint HTTPS.

Torne as repetições idempotentes

Persista o taskId no momento em que a chamada de criação retorna. Se seu processo cair no meio da geração, retome consultando o id já armazenado — não recrie a tarefa, ou você pagará por uma segunda renderização. Só recrie se a requisição de criação original em si falhar antes de retornar um id de tarefa. Como o Ray 3.2 é cobrado por clipe e clipes em alta resolução não são baratos, recriar duplicado é um erro de custo concreto, não apenas perda de tempo.

Os erros que você realmente verá

Cada linha abaixo é um formato de resposta em produção validado:

Sintoma Resposta Correção
Chave ausente/inválida 401, aninhado {"error":{"code":"permission_denied","type":"hiapi_error","request_id":"..."}} Verifique o cabeçalho Authorization: Bearer sk-... e se a chave tem permissão de acesso. Informe o request_id ao contatar o suporte.
Valor de enum inválido 400 INVALID_REQUEST, plano {"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: <field>: value must be one of ..."} Leia o campo indicado no message; ele lista o conjunto exato de valores permitidos.
duration enviado como string 400 INVALID_REQUEST Envie o inteiro puro 5 ou 10, não "5".
Id de modelo desconhecido 400, error_code: "MODEL_UNAVAILABLE", "model not available via /v1/tasks" Use estritamente ray-3.2/text-to-video — confira o id canônico na página do modelo.
Id de tarefa errado na consulta 404, plano {"code":404,"data":null,"message":"task not found"} (atenção: não há error_code no 404) O id está errado, ou você consultou com a chave de outra conta.
status: "fail" na consulta Estado terminal da tarefa, detalhes em data.error Leia data.error.code / data.error.message. Tarefas com falha são reembolsadas; sinalizações de política de conteúdo e problemas de capacidade da origem aparecem aqui — para sinalização de conteúdo, tente novamente com um prompt reformulado.

Recursos relacionados

Perguntas frequentes

Qual é o id do modelo e qual endpoint devo chamar? ray-3.2/text-to-video, enviado como model de nível superior para POST https://api.hiapi.ai/v1/tasks, com os parâmetros em input. É assíncrono — você recebe um taskId e depois consulta GET /v1/tasks/<id> (ou registra um callback).

duration é em segundos e por que "5" falha? Os clipes têm 5 ou 10 segundos e o campo é um inteiro: envie 5 ou 10. Uma string entre aspas, ou qualquer outro número como 7, falha com 400 INVALID_REQUEST: duration: value must be one of 5, 10.

Posso definir resolução e proporção? Sim — é exatamente nisso que o Ray 3.2 se diferencia de modelos de vídeo só com prompt. resolution aceita 540p, 720p ou 1080p; aspect_ratio aceita um de 16:9, 9:16, 1:1, 4:3, 3:4, 21:9. Ambos são opcionais (padrões 540p e 16:9) e ambos rejeitam valores fora da faixa com 400.

Quanto custa um clipe? O Ray 3.2 é cobrado por clipe, e a resolução é a maior alavanca — com a mesma duração, um clipe 1080p custa várias vezes o de 540p, e um clipe de 10 segundos custa cerca de três vezes o de 5 segundos. As tarifas mudam, então consulte a página de preços em vez de codificar um número fixo, e faça o protótipo em 540p/5 segundos.

O clipe tem áudio? Não — o texto para vídeo do Ray 3.2 retorna um MP4 sem áudio. Se precisar de som, adicione na pós-produção ou use um modelo de áudio separado.

O Ray 3.2 suporta imagem para vídeo? Sim, como um id de modelo separado na mesma API de tarefas: ray-3.2/image-to-video. O schema de entrada dele é diferente (recebe uma imagem de referência), então investigue antes de reutilizar o corpo desta requisição — veja a página do modelo de imagem para vídeo.

Minha geração está lenta ou parece travada. O que é normal? Tarefas de vídeo levam alguns minutos. Trate data.status não terminal no seu loop de consulta como "continue esperando" — reserve um prazo de 10–15 minutos, ou use callback com "when": "final" para a hiapi notificar você no estado terminal em vez de você adivinhar um intervalo.

Artigos relacionados

Ver todos os artigos →

Comece a criar com artefactos de IA persistentes

Obtenha a sua chave de API e chame modelos de imagem, vídeo e áudio através de uma única API baseada em tasks.

Ler a documentação da API