Webhooks
Receba eventos do dm-chat em tempo real no seu sistema. Use webhooks para integrar com n8n, Zapier, CRMs próprios, dashboards ou qualquer endpoint HTTPS.
Eventos disponíveis
| Evento | Quando dispara |
|---|---|
| message.received | Mensagem recebida (inbound) |
| message.sent | Mensagem enviada (outbound) |
| conversation.assigned | Conversa atribuída a atendente |
| conversation.closed | Conversa encerrada |
| campaign.finished | Campanha finalizada |
Formato do payload
Todos os eventos enviam POST JSON com a estrutura:
{
"event": "message.received",
"tenant_id": 42,
"created_at": "2026-05-05T20:30:00-03:00",
"data": {
"...": "campos específicos do evento"
}
}
Exemplo: message.received
{
"event": "message.received",
"tenant_id": 42,
"created_at": "2026-05-05T20:30:00-03:00",
"data": {
"conversation_id": 123,
"message_id": 9876,
"wa_account_id": 5,
"from": "5511999998888",
"contact_name": "Maria",
"type": "text",
"text": "Oi, quero saber sobre o curso",
"received_at": "2026-05-05T20:29:58-03:00"
}
}
Exemplo: conversation.assigned
{
"event": "conversation.assigned",
"tenant_id": 42,
"created_at": "2026-05-05T20:31:10-03:00",
"data": {
"conversation_id": 123,
"assigned_to": { "id": 7, "name": "Atendente João" },
"assigned_by": { "id": 1, "name": "Admin" }
}
}
Headers HTTP
| Header | Valor |
|---|---|
| Content-Type | application/json |
| User-Agent | dm-chat-webhook/1.0 |
| X-DmChat-Event | Nome do evento (ex.: message.received) |
| X-DmChat-Signature | sha256=<hex> — HMAC do body com seu secret |
| X-DmChat-Delivery | ID único da entrega (idempotência) |
Verificação HMAC
Cada endpoint tem um secret exibido apenas uma vez no momento da criação.
O dm-chat assina o body bruto da requisição com HMAC-SHA256 e envia em
X-DmChat-Signature no formato sha256=<hex>.
Sempre valide o body bruto (antes de qualquer parse), e use comparação constant-time
(hash_equals, crypto.timingSafeEqual) para evitar ataques de timing.
Exemplos de implementação
PHP (Laravel)
Route::post('/dmchat-webhook', function (Request $request) {
$secret = env('DMCHAT_WEBHOOK_SECRET');
$body = $request->getContent();
$sig = $request->header('X-DmChat-Signature', '');
$expected = 'sha256=' . hash_hmac('sha256', $body, $secret);
if (! hash_equals($expected, $sig)) {
abort(401, 'Invalid signature');
}
$payload = json_decode($body, true);
Log::info('dm-chat event', $payload);
// Idempotência: armazenar X-DmChat-Delivery e ignorar duplicatas.
return response()->json(['ok' => true]);
});
Node.js / Express
import express from 'express';
import crypto from 'node:crypto';
const app = express();
const SECRET = process.env.DMCHAT_WEBHOOK_SECRET;
// IMPORTANTE: usar raw body para o HMAC bater.
app.post('/dmchat-webhook',
express.raw({ type: 'application/json' }),
(req, res) => {
const sig = req.header('X-DmChat-Signature') || '';
const expected = 'sha256=' + crypto
.createHmac('sha256', SECRET)
.update(req.body)
.digest('hex');
const a = Buffer.from(sig);
const b = Buffer.from(expected);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) {
return res.status(401).send('Invalid signature');
}
const payload = JSON.parse(req.body.toString('utf8'));
console.log('dm-chat event', payload.event, payload.data);
res.json({ ok: true });
}
);
app.listen(3000);
cURL (simular entrega para testar)
Útil para reproduzir um payload no ambiente local:
BODY='{"event":"message.received","tenant_id":42,"created_at":"2026-05-05T20:30:00-03:00","data":{"text":"oi"}}'
SECRET="seu_secret_aqui"
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$SECRET" -hex | awk '{print $2}')
curl -X POST https://seu-endpoint.com/webhook \
-H "Content-Type: application/json" \
-H "X-DmChat-Event: message.received" \
-H "X-DmChat-Signature: sha256=$SIG" \
-H "X-DmChat-Delivery: test-123" \
-d "$BODY"
n8n
- Crie um workflow com nó Webhook (HTTP Method: POST).
- Copie a URL do n8n (formato
https://n8n.dominio/webhook/<id>). - No dm-chat, cadastre o endpoint apontando para essa URL e copie o secret.
- No n8n, adicione um nó Code antes do fluxo principal:
// n8n Code node — valida HMAC do dm-chat
const crypto = require('crypto');
const SECRET = $env.DMCHAT_WEBHOOK_SECRET;
const raw = JSON.stringify($input.first().json);
const sig = $input.first().headers['x-dmchat-signature'] || '';
const expected = 'sha256=' + crypto.createHmac('sha256', SECRET).update(raw).digest('hex');
if (sig !== expected) {
throw new Error('Invalid signature');
}
return $input.all();
Atenção: o n8n parseia o JSON antes do Code node. Para validação 100% precisa, use o nó Webhook com opção Raw Body ativada e re-serialize com a mesma chave/ordem do remetente, ou prefira validar por IP allowlist + token em query.
Zapier
- Crie um Zap com trigger Webhooks by Zapier → Catch Raw Hook.
- Copie a URL fornecida e cadastre como endpoint no dm-chat.
- Adicione um passo Code by Zapier (Run JavaScript) para validar:
// Zapier Code — valida HMAC
const crypto = require('crypto');
const SECRET = 'cole_seu_secret_aqui'; // ou use Storage by Zapier
const raw = inputData.rawBody;
const sig = inputData.signature;
const expected = 'sha256=' + crypto.createHmac('sha256', SECRET).update(raw).digest('hex');
if (sig !== expected) callback(new Error('Invalid signature'));
else callback(null, JSON.parse(raw));
No mapeamento do passo Code, defina rawBody = {{Raw Body}} e
signature = {{X-DmChat-Signature}}.
Retries e timeouts
- Timeout: 15 segundos por entrega.
- Sucesso: qualquer status HTTP
2xx. - Retries: até 5 tentativas com backoff exponencial (10s, 1min, 10min, 1h, 6h).
- Auto-desativação: após muitas falhas consecutivas o endpoint pode ser pausado automaticamente.
- Idempotência: use
X-DmChat-Deliverycomo chave para evitar processar duplicatas.
Boas práticas
- Responda rápido (< 2s). Enfileire o processamento em background.
- Sempre valide o HMAC antes de processar o conteúdo.
- Armazene o
X-DmChat-Deliverye ignore IDs já processados. - Não confie no IP de origem — confie no HMAC.
- Use HTTPS com certificado válido (não aceitamos endpoints HTTP).