Tutorial
API de texto para vídeo do PixVerse V6: um exemplo curl e Python que funciona de verdade
- Modelo
- pixverse-v6
Gerar um vídeo no hiapi com pixverse-v6/text-to-video é essencialmente um POST /v1/tasks mais uma rodada de polling — exatamente o mesmo padrão de tarefa assíncrona usado por todos os modelos de geração da plataforma. Este artigo traz exemplos de curl e Python prontos para copiar, os campos de entrada que o endpoint realmente valida e o ciclo de vida da tarefa e as armadilhas que registrei ao executar uma geração de verdade de ponta a ponta.
O que você precisa antes de começar
- Uma API key do hiapi. Crie no console e envie no cabeçalho
Authorization: Bearer sk-<sua key>. O formato do cabeçalho está na documentação de autenticação. - O model id é
pixverse-v6/text-to-video. Mantenha a barra no meio — ela faz parte do id, não é um caminho de URL. - O curl não exige nenhuma instalação; o exemplo em Python usa apenas a biblioteca padrão mais
requests.
O PixVerse V6 texto para vídeo transforma um prompt de texto em um clipe de 1–15 segundos, de 360p a 1080p. Ele segue a interface unificada de tarefas assíncronas: enviar a tarefa → consultar o resultado → baixar o vídeo antes que a URL de saída expire.
Requisição mínima funcional (curl)
Envie a tarefa para POST /v1/tasks:
curl -s -X POST https://api.hiapi.ai/v1/tasks \
-H "Authorization: Bearer sk-<sua key>" \
-H "Content-Type: application/json" \
-d '{
"model": "pixverse-v6/text-to-video",
"input": {
"prompt": "清晨阳光下,一只红色的狐狸小跑着穿过新雪,电影质感,慢动作",
"aspect_ratio": "16:9",
"duration": 5,
"resolution": "720p"
}
}'
A resposta traz um id de tarefa:
{ "code": 200, "data": { "taskId": "tk-hiapi-...." }, "message": "success" }
Depois consulte GET /v1/tasks/<taskId> até que data.status se torne success:
curl -s https://api.hiapi.ai/v1/tasks/tk-hiapi-.... \
-H "Authorization: Bearer sk-<sua key>"
Em caso de sucesso, a URL do vídeo final fica em data.output[0].url:
{
"code": 200,
"data": {
"status": "success",
"storage": "temp",
"output": [
{ "type": "video", "url": "https://temp.hiapi.ai/....mp4", "expireAt": 1793036664 }
]
},
"message": "success"
}
Essa URL de saída é temporária — ela carrega um timestamp expireAt (medido em 7 dias após a geração). Baixe o .mp4 imediatamente e armazene no seu próprio object storage; não faça hotlink direto desse endereço.
O mesmo fluxo (Python)
import time, requests
BASE = "https://api.hiapi.ai/v1/tasks"
HEADERS = {"Authorization": "Bearer sk-<sua key>", "Content-Type": "application/json"}
def create_task():
payload = {
"model": "pixverse-v6/text-to-video",
"input": {
"prompt": "清晨阳光下,一只红色的狐狸小跑着穿过新雪,电影质感,慢动作",
"aspect_ratio": "16:9",
"duration": 5,
"resolution": "720p",
},
}
r = requests.post(BASE, json=payload, headers=HEADERS, timeout=60)
r.raise_for_status()
data = r.json()
task_id = (data.get("data") or {}).get("taskId")
if not task_id:
raise RuntimeError(f"创建失败: {data}")
return task_id
def wait_for(task_id, timeout_s=600):
deadline = time.time() + timeout_s
while time.time() < deadline:
try:
r = requests.get(f"{BASE}/{task_id}", headers=HEADERS, timeout=30)
task = (r.json().get("data") or {})
except requests.RequestException:
time.sleep(5) # 单次网络抖动不该让整个轮询中止
continue
status = task.get("status")
if status == "success":
return task["output"][0]["url"]
if status == "fail":
raise RuntimeError(f"任务失败: {task.get('error')}")
time.sleep(5) # 还在排队/渲染——用同一个 task_id 继续轮询
raise TimeoutError(task_id)
task_id = create_task()
url = wait_for(task_id)
video = requests.get(url, timeout=120).content
open("out.mp4", "wb").write(video)
print("已保存 out.mp4")
O laço de polling só decide com base nos dois estados terminais success e fail — qualquer outro estado simplesmente continua aguardando. Assim, quer o render esteja reportando handling, quer archiving, o código não erra o julgamento. Ponto fundamental: se uma requisição de polling falhar por si só, espere um pouco e consulte novamente com o mesmo task_id já guardado; não reenvie a tarefa — reenviar renderiza de novo e cobra de novo.
Parâmetros que o pixverse-v6/text-to-video realmente valida
Estes são os campos que o endpoint efetivamente aceita. Confirmei cada um enviando um valor ilegal e lendo o erro de validação devolvido por ele mesmo, e cruzei as informações com a documentação do modelo:
| Campo | Tipo | Valores / faixa | Padrão | Descrição |
|---|---|---|---|---|
prompt |
string | 1–2048 bytes UTF-8 (1 caractere chinês = 3 bytes, cerca de 682 caracteres) | — | Obrigatório. |
aspect_ratio |
enum | 16:9, 4:3, 1:1, 3:4, 9:16, 2:3, 3:2, 21:9 |
16:9 |
Note que ele suporta 21:9 (ultrawide) e 2:3/3:2. |
duration |
integer | 1–15 |
5 |
Em segundos, precisa ser um inteiro, não pode ser string. |
resolution |
enum | 360p, 540p, 720p, 1080p |
720p |
Resolução de saída. |
generate_audio |
boolean | true / false |
false |
Se também gera trilha sonora, efeitos sonoros e diálogo; desligado por padrão, é preciso habilitar explicitamente para ter áudio. |
negative_prompt |
string | Até 2048 bytes UTF-8 | — | Opcional; conteúdo que se deseja evitar. |
seed |
integer | Qualquer inteiro | — | Opcional; mesmo seed + mesmo prompt reproduz o mesmo resultado. |
style |
enum | anime, 3d_animation, clay, comic, cyberpunk |
nenhum | Preset de estilo opcional; deixar vazio mantém o estilo natural. |
Se quiser usar callback em vez de polling, no mesmo nível de input também é possível incluir um objeto callback: url (endereço HTTPS de callback) + when (atualmente apenas final, ou seja, callback no estado terminal da tarefa).
Como escrever para produção
- Este é um schema fechado. Qualquer campo fora da tabela acima é rejeitado de imediato, com o erro
invalid input: <root>: additional properties '<campo>' not allowed. Isso na verdade é bom: campos digitados errado ou inventados falham ruidosamente no envio, em vez de serem silenciosamente ignorados. durationé inteiro, diferente de alguns modelos de vídeo da plataforma que aceitam string ("6"). Enviar"5"retornainvalid input: duration: got string, want integer; valores fora da faixa informam diretamente o limite, por exemploduration: maximum: got 999, want 15,duration: minimum: got 0, want 1.- O erro reporta apenas um campo por vez, e o envelope é plano:
{"code":400,"error_code":"INVALID_REQUEST","message":"invalid input: aspect_ratio: value must be one of ..."}. Corrija o campo reportado e reenvie; o próximo campo ilegal (se houver) aparecerá na chamada seguinte. - Quando a tarefa falha, o HTTP continua 200. A informação de falha está em
data.status: "fail"no corpo da resposta; o que se avalia é esse campo status, não o código HTTP. - Polling ou callback? Para scripts leves, polling é o mais simples; para escala, sem manter conexões abertas, use
callback. De qualquer forma, ao obteroutput[0].url, baixe imediatamente — a URL trazexpireAte vira 404 depois de expirar.
Registro do teste real: eu realmente executei uma vez
Este artigo não se limita a sondagens somente leitura — executei o ciclo de vida completo com uma requisição real, registrado a seguir:
- Criação: a requisição acima de 720p / 5 segundos / 16:9 retornou imediatamente
{"code":200,"data":{"taskId":"tk-hiapi-01M5AM..."},"message":"success"}. Note que o taskId é uma string com prefixotk-hiapi-, não um UUID. - Polling: o
data.statusdeGET /v1/tasks/<id>passou porhandling→archiving→success; o clipe de 5 segundos levou cerca de 74 segundos da criação à conclusão. - Saída: no estado terminal,
data.output[0]era{"type":"video","url":"https://temp.hiapi.ai/....mp4","expireAt":...,"artifactId":"...","storage":"temp"}.expireAtmenos o horário de criação dá exatamente 604800 segundos, ou seja, 7 dias. - Artefato: um HEAD naquela URL de saída retornou
content-type: video/mp4e cerca de 2,2 MB, confirmando um arquivo mp4 válido.
Uma correção sobre áudio merece registro separado: sondei alguns nomes de campos adjacentes com valores ilegais — generate_audio retornou got string, want boolean (indicando que é um campo booleano válido), enquanto sound e audio retornaram additional properties not allowed (não existem). Ou seja, o áudio é controlado pelo interruptor generate_audio, com padrão false; a página de preços tem as duas faixas correspondentes, 「Sound On / Sound Off」. Neste teste não ativei generate_audio, então o resultado foi um vídeo sem som.
Não fiz avaliação subjetiva da qualidade visual (neste teste apenas verifiquei o contrato da requisição, o ciclo de vida da tarefa e se o artefato é um mp4 válido); essa parte fica para você julgar após gerar de fato com seus próprios prompts.
Como o custo é calculado
O pixverse-v6/text-to-video cobra por segundo (o fator de cobrança é o próprio duration), então quanto mais longo, mais caro; resolução maior e a ativação de generate_audio na faixa 「Sound On」 aumentam o preço por segundo. As taxas por segundo específicas devem seguir os dados em tempo real da página de preços — dê uma olhada antes de gerar em lote.
Links relacionados
- PixVerse V6 texto para vídeo — página do modelo
- PixVerse V6 texto para vídeo — documentação da API
- Referência das interfaces Criar tarefa e Consultar detalhes da tarefa
- Início rápido e Autenticação
- Quer criar vídeo a partir de uma imagem? Veja PixVerse V6 imagem para vídeo
- Preços
Perguntas frequentes
duration é em segundos ou frames? Segundos — qualquer inteiro entre 1 e 15, padrão 5.
É possível gerar vídeo com som? Sim. Defina generate_audio como true e o modelo gera junto trilha sonora, efeitos sonoros e diálogo; o padrão é false (sem som). Ativar áudio usa a faixa de cobrança mais cara; consulte a página de preços para detalhes.
Qual o tamanho máximo do prompt? O limite é 2048 bytes UTF-8. Um caractere chinês conta 3 bytes, então o teto é cerca de 682 caracteres chineses.
Qual a diferença em relação a imagem para vídeo? Este endpoint (pixverse-v6/text-to-video) parte apenas do prompt de texto. Imagem para vídeo é outro model id, que recebe uma imagem inicial e a anima — use aquele se quiser animar uma imagem existente em vez de gerar do zero.
Por que minha requisição retorna "additional properties not allowed"? Você enviou um campo fora do schema. A entrada aceita apenas prompt, aspect_ratio, duration, resolution, generate_audio, negative_prompt, seed e style.
Artigos relacionados
Ver todos os artigos →-
Tutorial
Como chamar hailuo-2.3-fast/image-to-video pela API HiAPI: curl e Python na prática
A primeira requisição executável do nível rápido e econômico de geração de vídeo a partir de imagem — do ID do modelo ao download do MP4
-
Tutorial
Como chamar hailuo-2.3/text-to-video pela API HiAPI: curl, Python e exemplos de requisição executáveis
-
Tutorial
Usar Kandinsky 6.0 Pro text-to-video na HiAPI: tutorial de curl e Python
Demonstração prática com foco na requisição: montar a chamada de prompt para clipe de vídeo, enviar a requisição, consultar o status de conclusão e baixar o resultado