Registre um mediaWebhookUrl, receba um POST quando um job for concluído, consulte GET /api/media/jobs/{id}, trate os códigos de erro e entenda os limites de cobrança e idempotência.
Guia operacional para jobs de mídia assíncronos: registro de webhook, status, polling, códigos de erro, cobranças e limites de idempotência — estritamente conforme a implementação atual no código.
Ciclo de vida da tarefa
POST /api/media/generate — em caso de sucesso, 202 e { ok: true, jobId, status: "processing" }. Não há status separados de queued / running na API: até o job ser concluído, o cliente vê processing.
O upstream pode passar por etapas internas (waiting, generating) — elas não são refletidas na API pública; durante o polling, o job permanece processing.
Status do terminal: success (contém resultUrls, cobrado em caso de sucesso) ou fail (sem cobrança).
A conclusão é registrada uma vez: por meio do callback upstream ou em uma consulta lazy em GET /api/media/jobs/{id}.
Consulta: GET /api/media/jobs/{id}
GEThttps://getvibeapi.com/api/media/jobs/{id}
Parâmetro
Tipo
Descrição
status
string
submitting | processing | success | fail. submitting + media_submission_uncertain is non-terminal; within about 10–15 minutes such a submission is closed as fail (media_submission_not_started) without a charge — create a new task.
resultUrls
string[]
URLs assinadas /api/media/file/{id}/{idx}?sig=… (sem chave de API).
priceRub
number
Valor da cobrança em USD (0 em caso de falha ou antes da conclusão).
failMsg
string | null
Mensagem segura em caso de falha ou de um media_submission_uncertain não terminal.
errorCode
string | null
Código de erro (media_generation_failed) ou non-terminal media_submission_uncertain.
retryGuidance
string | null
Em media_submission_uncertain: uma instrução segura para consultar o mesmo jobId mais tarde e não criar uma duplicata automaticamente.
# 2. poll the job until it is ready
curl https://getvibeapi.com/api/media/jobs/JOB_ID \
-H "Authorization: Bearer $GETVIBE_API_KEY"
# → {"status":"success","resultUrls":["https://..."],"priceRub":...}
Intervalo de polling recomendado: 3–5 s, com recuo exponencial de até 30 s. O tempo limite no cliente deve seguir o SLA da sua aplicação (a geração de vídeo pode levar minutos).
Registro de webhook
GEThttps://getvibeapi.com/api/webhooks
PATCHhttps://getvibeapi.com/api/webhooks
Uma URL por conta: mediaWebhookUrl. Configurada em dashboard → Webhooks ou pela API com uma account session (um cookie após o login). O endpoint não aceita sk-pv-… — somente uma sessão autenticada.
# Example (a dashboard session is required, not an API key)
curl -X PATCH https://getvibeapi.com/api/webhooks \
-H "Content-Type: application/json" \
-b "session=YOUR_SESSION" \
-d '{"mediaWebhookUrl":"https://example.com/webhooks/media"}'
# Clear the URL
curl -X PATCH https://getvibeapi.com/api/webhooks \
-H "Content-Type: application/json" \
-b "session=YOUR_SESSION" \
-d '{"mediaWebhookUrl":null}'
Requisitos de URL
Parâmetro
Tipo
Descrição
mediaWebhookUrl
URL HTTPS
Um endereço HTTPS público; endereços privados/de loopback e nossos próprios domínios são recusados (proteção contra SSRF), e o endereço é verificado novamente antes de cada entrega. Uma string vazia ou null redefine esse valor.
balanceWebhookUrl
URL HTTPS
Um webhook separado para saldo baixo (não para mídia), assinado com o mesmo segredo da conta, x-pv-event: balance.low. O limite é balanceWebhookThresholdRub.
Entrega de webhook na conclusão do trabalho
Quando um trabalho atinge um status final, o GetVibe cria um evento lógico e o entrega via POST ao mediaWebhookUrl registrado. A entrega é limitada: o serviço faz até 5 tentativas no total. O mesmo payload pode chegar mais de uma vez.
// POST to your mediaWebhookUrl when a job finishes
{
"jobId": "...",
"status": "success", // or "fail"
"model": "veo-3.1",
"kind": "video", // image | video | audio | music | 3d
"resultUrls": ["https://getvibeapi.com/api/media/file/..."],
"failMsg": null,
"createdAt": "2026-06-17T10:00:00.000Z"
}
Comportamento de entrega (conforme o código)
Parâmetro
Tipo
Descrição
Signature / auth
—
Cada entrega é assinada com Standard Webhooks: os cabeçalhos webhook-id, webhook-timestamp e webhook-signature (v1, HMAC-SHA256 em base64 de “id.timestamp.body”). O segredo da conta é exibido no painel → Webhooks e retornado a uma chave de API como accountSecret por GET /api/media/webhook-secret; as entregas para um webhook_url por solicitação são assinadas com o segredo dessa chave (o campo secret). Rejeite uma solicitação com uma assinatura incorreta ou um timestamp com mais de 5 minutos.
Retries
outbox
Até 5 tentativas no total; intervalo após uma falha: 1, 2, 4, 8 minutos. Depois de esgotar as tentativas, o evento passa para FAILED e deixa de ser entregue automaticamente. O polling de GET /api/media/jobs/{id} continua sendo a fonte do estado.
Receiver dedup
required
Elimine duplicidades pelo par jobId + status e torne seu handler idempotente. Não use o webhook como única fonte de estado.
Content-Type
application/json
O corpo é um JSON com os campos jobId, status, model, kind, resultUrls, failMsg, createdAt.
Erros de POST /api/media/generate
HTTP
Quando
Cobrança
Tentar novamente
202
Tarefa aceita (ok: true, jobId)
Não (somente após o sucesso)
—
400
JSON / corpo da solicitação inválido
Não
Corrija a solicitação
401
Chave de API ausente ou inválida
Não
Verificar autorização
402
Saldo insuficiente (admissão)
Não
Adicionar saldo
422
Modelo desconhecido, opts inválidas, ok: false da facade
Não
Fix model/opts
502
media_submit_failed — upstream indisponível
Não
Tentar novamente com espera progressiva
503
priceUnavailable, proteção de roteamento, VIDEO_DISABLED, veo sem preço
Não
Outro modelo / mais tarde
Erros de consulta e falhas terminais
HTTP / status
Significado
Cobrança
404
job não encontrado ou um jobId de terceiros
Não
processing
O job ainda está em execução
Não
success
Concluído, resultUrls preenchido
Sim — priceRub na resposta
fail
Falha na geração
No (priceRub = 0)
Faturamento e idempotência
Cobrado uma vez em caso de sucesso. Em finalizeJob, a transição processing → success|fail é atômica: uma chamada de retorno ou consulta repetida não gera uma segunda cobrança.
fail — gratuito. Nenhum débito é realizado com um status fail.
Cotação de admissão. Se uma cotação foi salva na criação, exatamente esse valor é cobrado em caso de sucesso (nunca mais do que a medição real do upstream).
Crie a idempotência por meio do cabeçalho. Um POST repetido para /api/media/generate sem o cabeçalho cria um novo job e uma nova cobrança em caso de sucesso. Envie Idempotency-Key (até 255 caracteres ASCII): uma nova tentativa com a mesma chave e o mesmo corpo dentro de 24 horas retorna o mesmo jobId sem um novo job; a mesma chave com um corpo diferente retorna 422, e 409 enquanto a primeira solicitação ainda estiver sendo processada. O jobId de uma geração paga também é exibido em GET /v1/generations (o campo job_id).
O webhook é limitado a cinco tentativas. Um único evento lógico é criado por transição terminal, mas as tentativas de entrega podem se repetir. Após cinco falhas, o evento recebe o status FAILED . O handler do cliente deve eliminar duplicatas do par jobId + status.