X-Webhook-Signature. Validar essa
assinatura é o que separa “recebi uma notificação” de “recebi uma notificação nossa”.
Onde fica o secret
Cada loja tem o seu, em Dashboard → API e Desenvolvedores → Webhooks. Guarde numa variável de ambiente do seu backend. Se vazar, regenere pelo painel. O antigo para de funcionar na hora.Como calcular
O HMAC é sobre o corpo cru da requisição, a string exata que chegou, antes de qualquerJSON.parse. Se você parsear e re-serializar, a ordem das chaves ou o espaçamento mudam e
a assinatura nunca vai bater.
Compare com timingSafeEqual ou equivalente. Comparação com === vaza informação pelo
tempo de execução.
Idempotência
O headerX-Webhook-Id vem no formato evento:id, como payment.paid:psa_abc123.
Reentrega do mesmo evento usa o mesmo valor.
Erros comuns
A assinatura nunca bate
A assinatura nunca bate
Quase sempre é middleware de JSON rodando antes do handler e consumindo o corpo. Em
Express,
express.json() global quebra a validação. Registre a rota do webhook com
express.raw() antes do parser global.Funciona local e falha em produção
Funciona local e falha em produção
Proxy ou CDN reescrevendo o corpo. Verifique se não há compressão, reformatação de JSON
ou WAF alterando a requisição no caminho.
Bate às vezes
Bate às vezes
Você está comparando a assinatura contra um corpo re-serializado. Guarde os bytes
originais em vez de reconstruir o JSON.

