POST com Content-Type: application/json. O header x-coexy-signature carrega a assinatura HMAC-SHA256 — verifique-a antes de processar qualquer dado.
Documentation Index
Fetch the complete documentation index at: /llms.txt
Use this file to discover all available pages before exploring further.
Eventos enviados pelo Coexy — o payload segue o formato nativo da Meta (WhatsApp Cloud API).
POST com Content-Type: application/json. O header x-coexy-signature carrega a assinatura HMAC-SHA256 — verifique-a antes de processar qualquer dado.
X-Coexy-Signature: sha256=<hex> — assinatura HMAC do body
User-Agent: Coexy-Webhooks/1.0
Content-Type: application/json
{
"object": "whatsapp_business_account",
"entry": [{
"id": "<WHATSAPP_BUSINESS_ACCOUNT_ID>",
"changes": [{
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "15550783881",
"phone_number_id": "<PHONE_NUMBER_ID>"
},
"contacts": [{ "profile": { "name": "João Silva" }, "wa_id": "5511987654321" }],
"messages": [ /* mensagens recebidas */ ],
"statuses": [ /* atualizações de status */ ]
},
"field": "messages"
}]
}]
}
async function handleWebhook(req: Request): Promise<Response> {
const body = await req.text()
// 1. Verificar assinatura HMAC — obrigatório (ver Segurança)
const valid = await verifySignature(body, req.headers.get('x-coexy-signature') ?? '', secret)
if (!valid) return new Response('Unauthorized', { status: 401 })
// 2. Responder 200 IMEDIATAMENTE — o Coexy considera falha após 10s
processPayload(JSON.parse(body)).catch(console.error)
return new Response('OK', { status: 200 })
}
function processPayload(payload: unknown): void {
const data = payload as { entry?: Array<{ changes?: Array<{ value: Record<string, unknown> }> }> }
for (const entry of data.entry ?? []) {
for (const change of entry.changes ?? []) {
const value = change.value
// Mensagens recebidas
for (const msg of (value.messages as unknown[]) ?? []) {
handleMessage(msg, value)
}
// Status de mensagens enviadas
for (const status of (value.statuses as unknown[]) ?? []) {
handleStatus(status)
}
}
}
}
id de cada mensagem (o wamid) como chave de idempotência ao persistir. O mesmo evento pode chegar mais de uma vez em retentativas automáticas — um upsert com on conflict (wamid) do nothing garante que não haverá duplicatas.