Webhooks & relay
É assim que o seu sistema recebe o inbound. Quando a Meta nos envia um evento (mensagem recebida, status de entrega), nós o encaminhamos (relay) para o(s) seu(s) endpoint(s) de webhook HTTPS, num envelope unificado e assinado.
Você pode ter vários endpoints por tenant, cada um com seu escopo (canais/ativos) e filtro (tipos de evento) — útil para separar ambientes, times ou tipos de evento.
1. Registrar um endpoint
Seção intitulada “1. Registrar um endpoint”POST /v1/webhook-endpointsAuthorization: Bearer lidmo_sk_...Content-Type: application/json
{ "url": "https://seu-sistema.com/webhooks/lidmo", "channels": [], "asset_external_ids": [], "event_types": ["message.received", "message.status"]}Arrays vazios = todos: sem channels, recebe de todos os canais; sem
event_types, recebe todos os tipos. A resposta 201 inclui o
signing_secret uma única vez — guarde-o:
{ "id": "e3b0…", "url": "https://seu-sistema.com/webhooks/lidmo", "channels": [], "asset_external_ids": [], "event_types": ["message.received", "message.status"], "active": true, "signing_secret": "a1b2c3…", "created_at": "2026-11-04T00:00:00Z", "updated_at": "2026-11-04T00:00:00Z"}Gerencie com GET /v1/webhook-endpoints, PATCH /v1/webhook-endpoints/{id}
(editar escopo/filtro, pausar com "active": false) e
DELETE /v1/webhook-endpoints/{id}.
2. O envelope
Seção intitulada “2. O envelope”Cada entrega é um POST ao seu url com este corpo JSON (estável para os três
canais e todos os tipos):
{ "id": "evt_9f8c…", "type": "message.received", "channel": "whatsapp", "tenant_id": "398012597749743619", "asset": "1055551234567890", "occurred_at": "2026-11-04T00:00:00Z", "data": { "...": "payload específico do tipo de evento" }}| Campo | Descrição |
|---|---|
id |
id único e estável do evento (idempotência; vem no header X-Lidmo-Event-Id) |
type |
tipo do evento (abaixo) |
channel |
whatsapp | instagram | messenger |
tenant_id |
sua organização |
asset |
ativo receptor (phone_number_id / page_id / ig_account_id) |
occurred_at |
quando ocorreu na Meta |
data |
corpo específico do tipo, como JSON |
Tipos de evento
Seção intitulada “Tipos de evento”| Tipo | Quando |
|---|---|
message.received |
mensagem inbound de um contato |
message.status |
atualização de status de uma mensagem que você enviou (enviado/entregue/lido/falhou) |
template.update |
mudança de aprovação/qualidade de template (reservado) |
quality.alert |
mudança de qualidade/limite de envio (reservado) |
3. Verificar a assinatura
Seção intitulada “3. Verificar a assinatura”Cada entrega vem com o header:
X-Lidmo-Signature-256: sha256=<hex>X-Lidmo-Event-Id: evt_9f8c…O valor é o HMAC-SHA256 do corpo cru (os bytes exatos do request, antes de
qualquer parsing) usando o signing_secret daquele endpoint. Compare em
tempo constante e rejeite o que não bater.
import crypto from "node:crypto";
function verify(rawBody, header, secret) { const expected = "sha256=" + crypto.createHmac("sha256", secret).update(rawBody).digest("hex"); const a = Buffer.from(header || ""); const b = Buffer.from(expected); return a.length === b.length && crypto.timingSafeEqual(a, b);}4. Responder e idempotência
Seção intitulada “4. Responder e idempotência”- Responda 2xx rápido (idealmente enfileire e processe depois). Qualquer resposta não-2xx (ou timeout) é tratada como falha.
- Retentativas: entregas falhas são re-tentadas com backoff (até 10
tentativas). Trate o seu handler como idempotente: use o
iddo evento (X-Lidmo-Event-Id) para descartar duplicatas. - Log: cada entrega (status, tentativas, erro) fica registrada e visível no console em Entregas.