API v1
Documentação da API Cheaper Veo
Gere vídeos com Veo 3.1 via HTTP. Pay as you go, sem mensalidade, créditos pré-pagos. Esta referência cobre autenticação, geração, polling de status, modelos disponíveis e tratamento de erros.
Cole no Claude / ChatGPT / Cursor e integre em segundos
Copie o prompt abaixo, cole no seu LLM de código e ele vai scaffoldar o cliente, escrever a integração e wire up no seu stack — Node ou Python — automaticamente.
Integrate Cheaper Veo into this project. The full API spec, types, error handling, and drop-in clients (Node.js + Python) are at: https://cheapervideo.com/llms.txt Fetch that file, follow the integration agent instructions, and wire up at least one working example using my existing stack. Add CHEAPER_VEO_API_KEY to .env. After you're done, tell me where to get an API key.
Introdução
A API Cheaper Veo é uma camada HTTP fina sobre o Google Veo 3.1. Você envia um prompt (e opcionalmente imagens de referência), recebe um taskId imediato e faz polling até o vídeo ficar pronto. Em três passos:
- Autenticar: envie sua chave no header
Authorization: Bearer veo_live_…. - Gerar:
POST /api/v1/generatecom o body do tipo desejado (text-to-video, image-to-video ou references). A resposta contém otaskIde o custo em créditos já debitado. - Aguardar:
GET /api/v1/status/{taskId}a cada 5–10 segundos até o status virarsucceeded. O campovideoUrlaponta para o MP4 final.
Base URL
Produção: https://api.geraew.com
Desenvolvimento: http://localhost:3000
Quickstart
Do zero ao primeiro vídeo em 3 passos. Total: ~2 minutos.
- 1
Crie uma API key
Acesse Painel → API Keys e clique em Gerar nova chave. A chave (formato
veo_live_…) é exibida apenas uma vez — copie pra um cofre de segredos. - 2
Teste o saldo
Confirma que a chave tá funcionando antes de gerar nada (não consome crédito):
bashcurl https://api.geraew.com/api/v1/account \ -H "Authorization: Bearer veo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"Resposta deve mostrar seu email e
balanceem créditos. Se receber401, a chave está errada ou foi revogada. - 3
Gere e aguarde
Vídeo barato pra testar (Lite 720p sem áudio, 4s = 5 créditos = US$0,05):
bash# Inicia geração — retorna taskId imediato curl -X POST https://api.geraew.com/api/v1/generate \ -H "Authorization: Bearer veo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "kind": "text_to_video", "modelId": "veo3-lite", "prompt": "a calm wave breaking on a beach at sunset", "resolution": "720p", "aspectRatio": "16:9", "durationSeconds": 4, "audio": false }' # Resposta: { "taskId": "tsk_01HYAB…", "status": "pending", … } # Pega o taskId acima e faz polling a cada 5s curl https://api.geraew.com/api/v1/status/tsk_01HYAB… \ -H "Authorization: Bearer veo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"Quando
statusvirarsucceeded, o campovideoUrltraz o MP4 final.
Autenticação
Toda requisição precisa do header Authorization: Bearer veo_live_…. As chaves começam com veo_live_ e são geradas em Painel → API keys. A chave é exibida apenas uma vez no momento da criação — guarde-a num cofre de segredos.
Authorization: Bearer veo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx
Content-Type: application/jsonSe a chave for inválida, revogada ou estiver ausente, a API responde 401 UNAUTHORIZED. Nunca exponha a chave em código client-side: faça as chamadas a partir do seu backend.
Geração de vídeo
POST /api/v1/generate aceita um body discriminado pelo campo kind. O caso mais comum é text_to_video. A chamada retorna imediatamente com taskId, status e o custo em créditos.
Body
{
"kind": "text_to_video",
"modelId": "veo3-lite | veo3-fast | veo3-quality",
"prompt": "string (1-8000 chars)",
"resolution": "720p | 1080p | 4k",
"aspectRatio": "16:9 | 9:16",
"durationSeconds": 4 | 6 | 8,
"audio": true,
"negativePrompt": "string (opcional, max 2000 chars)"
}Atenção: o campo é modelId (não model) na requisição. Restrições: veo3-lite só suporta 720p/1080p (sem 4K). 1080p e 4k exigem durationSeconds: 8.
Resposta
HTTP 202 Accepted — créditos já debitados, geração enfileirada. Note que a resposta usa model (sem o "Id"):
{
"taskId": "tsk_01HYABCDEF…",
"status": "pending",
"creditsCost": 30,
"model": "veo3-fast",
"durationSeconds": 8
}cURL
curl -X POST https://api.geraew.com/api/v1/generate \
-H "Authorization: Bearer veo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"kind": "text_to_video",
"modelId": "veo3-fast",
"prompt": "drone shot over neon-lit Tokyo at night, cinematic",
"resolution": "1080p",
"aspectRatio": "16:9",
"durationSeconds": 8,
"audio": true
}'Node.js
const res = await fetch("https://api.geraew.com/api/v1/generate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CHEAPER_VEO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
kind: "text_to_video",
modelId: "veo3-fast",
prompt: "drone shot over neon-lit Tokyo at night, cinematic",
resolution: "1080p",
aspectRatio: "16:9",
durationSeconds: 8,
audio: true,
}),
});
const data = await res.json();
console.log(data.taskId, data.creditsCost);Python
import os
import requests
res = requests.post(
"https://api.geraew.com/api/v1/generate",
headers={
"Authorization": f"Bearer {os.environ['CHEAPER_VEO_API_KEY']}",
"Content-Type": "application/json",
},
json={
"kind": "text_to_video",
"modelId": "veo3-fast",
"prompt": "drone shot over neon-lit Tokyo at night, cinematic",
"resolution": "1080p",
"aspectRatio": "16:9",
"durationSeconds": 8,
"audio": True,
},
timeout=30,
)
data = res.json()
print(data["taskId"], data["creditsCost"])Image-to-video
Use kind: "image_to_video" para animar a partir de um quadro inicial. Envie a imagem em base64 com firstFrame. O campo opcional lastFrame (suportado apenas em veo3-quality) define o quadro final, fazendo a interpolação entre os dois.
Formato do objeto de imagem
Toda imagem (em firstFrame, lastFrame ou referenceImages[]) segue o mesmo schema:
{
"bytesBase64Encoded": "base64_encoded_image_data_here",
"mimeType": "image/jpeg"
}bytesBase64Encoded(obrigatório): string base64 sem o prefixodata:. Limite ~10MB decodificado.mimeType(opcional, padrãoimage/jpeg):image/png,image/jpegouimage/webp.
curl -X POST https://api.geraew.com/api/v1/generate \
-H "Authorization: Bearer veo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"kind": "image_to_video",
"modelId": "veo3-quality",
"prompt": "the character starts walking towards the camera",
"resolution": "1080p",
"aspectRatio": "16:9",
"durationSeconds": 8,
"audio": true,
"firstFrame": {
"bytesBase64Encoded": "iVBORw0KGgoAAAANS...",
"mimeType": "image/png"
}
}'import { readFile } from "node:fs/promises";
const firstFrame = await readFile("./first.png");
const lastFrame = await readFile("./last.png");
const res = await fetch("https://api.geraew.com/api/v1/generate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.CHEAPER_VEO_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
kind: "image_to_video",
modelId: "veo3-quality",
prompt: "the character starts walking towards the camera",
resolution: "1080p",
aspectRatio: "16:9",
durationSeconds: 8,
audio: true,
firstFrame: {
bytesBase64Encoded: firstFrame.toString("base64"),
mimeType: "image/png",
},
// lastFrame is only accepted on veo3-quality
lastFrame: {
bytesBase64Encoded: lastFrame.toString("base64"),
mimeType: "image/png",
},
}),
});Vídeo com referências
Use kind: "references" para guiar o estilo, personagem ou produto através de 1 a 3 imagens de referência. Cada item do array referenceImages aceita base64, mimeType e referenceType (atualmente apenas asset).
curl -X POST https://api.geraew.com/api/v1/generate \
-H "Authorization: Bearer veo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx" \
-H "Content-Type: application/json" \
-d '{
"kind": "references",
"modelId": "veo3-fast",
"prompt": "the product floats slowly while rotating, studio lighting",
"resolution": "1080p",
"aspectRatio": "9:16",
"durationSeconds": 8,
"audio": false,
"referenceImages": [
{ "bytesBase64Encoded": "iVBORw0KGgo...", "mimeType": "image/png", "referenceType": "asset" },
{ "bytesBase64Encoded": "iVBORw0KGgo...", "mimeType": "image/png", "referenceType": "asset" }
]
}'Polling de status
GET /api/v1/status/{taskId} retorna o estado atual da tarefa. Os possíveis valores de status são:
pending— fila inicial, ainda não enviado ao provider.processing— Veo está gerando.succeeded— pronto. UsevideoUrlpara baixar.failed— falha definitiva sem reembolso (entrada inválida, content policy, etc).refunded— falha de upstream; os créditos já voltaram para sua conta.
Recomendado: intervalo de 5 a 10 segundos entre chamadas. Não consulte com mais frequência: vai apenas consumir rate limit sem acelerar a geração. Tempos típicos: lite/fast em 1–3 minutos, quality em 2–5 minutos.
Resposta
{
"taskId": "tsk_01HYABCDEF…",
"status": "succeeded",
"model": "veo3-fast",
"creditsCost": 30,
"videoUrl": "https://cdn.cheapervideo.com/v/tsk_01HYABCDEF.mp4",
"createdAt": "2026-05-08T12:34:56.000Z",
"completedAt": "2026-05-08T12:36:11.000Z"
}Node.js
async function waitForVideo(taskId: string): Promise<string> {
const apiKey = process.env.CHEAPER_VEO_API_KEY!;
for (;;) {
const res = await fetch(`https://api.geraew.com/api/v1/status/${taskId}`, {
headers: { Authorization: `Bearer ${apiKey}` },
});
// Respect rate limits: if 429, sleep for Retry-After then retry.
if (res.status === 429) {
const retry = Number(res.headers.get("Retry-After") ?? "5");
await new Promise((r) => setTimeout(r, retry * 1000));
continue;
}
const job = await res.json();
if (job.status === "succeeded") return job.videoUrl as string;
if (job.status === "failed" || job.status === "refunded") {
throw new Error(job.error?.message ?? "generation failed");
}
// pending | processing — wait 5s before next call
await new Promise((r) => setTimeout(r, 5000));
}
}Python
import os
import time
import requests
def wait_for_video(task_id: str) -> str:
api_key = os.environ["CHEAPER_VEO_API_KEY"]
headers = {"Authorization": f"Bearer {api_key}"}
while True:
res = requests.get(
f"https://api.geraew.com/api/v1/status/{task_id}",
headers=headers,
timeout=15,
)
# Respect rate limits
if res.status_code == 429:
retry = int(res.headers.get("Retry-After", "5"))
time.sleep(retry)
continue
job = res.json()
if job["status"] == "succeeded":
return job["videoUrl"]
if job["status"] in ("failed", "refunded"):
raise RuntimeError(job.get("error", {}).get("message", "generation failed"))
time.sleep(5)Conta & saldo
GET /api/v1/account retorna o saldo atual em créditos e as últimas 10 gerações da conta dona da API key. Útil pra checar saldo antes de chamar /generate e evitar 402 INSUFFICIENT_CREDITS.
Resposta
{
"email": "voce@empresa.com",
"balance": 713,
"recentGenerations": [
{
"taskId": "tsk_01HYABCDEF…",
"kind": "text_to_video",
"model": "veo3-fast",
"status": "succeeded",
"creditsCost": 30,
"durationSeconds": 8,
"resolution": "1080p",
"videoUrl": "https://cdn.cheapervideo.com/v/tsk_01HYABCDEF.mp4",
"createdAt": "2026-05-08T12:34:56.000Z",
"completedAt": "2026-05-08T12:36:11.000Z"
}
]
}cURL
curl -X GET https://api.geraew.com/api/v1/account \
-H "Authorization: Bearer veo_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx"balance está em créditos — divida por 100 pra ter o equivalente em USD (1 crédito = US$ 0,01).
Modelos e preços
Tabela de custo para vídeos de 8 segundos com áudio. Para 6s aplique 75% e para 4s, 50% (sempre arredondado para cima). 1 crédito = US$ 0,01.
| Modelo | Velocidade | 720p | 1080p | 4k |
|---|---|---|---|---|
Veo 3.1 Lite veo3-lite | 1-2 min | 14 cr · $0.14 | 16 cr · $0.16 | — |
Veo 3.1 Fast veo3-fast | 1-3 min | 28 cr · $0.28 | 30 cr · $0.30 | 84 cr · $0.84 |
Veo 3.1 Quality veo3-quality | 2-5 min | 112 cr · $1.12 | 112 cr · $1.12 | 168 cr · $1.68 |
Valores acima incluem áudio. Sem áudio o custo é menor; consulte a página de preços do site para o detalhamento completo. O custo exato é sempre informado no campo creditsCost da resposta de /generate.
Erros
Erros usam HTTP status codes padrão e um body JSON com error.code e error.message:
{
"error": {
"code": "INSUFFICIENT_CREDITS",
"message": "Saldo insuficiente: 12 créditos disponíveis, 30 necessários."
}
}| Status | Code | Quando ocorre |
|---|---|---|
| 401 | UNAUTHORIZED | Chave ausente, inválida ou revogada. |
| 400 | VALIDATION_ERROR | Body fora do schema (campo faltando, valor inválido, imagem muito grande). |
| 402 | INSUFFICIENT_CREDITS | Saldo abaixo do custo da geração. Recarregue no painel. |
| 429 | RATE_LIMITED | Limite de requisições excedido para esta API key. Header Retry-After indica quando tentar de novo. |
| 502 | UPSTREAM_ERROR | Falha do provider Veo. Reembolso automático em créditos. |
| 500 | INTERNAL_ERROR | Erro inesperado do nosso lado. Tente novamente. |
Boas práticas
- Use
negativePrompt: descreva o que você não quer ("sem texto, sem marca d'água, sem distorções") para reduzir descartes. - Retry com backoff exponencial: se receber
500ou502, aguarde 1s, 2s, 4s e desista após 3 tentativas. Erros4xxnão devem ser repetidos sem corrigir o body. - Idempotência: guarde o
taskIdno seu banco antes de prosseguir. Se a sua função morrer no meio do polling, recupere o taskId e continue de onde parou — não chame/generatede novo. - Polling no backend: nunca faça polling do navegador com a chave embutida. Faça do seu servidor ou via webhook próprio que notifica seu front quando o vídeo está pronto.
- Cache de
videoUrl: o link de saída tem validade longa, mas baixe e reupload para o seu storage se for servir publicamente.
Limites
Rate limits
Cada API key tem dois buckets independentes, ambos resetando a cada hora cheia (UTC):
| Endpoint | Bucket | Limite |
|---|---|---|
POST /api/v1/generate | generate | 100 / hora |
GET /api/v1/status/{taskId} | status | 1.000 / hora |
Toda resposta autenticada — mesmo em caso de erro — carrega headers com o estado atual:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1762531200Quando o limite é atingido, a API retorna 429 RATE_LIMITED com o header Retry-After em segundos:
{
"error": {
"code": "RATE_LIMITED",
"message": "Rate limit of 100/hour exceeded for this API key. Try again in 1837s."
}
}Os limites são por API key, não por conta — você pode emitir múltiplas chaves para paralelizar workloads. Janelas são alinhadas à hora UTC (ex.: 14:00 → 15:00); não é uma janela deslizante.
Outros limites
- Tamanho de imagem: até ~10 MB por imagem em base64. PNG e JPEG são aceitos.
- Duração: 4, 6 ou 8 segundos. Resoluções a partir de
1080pexigemdurationSeconds: 8. - Aspect ratio:
16:9(paisagem) e9:16(retrato). - Referências: de 1 a 3 imagens por geração no modo
references. lastFrame: suportado apenas emveo3-quality.- Resolução 4K: disponível em
veo3-fasteveo3-quality.veo3-litevai até 1080p.
Pronto para testar?
Crie sua conta, gere uma chave e dispare o primeiro vídeo em menos de dois minutos.