Skip to navigation

Recebendo Mensagens via Webhook

Visão geral

Quando um usuário do WhatsApp envia uma mensagem para um dos seus números conectados, o Muchaw DEV roteia essa mensagem para a sua URL de webhook. Este guia mostra como configurar um servidor de webhook que recebe e processa esses eventos com segurança.

Passo 1 — Crie um webhook

curl -X POST https://dev.muchau.com.br/api/webhooks \
-H "Authorization: Bearer $MUCHAW_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"url": "https://seu-servidor.com/webhooks/whatsapp",
"events": [
"message.received",
"message.delivered",
"message.read",
"message.failed"
]
}'

Salve o secret da resposta — você precisará dele para verificar as requisições recebidas.

export MUCHAW_WEBHOOK_SECRET=whsec_...

Passo 2 — Construa o handler do webhook

import express from "express";
import crypto from "node:crypto";
const app = express();
function verifySignature(rawBody, signature, secret) {
if (!signature?.startsWith("sha256=")) return false;
const expected = crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(signature.slice(7)),
Buffer.from(expected)
);
}
// Use raw body parser para preservar os bytes originais na verificação de assinatura
app.post(
"/webhooks/whatsapp",
express.raw({ type: "application/json" }),
(req, res) => {
// 1. Verificar assinatura
const signature = req.headers["x-muchaw-signature"];
if (!verifySignature(req.body, signature, process.env.MUCHAW_WEBHOOK_SECRET)) {
return res.status(401).json({ error: "Assinatura inválida" });
}
// 2. Responder imediatamente (antes de processar)
res.sendStatus(200);
// 3. Parsear e processar
const event = JSON.parse(req.body.toString());
handleEvent(event);
}
);
function handleEvent(event) {
switch (event.event) {
case "message.received":
console.log("Nova mensagem de", event.data.fromNumber, ":", event.data.body);
break;
case "message.delivered":
console.log("Mensagem", event.data.id, "entregue");
break;
case "message.read":
console.log("Mensagem", event.data.id, "lida");
break;
case "message.failed":
console.error("Falha na entrega da mensagem", event.data.id);
break;
}
}
app.listen(3001, () => console.log("Servidor de webhook na porta 3001"));

Sempre responda com 200 antes de processar. O Muchaw DEV aguarda até 10 segundos por uma resposta. Se seu processamento demorar mais, responda imediatamente e processe o evento de forma assíncrona.

Passo 3 — Exponha seu servidor publicamente

Para desenvolvimento local, use um tunnel como o ngrok:

ngrok http 3001
# → Forwarding: https://abc123.ngrok.io → localhost:3001

Atualize a URL do seu webhook para a URL do ngrok.

Passo 4 — Teste o webhook

curl -X POST "https://dev.muchau.com.br/api/webhooks/<webhook_id>/test" \
-H "Authorization: Bearer $MUCHAW_API_KEY"

Resposta:

{
"success": true,
"statusCode": 200,
"responseTimeMs": 87,
"message": "Test webhook delivered successfully"
}

Estrutura do evento de webhook

Todos os eventos seguem o mesmo envelope:

{
"event": "message.received",
"timestamp": "2024-01-15T10:05:00.000Z",
"data": { ... }
}

O formato de data depende do tipo de evento. Para eventos message.*, é um objeto Message. Para eventos number.*, é um objeto Number.

Lidando com retries

O Muchaw DEV tenta novamente os eventos até 3 vezes com backoff exponencial. Seu handler deve ser idempotente — processar o mesmo evento duas vezes não deve causar efeitos colaterais (registros duplicados, envios duplicados, etc.).

Use event.data.id como chave de deduplicação:

const processed = new Set();
function handleEvent(event) {
const key = `${event.event}:${event.data.id}`;
if (processed.has(key)) return;
processed.add(key);
// processar...
}

Em produção, use Redis ou seu banco de dados para deduplicação.