Pular para o conteúdo

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.

POST /v1/webhook-endpoints
Authorization: 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}.

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
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)

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);
}
  • 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 id do evento (X-Lidmo-Event-Id) para descartar duplicatas.
  • Log: cada entrega (status, tentativas, erro) fica registrada e visível no console em Entregas.