HiAPI
Blogue

Tutorial

API de texto para vídeo do PixVerse V6: um exemplo curl e Python que funciona de verdade

Oct 20, 2026
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" retorna invalid input: duration: got string, want integer; valores fora da faixa informam diretamente o limite, por exemplo duration: 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 obter output[0].url, baixe imediatamente — a URL traz expireAt e 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 prefixo tk-hiapi-, não um UUID.
  • Polling: o data.status de GET /v1/tasks/<id> passou por handling → 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"}. expireAt menos 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/mp4 e 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

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 →

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