Pular para o conteúdo principal

Guia de implementação

Concluir o trabalho depois que a requisição já se foi.

Uma tarefa de mídia sobrevive à chamada HTTP que a criou, à página que a disparou e muitas vezes ao deploy que estava rodando na hora. Tudo aqui serve para aguentar isso.

O desafio

A conexão não é a transação

Entre apertar enviar e ter o arquivo existem quatro lugares para perder trabalho: uma criação reenviada às cegas depois do tempo esgotado, um retorno que você não consegue verificar, um laço de consulta que martela ou desiste, e uma URL de resultado que expirou enquanto você decidia o que fazer.

01

Um reenvio sem chave é uma segunda fatura

Idempotency-Key faz com que repetir o mesmo modelo, entrada e retorno em até 24 horas devolva a tarefa original sem reservar de novo. O escopo é uma chave de API; uma chave irmã repetindo o mesmo valor recebe 409 e nenhum identificador de tarefa.

02

Um retorno não verificado é um endpoint aberto

As entregas trazem X-Webhook-Timestamp e um HMAC-SHA256 em Base64 no X-Webhook-Signature, calculado sobre taskId.timestamp.sha256(raw_body). Verifique contra os bytes crus em tempo constante e recuse carimbos antigos antes de mexer no estado da tarefa ou da cobrança.

03

Consultar sem teto é pedir limite de taxa

recordInfo é reserva, não transporte. Comece perto de dois segundos, cresça metade a cada vez, limite em quinze e pare num prazo escolhido por você.

A abordagem

Um registro durável por tarefa, escrito antes de responder

Persista a chave de idempotência, o taskId e o seu identificador de correlação na mesma transação em que responde a quem chamou. Todo evento seguinte — retorno, consulta, repetição, dúvida de suporte — resolve contra aquela linha, e uma entrega duplicada vira uma atualização em vez de um segundo pedido.

Verifique primeiro, leia depois. A assinatura cobre os bytes crus, então a análise vem depois da comparação.

Verify the callback before you trust it

import { createHash, createHmac, timingSafeEqual } from "node:crypto";

// rawBody is the exact bytes that arrived. Parse only to read the task ID:
// the digest is always computed over those raw bytes, never over a re-encode.
export function verifyDelivery(rawBody, headers, webhookKey) {
  const timestamp = headers["x-webhook-timestamp"];
  if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;

  const taskId = JSON.parse(rawBody).data.taskId;          // payload version 2
  const digest = createHash("sha256").update(rawBody).digest("hex");
  const expected = createHmac("sha256", webhookKey)
    .update(`${taskId}.${timestamp}.${digest}`)
    .digest("base64");

  const sent = Buffer.from(headers["x-webhook-signature"] ?? "", "utf8");
  const mine = Buffer.from(expected, "utf8");
  return sent.length === mine.length && timingSafeEqual(sent, mine);
}

Delivery headers

X-Webhook-Timestamp: 1788652800
X-Webhook-Signature: <base64>
X-Webhook-Payload-Version: 2

{
  "code": 200,
  "msg": "success",
  "request_id": "whd_01k3m8x9q2z4v7n5p6r8s0t1w3",
  "data": { "taskId": "job_01k3…", "state": "succeeded", "settled": true, … }
}

Contrato

O que vale fixar logo de início

API de mídia assíncrona: tarefas e webhooks — O que vale fixar logo de início
Campo ou cabeçalhoValor ou limite
Idempotency-Key24 h · scoped to one API key
X-Webhook-Signaturebase64(HMAC-SHA256)
signed stringtaskId.timestamp.sha256(raw_body)
X-Webhook-Payload-Version2 for new integrations

Deslize horizontalmente para ver todas as colunas.

Integração

Da primeira chamada até produção

  1. 01Gere e guarde uma chave de idempotência e chame createTask com ela e com callBackUrl apontando para um endpoint HTTPS na porta 80 ou 443.
  2. 02Escreva data.taskId no seu banco antes de responder; o 202 é o único lugar onde ele aparece primeiro.
  3. 03Aceite o retorno, verifique a assinatura sobre o corpo cru, deduplique por request_id e atualize o registro.
  4. 04Mantenha recordInfo com backoff exponencial como reserva e copie output.assets antes de a URL assinada expirar.

Adequação

Quando este caminho é o certo

Escolha se

  • Qualquer coisa que produza mídia. Endpoints de imagem, vídeo e áudio são assíncronos por construção.
  • Você precisa de registro durável do que foi enviado, do quanto deveria custar e de como terminou.

Procure outro caminho se

  • Você está chamando um modelo de texto: ele transmite dentro da requisição e liquida por uso medido.
  • Você quer que o navegador seja dono do trabalho. As chaves são do servidor, e o registro da tarefa também.

Evidências

O que você mesmo pode verificar

Toda resposta traz um request_id

O envelope é {code, msg, data, request_id} em todas as operações /api/v1. Na versão 2 de payload, o request_id da entrega é estável entre reenvios, então serve naturalmente como chave de deduplicação.

As reservas aparecem no registro

cost com settled: false é a estimativa reservada; settled: true é a cobrança final. O sucesso nunca ultrapassa a reserva, e falha ou expiração libera tudo.

As falhas usam vocabulário fechado

errorCode é um de nove valores estáveis: invalid_request, unsupported_combination, content_rejected, rate_limited, upstream_unavailable, generation_failed, timeout, invalid_asset, upstream_failed. Qualquer outro valor deve ser tratado como upstream_failed.

Antes de lançar

Comportamentos da plataforma a confirmar

  • Guarde a chave de idempotência com a tarefa, não na memória do processo.
  • Torne o tratador do retorno idempotente; as entregas são repetidas por projeto.
  • Defina um prazo de consulta e alerte sobre tarefas que o ultrapassem.
  • Copie os arquivos antes de expiresAt e peça a URL de novo em vez de guardar uma assinada em cache.

Perguntas frequentes

O que mais perguntam nesta página

Reenvie a mesma requisição com a mesma Idempotency-Key. Em até 24 horas e com a mesma chave de API você recupera a tarefa original sem segunda reserva. Nunca envie um corpo novo depois de um tempo esgotado: isso é uma tarefa nova, cobrada à parte.

A seguir

Montar um fluxo de tarefas que sobrevive a um deploy

Envie trabalhos longos do seu servidor e conclua com garantia: chaves de idempotência, retornos assinados, consulta limitada e cinco estados.

Guias relacionados