Pular para o conteúdo
Guias
Guias

Callbacks

Receba e verifique entregas de callback de Task com segurança.

Use Callbacks para receber eventos do ciclo de vida de Tasks em um endpoint HTTPS público. Verifique cada callback antes de processar seu corpo JSON para que apenas entregas assinadas para a sua conta possam alterar o estado da aplicação.

Configurar uma URL de callback

Adicione um callback_url HTTPS público ao criar uma Tarefa. O corpo do evento e os estados do ciclo de vida dependem do endpoint; consulte a Referência da API daquele endpoint para conhecer os payloads de callback.

JSON
{
  "model": "flux-2-pro-text-to-image",
  "prompt": "A product photograph on a clean studio background",
  "callback_url": "https://your-domain.com/webhooks/runapi"
}

Criar um Callback Secret

Siga o Guia de Autenticação para fazer login, depois abra Chaves de API e crie um Callback Secret para a conta que cria a Task. Armazene o valor em um gerenciador de segredos e o disponibilize somente para o seu receptor de callbacks. Não é uma Chave de API e nunca deve ser enviado em uma requisição de Task.

O secret assina os callbacks daquela conta. Rotacioná-lo altera a assinatura para entregas posteriores, portanto atualize imediatamente todos os receptores de callback e mantenha ambos os valores disponíveis apenas pelo tempo necessário para tratar as entregas em andamento.

Verificar uma assinatura de callback

Cada callback é um HTTP POST com Content-Type: application/json. O RunAPI não adiciona um cabeçalho Authorization a esta requisição. Verifique estes cabeçalhos antes de desserializar o corpo:

Cabeçalho Significado X-Callback-Id Identificador único para esta tentativa de entrega. X-Callback-Timestamp Timestamp Unix em segundos de quando a entrega foi assinada. X-Callback-Signature Assinatura HMAC-SHA-256 codificada em Base64.

Construa o valor assinado exatamente como descrito abaixo, utilizando os bytes do corpo da requisição sem modificações:

TEXT
X-Callback-Id + "." + X-Callback-Timestamp + "." + raw request body

Decodifique o Callback Secret em Base64, calcule o HMAC-SHA-256 sobre esse valor, codifique o resultado em Base64 e compare-o com X-Callback-Signature usando uma comparação segura contra timing. Não analise nem re-serialize o JSON antes de verificar.

JavaScript

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

export function verifyCallback({headers, rawBody, callbackSecret}) {
  const callbackId = headers["x-callback-id"];
  const timestamp = Number(headers["x-callback-timestamp"]);
  const signature = headers["x-callback-signature"];

  if (!callbackId || !signature || !Number.isSafeInteger(timestamp)) return false;
  if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;

  const signedContent = `${callbackId}.${timestamp}.${rawBody}`;
  const expected = createHmac("sha256", Buffer.from(callbackSecret, "base64"))
    .update(signedContent, "utf8")
    .digest();
  const received = Buffer.from(signature, "base64");

  return expected.length === received.length && timingSafeEqual(expected, received);
}

Passe a string de corpo bruto da solicitação do framework para rawBody; não chame JSON.stringify em dados já analisados.

Python

PYTHON
import base64
import hashlib
import hmac
import time


def verify_callback(headers, raw_body, callback_secret):
    callback_id = headers.get("X-Callback-Id")
    timestamp = headers.get("X-Callback-Timestamp")
    signature = headers.get("X-Callback-Signature")

    if not callback_id or not timestamp or not signature:
        return False

    try:
        timestamp = int(timestamp)
        secret = base64.b64decode(callback_secret, validate=True)
        received = base64.b64decode(signature, validate=True)
    except (ValueError, TypeError):
        return False

    if abs(time.time() - timestamp) > 300:
        return False

    signed_content = f"{callback_id}.{timestamp}.{raw_body}".encode("utf-8")
    expected = hmac.new(secret, signed_content, hashlib.sha256).digest()
    return hmac.compare_digest(expected, received)

Passe a string exata do corpo bruto da solicitação recebida pelo seu framework HTTP como raw_body.

Processar entregas com segurança

  • Retorne uma resposta 2xx somente após o callback ter sido aceito para processamento. Após uma resposta não 2xx ou falha de transporte, a entrega é tentada até 10 vezes.
  • Responda dentro de 15 segundos. Enfileire trabalhos mais lentos após a verificação, em vez de bloquear a resposta HTTP.
  • Rejeite Callbacks com cabeçalhos de assinatura ausentes, assinatura inválida ou timestamp fora da janela de tolerância definida pelo seu receptor.

Solucionar problemas de verificação

  • Incompatibilidade de assinatura: confirme que o Callback Secret pertence à mesma conta que a Tarefa, decodifique-o com Base64 e assine o corpo original em vez do JSON parseado.
  • Cabeçalhos de assinatura ausentes: crie um Callback Secret antes de depender de callbacks para mudanças de estado.
  • Timestamp rejeitado: sincronize o relógio do receptor e utilize uma tolerância adequada para o seu ambiente de implantação.

Para orientações de configuração e ciclo de vida, volte ao Início rápido da API de Task.