Um receptor de webhooks pronto para produção: Express, validação HMAC com comparação em tempo constante e as armadilhas que derrubam todo mundo.
Cada entrega de webhook da WPPAPI inclui dois headers:
X-WPPAPI-Signature
— o HMAC-SHA256 do body em hexadecimal, calculado com o secret do seu webhook — e
X-WPPAPI-Signature-Alg: sha256.
Os headers X-WPPAPI-Event e
X-WPPAPI-Instance identificam o evento e a instância.
Recalcule o HMAC sobre os bytes exatos recebidos e compare com
timingSafeEqual.
Se bater, a requisição veio da WPPAPI e não foi alterada.
import express from "express";
import { createHmac, timingSafeEqual } from "crypto";
const app = express();
const SECRET = process.env.WPPAPI_WEBHOOK_SECRET;
// Importante: o HMAC é calculado sobre os BYTES EXATOS do body.
// Use express.raw() na rota do webhook — não express.json().
app.post(
"/webhooks/wppapi",
express.raw({ type: "application/json" }),
(req, res) => {
const signature = req.header("X-WPPAPI-Signature") ?? "";
const expected = createHmac("sha256", SECRET)
.update(req.body)
.digest("hex");
const valid =
signature.length === expected.length &&
timingSafeEqual(Buffer.from(signature), Buffer.from(expected));
if (!valid) return res.status(401).send("invalid signature");
const event = JSON.parse(req.body.toString("utf8"));
if (event.event === "received" && !event.data?.fromMe) {
console.log("Mensagem de", event.data.from, ":", event.data.body);
// Enfileire o processamento pesado e responda 200 rápido.
}
res.sendStatus(200);
}
);
app.listen(3000); Em desenvolvimento, exponha a porta local com um túnel (ngrok, cloudflared) e cadastre a URL no painel da WPPAPI. O secret é exibido ao criar o webhook.
Valide a assinatura, enfileire e responda. Processamento lento causa timeout e reentrega — seu handler precisa ser idempotente de qualquer forma.
O erro nº 1 em validação HMAC: deixar o express.json() fazer parse e depois re-serializar. Bytes diferentes = assinatura inválida. Use express.raw() na rota do webhook.
A WPPAPI reentrega em caso de falha e move para dead-letter queue após esgotar as tentativas. Guarde IDs processados para descartar duplicatas.
Eventos das suas próprias mensagens chegam com fromMe: true. Se seu bot responde mensagens, filtre — ou ele conversará consigo mesmo.
Com o receptor rodando, o próximo passo natural é automatizar respostas no n8n ou plugar o Chatwoot para atendimento humano. A referência de eventos está na documentação.
3 dias grátis, sem cartão — webhooks com HMAC inclusos em todos os planos.
Criar conta grátis