Documentação
Geração de vídeo
Geração de vídeos a partir de texto e de imagens da família Veo 3.1 do Google. Dois formatos de API: um endpoint síncrono de chamada única que aguarda até o clipe ficar pronto e um par assíncrono de envio e consulta, recomendado para cargas de trabalho de produção.
Endpoints: POST /v1/video/generations (síncrono, apresentado primeiro) e POST /v1/videos + GET /v1/videos/{id} (assíncronos, recomendados para produção). A geração leva de 30 segundos a vários minutos, dependendo do modelo e da duração — no endpoint síncrono, defina um timeout generoso para o cliente (600s é seguro).
Geração de vídeo a partir de texto
Envie um prompt e escolha um modelo. aspect_ratio é opcional.
import requests
resp = requests.post(
"https://api.kunavo.com/v1/video/generations",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "veo-3",
"prompt": "a cinematic dolly-in on a red origami crane unfolding, soft light",
"aspect_ratio": "16:9",
},
timeout=600, # video generation can take minutes
)
print(resp.json()["data"][0]["url"])duration (em segundos) define a duração do clipe nos modelos cobrados por segundo: os modelos Seedance e o Wan 2.7. Os modelos Veo ignoram esse valor; cada clipe do Veo tem 8 segundos e é cobrado por vídeo.
# The models billed per second take a clip length: here 5 seconds of
# Seedance 2. Leave "duration" out and these models make a 5-second clip.
resp = requests.post(
"https://api.kunavo.com/v1/video/generations",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "seedance-2",
"prompt": "a paper crane unfolds into a flock of birds over a city at dawn",
"duration": 5,
"aspect_ratio": "16:9",
},
timeout=600,
)
print(resp.json()["data"][0]["url"])Imagem para vídeo
Adicione um image_url e o Veo o animará — por padrão, a imagem estática se torna o primeiro quadro do vídeo.
# Image-to-video: animate a still image. The source image can be an
# https URL, or inline base64 — Kunavo hosts it for the model automatically.
resp = requests.post(
"https://api.kunavo.com/v1/video/generations",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "veo-3",
"prompt": "the crane gently lifts off the desk",
"image_url": "https://your-cdn.com/source.png",
},
timeout=600,
)
print(resp.json()["data"][0]["url"])image_url aceita uma URL https:// ou um URI base64 data: em linha. O base64 é decodificado e hospedado automaticamente na CDN da Kunavo antes da execução do modelo.Primeiro quadro, último quadro e referências
image_mode controla como o Veo usa a(s) imagem(ns). Envie image_urls (um array) para incluir mais de uma.
frame(padrão) — uma imagem se torna o primeiro quadro; duas imagens se tornam o primeiro e o último quadro, e o Veo gera a transição entre elas.reference— até três imagens atuam como referências de estilo e tema. Elas orientam a aparência, mas nunca aparecem como quadros.
# First + last frame: pass two images and Veo fills in the motion.
resp = requests.post(
"https://api.kunavo.com/v1/video/generations",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "veo-3",
"prompt": "a smooth transition between the two poses",
"image_urls": [
"https://your-cdn.com/first.png",
"https://your-cdn.com/last.png",
],
"image_mode": "frame",
},
timeout=600,
)Enviando um quadro de origem
Quando você só tem um arquivo local, envie-o uma vez por POST /v1/files e reutilize a URL permanente retornada.
# No public URL? Upload the still first, then animate it.
with open("frame.png", "rb") as f:
up = requests.post(
"https://api.kunavo.com/v1/files",
headers={"Authorization": f"Bearer {API_KEY}"},
files={"file": f},
).json()
resp = requests.post(
"https://api.kunavo.com/v1/video/generations",
headers={"Authorization": f"Bearer {API_KEY}"},
json={
"model": "veo-3",
"prompt": "slow push-in, volumetric light",
"image_url": up["url"],
},
timeout=600,
)Parâmetros
| Parâmetro | Tipo | Observações |
|---|---|---|
model | string (obrigatório) | Slug de um modelo de vídeo disponível em /v1/models. |
prompt | string (obrigatório) | Descrição textual da cena. |
image_url | string | Imagem de origem única para geração de vídeo a partir de imagem. URL ou URI data:. |
image_urls | string[] | Várias imagens de origem (Veo). Tem prioridade sobre image_url. |
image_mode | string | Veo: "frame" (padrão — primeiro/ |
duration | int | Duração do clipe em segundos nos modelos cobrados por segundo, 5 quando omitida: o Seedance 2, o Seedance 2 Fast e o Seedance 2.0 Mini aceitam 4–15, o Seedance 2.5 aceita 4–30 e o Wan 2.7 aceita 2–15. Uma duração fora do intervalo de um modelo é rejeitada com um erro 400. O Veo ignora esse valor: cada clipe do Veo tem 8 segundos. |
aspect_ratio | string | Por exemplo: "16:9", "9:16", "1:1". |
resolution | string | Quando o modelo disponibiliza opções — por exemplo, "720p", "1080p". |
input | object | Opção de escape — veja abaixo Raw input. |
Opção de escape para entrada bruta
Nos modelos cobrados por segundo, input é enviado ao provedor upstream exatamente como foi escrito, no lugar da entrada que nosso adaptador criaria. Os modelos Veo o ignoram.
Os campos que definem o preço são a exceção: resolution é sempre enviado como um dos níveis do modelo (o nível padrão quando é omitido ou não corresponde a nenhum deles), e duration deve ser um número inteiro de segundos dentro do intervalo do modelo (qualquer outro valor é rejeitado com um erro 400; 5 é enviado quando é omitido). resolution e duration da própria solicitação não são lidos quando input está definido.
Modelos de vídeo
| Slug | Provedor | Observações |
|---|---|---|
veo-3 | Veo 3.1 Fast — mais rápido e barato que o Quality, com áudio nativo. | |
veo-3-quality | Veo 3.1 Quality — máxima fidelidade. | |
veo-3-lite | Veo 3.1 Lite — opção econômica para prévias. | |
seedance-2-5 | ByteDance | Seedance 2.5 — clipes de até 30s, referências multimodais, cobrança por segundo. |
seedance-2 | ByteDance | Seedance 2 — consistência entre várias tomadas, até 1080p, cobrança por segundo. |
seedance-2-fast | ByteDance | Seedance 2 Fast — opção econômica, até 720p, cobrança por segundo. |
seedance-2-mini | ByteDance | Seedance 2.0 Mini — opção mais econômica, apenas 480p/720p, para rascunhos e alto volume. |
wan-2-7 | Alibaba | Wan 2.7 — geração cinematográfica de vídeos a partir de texto, com cobrança por segundo. |
Consulte sempre /models para ver a lista atualizada e os preços por modelo.
Latência e tempos limite
- A Kunavo consulta a tarefa upstream por até 540 segundos antes de retornar um erro 504.
- Opções Fast (Veo 3.1 Fast / Lite): geralmente de 30 a 90s.
- Opções Quality e durações maiores: de 2 a 5 minutos.
- Defina o timeout do cliente HTTP como pelo menos 600s.
- Em redes instáveis ou clientes móveis, prefira a API assíncrona — o envio retorna em segundos e você consulta o resultado.
API assíncrona (envio + consulta)
Endpoints: POST /v1/videos + GET /v1/videos/{id}. O objeto de tarefa retornado por eles usa os nomes de campos e os valores de status do objeto de vídeo da OpenAI e adiciona output com a URL do clipe. A solicitação é um corpo JSON com os parâmetros acima.
O endpoint síncrono acima mantém uma conexão HTTP aberta por até nove minutos — é conveniente para scripts de chamada única, mas pouco confiável em dispositivos móveis e ineficiente no servidor. O par assíncrono retorna imediatamente um ID vid_*; consulte GET /v1/videos/{id} até que status seja completed ou failed. Os modelos e preços são os mesmos, assim como as URLs arquivadas.
import requests, time
# 1. Submit — returns immediately with a task id. No long-lived connection.
submit = requests.post(
"https://api.kunavo.com/v1/videos",
headers={
"Authorization": f"Bearer {API_KEY}",
# Optional: retrying with the same key inside ~24h returns the
# original task rather than submitting again.
"Idempotency-Key": "my-task-uuid",
},
json={
"model": "veo-3",
"prompt": "a cinematic dolly-in on a red origami crane",
"aspect_ratio": "16:9",
},
timeout=60,
).json()
task_id = submit["id"] # "vid_abc..."
status = submit["status"] # "queued"
# 2. Poll until terminal. Recommended cadence: 5s, backing off to 30s.
while status not in ("completed", "failed"):
time.sleep(5)
r = requests.get(
f"https://api.kunavo.com/v1/videos/{task_id}",
headers={"Authorization": f"Bearer {API_KEY}"},
timeout=30,
).json()
status = r["status"]
if status == "failed":
raise RuntimeError(r["error"]["message"])
print(r["output"]["url"])No SDK da OpenAI, envie esse corpo com client.post e consulte o status com client.get, como mostrado abaixo. O próprio client.videos.create do SDK não funciona aqui: ele aceita apenas os parâmetros do Sora e os envia como um formulário multipart (no SDK Python desde a versão 2.27.0), o que este endpoint rejeita com um erro 400.
import time
from openai import OpenAI
client = OpenAI(api_key=API_KEY, base_url="https://api.kunavo.com/v1")
# The same JSON body, sent with the client's own post().
task = client.post(
"/videos",
body={
"model": "veo-3",
"prompt": "a cinematic dolly-in on a red origami crane",
"aspect_ratio": "16:9",
},
# object hands back the JSON as parsed. Passing dict instead raises
# after the task has been created.
cast_to=object,
options={"headers": {"Idempotency-Key": "my-task-uuid"}},
)
while task["status"] not in ("completed", "failed"):
time.sleep(5)
task = client.get(f"/videos/{task['id']}", cast_to=object)
if task["status"] == "failed":
raise RuntimeError(task["error"]["message"])
print(task["output"]["url"])Formato da resposta
| Campo | Tipo | Observações |
|---|---|---|
id | string | ID da tarefa com o prefixo vid_-. Estável mesmo quando o upstream muda. |
object | string | "video". |
status | string | queued | in_progress | completed | failed. |
model | string | O slug do modelo enviado. |
created_at | int | Segundos Unix em que aceitamos o envio. |
completed_at | int | null | Segundos Unix em que a tarefa terminou — null enquanto estiver pendente. |
expires_at | int | Segundos Unix, 30 dias após o envio: a tarefa pode ser consultada pelo menos até lá. As URLs dos resultados não expiram. |
progress | int | 0–100. Atualmente, informamos 0 até o estado terminal e, então, 100. |
output | object | null | {url, urls[], duration_ |
error | object | null | {code, message} quando falha. |
Cabeçalhos e convenções
Idempotency-Key(opcional, até 128 caracteres) — enviar duas vezes a mesma chave na mesma conta retorna a tarefa original, em vez de criar uma duplicada. Útil para ciclos de repetição.POST /v1/videosretorna 202 Accepted em um novo envio e 200 OK quando uma chave de idempotência encontra e reproduz um resultado anterior.GET /v1/videos/{id}é restrito ao proprietário: consultar uma tarefa pertencente a outra conta retorna 404 — nunca confirmamos a existência de um ID de outra pessoa.- Cadência de consulta recomendada: 5 s, com backoff exponencial até 30 s. As tarefas geralmente são concluídas em 30 s a 5 min, dependendo do modelo e da resolução.
Quando usar cada um
| Síncrono /v1/ | Assíncrono /v1/videos | |
|---|---|---|
| Melhor para | Scripts e notebooks de uso pontual | Produção, dispositivos móveis, tarefas de longa duração |
| Rede | Mantém a conexão aberta por até 9 min | Envie em segundos; consulte no seu ritmo |
| Recuperação de falhas | Perder a resposta = perder a tarefa | Consulte o ID novamente a qualquer momento antes de expires_at |
| Concorrência | Um worker do servidor por chamada | Envia e libera imediatamente |
| Formato da resposta | Formato de /images/ | Formato de /videos da OpenAI |
Resposta e armazenamento
A resposta segue o formato padrão da OpenAI — data[].url. A URL é um link permanente files.kunavo.com: a Kunavo arquiva todos os resultados na própria CDN, então, ao contrário das URLs upstream diretas, ele nunca expira. Todos os clipes também aparecem em /app/assets.