Toda entrega da Malvo inclui o header Malvo-Signature. Verifique o HMAC do corpo HTTP cru antes de aplicar qualquer efeito. Headers customizados e o IP de egress estático continuam válidos como defesa em profundidade. Aplicações criadas após este lançamento já nascem com um signing secret. Aplicações existentes têm um prazo de adequação publicado no Dashboard (90 dias). A Malvo não interrompe entregas depois do prazo — o modelo antigo (só headers + IP) deixa de ser suficiente.

HMAC (Malvo-Signature)

Formato:
A assinatura é HMAC-SHA256 de {t}.{raw body}, hex minúsculo, com o signing secret da aplicação (whsec_…). Durante uma rotação o header pode trazer dois v1. Use os bytes exatos do POST — nunca JSON.parse + JSON.stringify. Vetor de teste:
Copie o secret em Dashboard → Webhooks → Revelar segredo. Ele não volta em GET /webhooks. Durante uma rotação o SDK aceita os dois secrets:
A janela de replay padrão é 5 minutos. Cada reentrega da Malvo assina com t fresco, então retries de até ~3 h continuam válidos. Deduplique por eventId — o HMAC não substitui isso. Quem não usa o SDK: HMAC-SHA256 de "{t}." + raw_body com a string inteira do secret (incluindo whsec_), compare em tempo constante, aceite qualquer v1 do header.

Headers customizados por webhook

Cada webhook pode carregar um mapa de headers (nome → valor) que é enviado verbatim em toda entrega. É aí que você coloca o seu segredo compartilhado.
Propriedades importantes dos headers:
  • Na API pública, o mapa é aceito em POST /webhooks e PATCH /webhooks/{id} e não volta em nenhum GET/list.
  • No Dashboard, owners e admins veem e editam os headers do endpoint. O signing secret HMAC é outro material — mora na aplicação e só aparece ao revelar na página Webhooks.
  • Não coloque o signing secret HMAC nesse mapa: a Malvo já envia Malvo-Signature.

Rotação dos headers customizados via PATCH

Pela API pública a rotação do mapa é um PATCH que reescreve os headers:
A resposta pública do PATCH confirma a atualização mas não ecoa os headers. No Dashboard você edita o mapa na ficha do endpoint. A rotação do signing secret HMAC é o botão Rotacionar da página Webhooks (o previous vale 24 h).

Rotação do signing secret

  1. No Dashboard → Webhooks, Rotacionar gera um secret novo e mantém o anterior por 24 h.
  2. No receiver, passe os dois para verifyWebhookSignature enquanto migra.
  3. Encerrar anterior invalida o secret antigo na hora. Uma segunda rotação com previous ainda válido retorna 409.

IP allowlisting

Todas as entregas saem de um único IP de egress estático. Liberar esse IP no firewall/WAF é defesa extra, não substitui o HMAC.
O IP de egress ainda não é exibido na página Webhooks do Dashboard. Confirme o valor vigente com o suporte da Malvo — não invente nem reutilize um IP de outra fonte.

Checklist de validação do receiver

Valide toda requisição recebida nesta ordem, antes de aplicar qualquer efeito:
1

HMAC

Malvo-Signature confere com o signing secret da aplicação sobre o corpo cru.
2

IP de origem

O IP de origem é o egress estático da Malvo (valor vigente via suporte, até o Dashboard publicar).
3

Header de autenticação

O header de auth customizado bate com o segredo configurado, se você usa um.
4

Corpo e evento

O corpo é JSON válido e event é um valor que você assina.
5

Idempotência

O eventId ainda não foi processado (deduplique — veja Entrega & Retry).
Proteção contra replay: o t do HMAC expira em 5 minutos; cada retry da Malvo traz um t novo. Persista o eventId e trate duplicatas como no-op. Não rejeite o evento pela idade do outbox.

Handler de exemplo

O padrão é: HMAC → parse → idempotência → 200 → processar async. Use express.raw (ou o equivalente no seu framework). express.json() consome o body e o HMAC quebra.
401 na assinatura faz a Malvo reentregar (útil se o relógio do receiver atrasou). Secret errado ou express.json() no lugar de .raw() também geram 9 retries — corrija o receiver, não o cadastro do webhook.
Responda 2XX antes do trabalho pesado. Processamento síncrono antes do 200 estoura o limite de 5 segundos e a Malvo passa a reentregar o mesmo evento até 9 vezes.

Troubleshooting de entrega

Próximos passos

Entrega & Retry

O schedule de retry, idempotência e a reconciliação noturna.

Referência — Webhooks

POST, GET, PATCH e DELETE de webhooks, incluindo o campo headers.