Mandaí DocsAbrir console
Webhooks · SegurançaAbrir para IA

Valide os bytes antes de interpretar o JSON

A assinatura usa HMAC-SHA256 sobre o timestamp e o corpo bruto. Faça a comparação em tempo constante antes de executar qualquer regra de negócio.

Headers assinados

evt_…
Unix seconds
1
v1=<base64url>

Entrada assinada

Concatene o valor exato de Mandai-Timestamp, um ponto e o corpo bruto recebido: <timestamp>.<raw body>. Não faça parse, reserialização, trim ou alteração de encoding antes da verificação.

Exemplo Node.js e Bun

TypeScript
import { createHmac, timingSafeEqual } from 'node:crypto';

const MAX_AGE_SECONDS = 300;

// Keep both entries during a rotation overlap; drop the old one once it closes.
const SECRETS: Record<string, string> = {
  '1': process.env.MANDAI_WEBHOOK_SECRET!,
};

export function verifyMandaiWebhook(input: {
  rawBody: string;
  timestamp: string;
  signature: string;
  version: string;
}): boolean {
  const timestamp = Number(input.timestamp);
  const received = input.signature.match(/^v1=(.+)$/)?.[1];
  const secret = SECRETS[input.version];
  const now = Math.floor(Date.now() / 1000);

  if (!Number.isSafeInteger(timestamp) || !received || !secret) return false;
  if (Math.abs(now - timestamp) > MAX_AGE_SECONDS) return false;

  const expected = createHmac('sha256', secret)
    .update(`${input.timestamp}.${input.rawBody}`)
    .digest('base64url');

  const left = Buffer.from(received);
  const right = Buffer.from(expected);
  return left.length === right.length && timingSafeEqual(left, right);
}

Rotação de segredo

Ao rotacionar, você informa overlap_seconds. Durante essa janela o Mandaí continua assinando com o segredo anterior; quando ela fecha, passa a assinar com o novo. Antes de rotacionar, faça o deploy de um verificador que aceita as duas versões e usa Mandai-Signature-Version para escolher o segredo. Depois que a janela fechar, remova o segredo antigo. overlap_seconds igual a zero corta na hora.

Checklist de verificação

  • Rejeite timestamp com diferença superior a cinco minutos.
  • Aceite apenas versões que você conhece; durante uma rotação isso inclui a anterior e a nova.
  • Use o segredo do mesmo ambiente do endpoint.
  • Compare o digest em tempo constante.
  • Persista event_id antes de responder 2xx.
Primeiros passosWebhooksOpenAPITermos de usoPrivacidadeUso aceitável