Visão geral
- Webhooks chegam sempre assinados com sua própria
apiKey. Valide a assinatura antes de processar. - Use
express.rawsomente na rota de webhook para preservar o corpo bruto. - Planos free recebem apenas
SESSION-CONNECTEDeSESSION-DISCONNECTED. EventosMESSAGE-*são exclusivos de planos pagos comwebhookMessages = true. - As tipagens
WebhookEvent/WebhookPayloadMapentregam autocomplete imediato: exploreevent.payloadna IDE para descobrir os campos mais recentes.
Exemplo de implementação (Express)
Exemplos rápidos de cada evento
Todos seguem o mesmo envelope{ apiKey, sessionId, type, payload } enviado pelo backend:
SESSION-CONNECTED
SESSION-DISCONNECTED
MESSAGE-RECEIVED
Inclui respostas de botão/lista, edições/deleções e reações já normalizadas.Template hidratado (contas Business)
Templates enviados por contas Business chegam comtype: "templateMessage". O texto (título, corpo e rodapé, quando presentes) é normalizado no campo message. Se o template tiver botões, eles vêm em interact com type: "templateButtons", onde cada botão é quickReply (id), url (url) ou call (phoneNumber).
Importante sobre key
No evento MESSAGE-SENT, o payload.key é o ID principal da mensagem (string). Guarde esse valor: ele aparece como key/referenceKey nos eventos seguintes (MESSAGE-DELIVERED/READ/DELETED/EDITED/REACTION) e permite correlacionar reações, edições e deleções com a mensagem original.
MESSAGE-SENT
MESSAGE-DELIVERED / MESSAGE-READ
MESSAGE-DELETED
Eventos normalizados.MESSAGE-EDITED
MESSAGE-DISCARDED
REACTION-MESSAGE
Normalizado comoNormalizedWebhookMessage.
Payloads por evento
NormalizedWebhookMessage resume: key, fromMe, sender (phone/name/profileImage), type, eventType, referenceKey, message ou mediaUrl/filename/latitude/longitude/interact, timestamp, isBroadcast, historic, responseButtonId, etc. Em templates hidratados (type: "templateMessage"), o campo interact traz { type: "templateButtons", buttons: [...] } quando o template tem botões.
Notas adicionais
- URLs de mídia (
payload.mediaUrl) expiram em até 24h. Baixe imediatamente se precisar armazenar. - Para testes locais você pode gerar o cabeçalho com
zap.webhooks.signPayload(rawBody)e enviarx-locezap-signature/x-locezap-timestampmanualmente.

