Tema
Idioma

Webhooks e o ciclo de vida do trabalho de mídia

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

  1. 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.
  2. 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.
  3. Status do terminal: success (contém resultUrls, cobrado em caso de sucesso) ou fail (sem cobrança).
  4. 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âmetroTipoDescrição
statusstringsubmitting | 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.
resultUrlsstring[]URLs assinadas /api/media/file/{id}/{idx}?sig=… (sem chave de API).
priceRubnumberValor da cobrança em USD (0 em caso de falha ou antes da conclusão).
failMsgstring | nullMensagem segura em caso de falha ou de um media_submission_uncertain não terminal.
errorCodestring | nullCódigo de erro (media_generation_failed) ou non-terminal media_submission_uncertain.
retryGuidancestring | nullEm 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âmetroTipoDescrição
mediaWebhookUrlURL HTTPSUm 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.
balanceWebhookUrlURL HTTPSUm 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âmetroTipoDescriçã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.
RetriesoutboxAté 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 deduprequiredElimine duplicidades pelo par jobId + status e torne seu handler idempotente. Não use o webhook como única fonte de estado.
Content-Typeapplication/jsonO corpo é um JSON com os campos jobId, status, model, kind, resultUrls, failMsg, createdAt.

Erros de POST /api/media/generate

HTTPQuandoCobrançaTentar novamente
202Tarefa aceita (ok: true, jobId)Não (somente após o sucesso)—
400JSON / corpo da solicitação inválidoNãoCorrija a solicitação
401Chave de API ausente ou inválidaNãoVerificar autorização
402Saldo insuficiente (admissão)NãoAdicionar saldo
422Modelo desconhecido, opts inválidas, ok: false da facadeNãoFix model/opts
502media_submit_failed — upstream indisponívelNãoTentar novamente com espera progressiva
503priceUnavailable, proteção de roteamento, VIDEO_DISABLED, veo sem preçoNãoOutro modelo / mais tarde

Erros de consulta e falhas terminais

HTTP / statusSignificadoCobrança
404job não encontrado ou um jobId de terceirosNão
processingO job ainda está em execuçãoNão
successConcluído, resultUrls preenchidoSim — priceRub na resposta
failFalha na geraçãoNo (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.
Veja também: Geração de mídia, Catálogo de modelos de mídia, Erros e limites (códigos 401/402/429 comuns para /v1).
Webhooks de mídia da GetVibe API — status, erros, cobrança | GetVibe API