Ir para o conteúdo
OmniChannels.ai

Webhooks do WhatsApp: eventos, segurança e novas tentativas

Como funcionam os webhooks do WhatsApp: eventos de mensagem e status, handler confiável, assinatura da Meta, retries, idempotência e eventos perdidos.

Atualizado em 10 min de leitura

Por OmniChannels.ai Editorial Team · Revisado por BroadNet Messaging Solutions Team

Integração

Resposta curta

Um webhook do WhatsApp é um endpoint HTTPS no seu servidor que recebe eventos: status de entrega das mensagens que você enviou e mensagens que os clientes enviam para você. Com a OmniChannels.ai, os status chegam como SUBMITTED, SENT, DELIVERED, READ, FAILED ou REJECTED. Guarde o corpo bruto, responda 2xx rapidamente, deduplique pelo ID da mensagem e processe de forma assíncrona. A Meta assina seus próprios webhooks; nossa documentação não define cabeçalho de assinatura, então proteja o seu endpoint no nível do transporte e da aplicação.

Nesta página
  1. O que são webhooks do WhatsApp e por que usá-los?
  2. Quais eventos e status vou receber?
  3. Como configuro o endpoint?
  4. Como é o payload?
  5. Como escrevo um handler confiável?
  6. Como protejo um webhook do WhatsApp?
  7. O que acontece quando a entrega falha?
  8. Como recupero eventos perdidos?
  9. Exemplo prático: o pipeline de notificações de uma varejista
  10. Quais são os erros comuns?
  11. Como a OmniChannels.ai ajuda

Pontos principais

  • Os webhooks enviam por push status e mensagens recebidas ao seu endpoint HTTPS para que você não precise fazer polling; os status do WhatsApp são normalizados para SUBMITTED, SENT, DELIVERED, READ, FAILED e REJECTED.
  • Um handler confiável faz três coisas, nesta ordem: armazena o evento bruto, devolve 2xx e só então processa de forma assíncrona e idempotente.
  • Os status podem chegar fora de ordem ou duplicados, então atribua uma ordem de avanço a eles e nunca deixe um SENT tardio sobrescrever um DELIVERED já armazenado.
  • A Meta assina os webhooks enviados a apps com o cabeçalho X-Hub-Signature-256, mas a especificação da API da OmniChannels.ai não define assinatura de webhook, então use HTTPS, um caminho imprevisível e validação do corpo.
  • Se eventos foram perdidos, leia o status do WhatsApp por lote no endpoint bulk-insights em vez de reenviar mensagens.

Este guia é para engenheiros que precisam receber eventos do WhatsApp de forma confiável: status de entrega das mensagens que enviam e mensagens recebidas de clientes. Ele explica como os webhooks funcionam, o que construir no handler, como a segurança difere entre os webhooks da Meta e os nossos e o que fazer quando eventos se perdem.

O que são webhooks do WhatsApp e por que usá-los?

Webhooks do WhatsApp são callbacks HTTP. Quando uma mensagem muda de estado ou um cliente escreve para você, a plataforma envia um POST com um corpo JSON ao seu endpoint. Você não precisa fazer polling e vê os eventos conforme acontecem.

Duas famílias de eventos importam:

  • Eventos de status das mensagens que você enviou: enfileirada, enviada, entregue, lida, com falha.
  • Mensagens recebidas de clientes, que abrem ou estendem a janela de atendimento ao cliente de 24 horas. Veja nosso guia da janela.

Uma chamada de envio apenas informa que as mensagens foram enfileiradas. O webhook é onde você descobre o que aconteceu com cada destinatário.

Quais eventos e status vou receber?

Na OmniChannels.ai, todos os canais informam os mesmos status normalizados, então um único handler pode atender WhatsApp, SMS e os demais.

Status Significado Final?
SUBMITTED Aceita pela plataforma e enfileirada Não
SENT Entregue ao canal Não
DELIVERED Confirmada no dispositivo do destinatário Normalmente; READ pode vir depois
READ Aberta pelo destinatário, onde o canal informa leituras Sim
FAILED Não entregue; o evento traz um motivo, quando disponível Sim
REJECTED Recusada, por exemplo por conteúdo bloqueado ou remetente não registrado Sim

Trate os status como uma progressão que pode chegar fora de ordem e espere novos valores ao longo do tempo. Não falhe diante de um status que você não reconhece. Veja status de entrega de mensagens explicados.

Como configuro o endpoint?

Exponha um endpoint HTTPS, informe a URL ao seu provedor e teste com o seu próprio número.

  1. Crie um endpoint que aceite POST com um corpo JSON, por exemplo https://api.example.com/webhooks/omnichannels.
  2. Envie a URL à nossa equipe ou ao administrador da sua conta para configurá-la na sua conta. Os revendedores podem ter um webhook separado por subconta.
  3. Envie uma mensagem de teste para o seu próprio número e confirme que os eventos chegam.

Durante o desenvolvimento, um túnel como o ngrok dá ao seu servidor local uma URL HTTPS pública. Se você também conectar um app diretamente à Meta, a verificação de endpoint da Meta é uma etapa separada: uma requisição GET com um verify token e um valor hub.challenge, à qual você responde 200 com o challenge, como descrito na documentação de endpoint de webhook da Meta.

Como é o payload?

Varia por canal. A especificação da API não define um único esquema de webhook, então registre primeiro o corpo bruto e mapeie os campos de que precisa a partir de eventos reais da sua conta. O exemplo mostra o tipo de informação que um evento de entrega traz e é apenas ilustrativo.

{
  "messageId": "2603121407537573731",
  "channel": "SMS",
  "destination": "447700900123",
  "status": "DELIVERED",
  "timestamp": "2026-10-10T09:15:42Z",
  "reason": null
}

Não programe com base nesses nomes de campos sem conferir um evento real. Peça ao seu engenheiro de onboarding exemplos de payload por canal e guarde-os como fixtures de teste. Para a documentação mais ampla, veja a referência de webhooks.

Como escrevo um handler confiável?

Faça três coisas, nesta ordem: armazene o evento bruto, confirme com um 2xx e depois processe de forma assíncrona. O handler abaixo segue o padrão da nossa documentação.

import express from "express";

const app = express();

// Capture o corpo bruto para guardá-lo exatamente como foi recebido.
app.post(
  "/webhooks/omnichannels",
  express.json({ verify: (req, _res, buf) => { req.rawBody = buf.toString("utf8"); } }),
  async (req, res) => {
    try {
      await db.webhookEvents.insert({ receivedAt: new Date(), body: req.rawBody });
    } catch (err) {
      return res.sendStatus(500); // o armazenamento falhou: deixe o evento ser reenviado
    }
    res.sendStatus(200);          // confirme rápido
    queue.publish("status-events", req.body); // faça o trabalho de verdade em outro lugar
  },
);

// Worker: processamento idempotente
async function processEvent(event) {
  const id = event.messageId ?? event.message_id ?? event.id; // mapeie por canal
  const status = event.status;
  const rank = { SUBMITTED: 1, SENT: 2, DELIVERED: 3, READ: 4, FAILED: 4, REJECTED: 4 };

  const current = await db.messages.findOne({ providerId: id });
  if (!current) return; // mensagem desconhecida: registre e investigue
  if ((rank[status] ?? 0) <= (rank[current.status] ?? 0)) return; // duplicado ou desatualizado

  await db.messages.update({ providerId: id }, { status, updatedAt: new Date() });
}
from datetime import datetime, timezone
from flask import Flask, request

app = Flask(__name__)

RANK = {"SUBMITTED": 1, "SENT": 2, "DELIVERED": 3, "READ": 4, "FAILED": 4, "REJECTED": 4}


@app.post("/webhooks/omnichannels")
def omnichannels_webhook():
    raw = request.get_data(as_text=True)
    try:
        db.webhook_events.insert({"received_at": datetime.now(timezone.utc), "body": raw})
    except Exception:
        return "", 500           # o armazenamento falhou: deixe o evento ser reenviado
    queue.publish("status-events", raw)  # processe de forma assíncrona
    return "", 200               # confirme rápido

Os objetos db e queue são o seu próprio armazenamento e fila de jobs. O mapa rank é o que torna o processamento idempotente: um evento duplicado ou desatualizado não representa um avanço, então é ignorado.

Regras para um handler confiável

  • Responda em poucos segundos. Não faça trabalho pesado antes de responder.
  • Devolva 2xx apenas depois que o evento estiver armazenado. Se o armazenamento falhar, devolva 5xx.
  • Deduplique pelo ID da mensagem. O mesmo status pode chegar mais de uma vez.
  • Nunca reenvie uma mensagem a partir do handler. Decida sobre novas tentativas em um job separado, depois de conferir o status.
  • Guarde o corpo bruto para diagnóstico e para reproduzir eventos depois de uma correção.

Como protejo um webhook do WhatsApp?

Depende de quem envia ao seu endpoint. A Meta assina os webhooks que envia a apps registrados nela. A especificação da API da OmniChannels.ai não define cabeçalho de assinatura de webhook, então não espere por um.

Meta para o seu próprio app OmniChannels.ai para o seu endpoint
Assinatura Cabeçalho X-Hub-Signature-256, conforme a documentação da Meta Nenhuma definida na especificação da API
Verificação HMAC-SHA256 do payload bruto com o segredo do app, comparado com o cabeçalho Não se aplica
Seus controles Verificar a assinatura em todo POST HTTPS com certificado válido, um caminho imprevisível, validação rigorosa do corpo

Para o esquema da Meta, a documentação dela diz para gerar um hash HMAC-SHA256 do payload JSON usando o segredo do seu app e compará-lo com o valor após sha256= no cabeçalho X-Hub-Signature-256. O próprio HMAC é definido na RFC 2104. Calcule-o sobre os bytes brutos, não sobre um objeto serializado de novo, e compare em tempo constante.

Para o nosso endpoint:

  • Use apenas HTTPS, com um certificado válido.
  • Use um caminho longo e imprevisível e troque-o se vazar.
  • Valide o formato do corpo e rejeite qualquer coisa inesperada.
  • Trate os eventos como notificações. Antes de uma ação irreversível, como um reembolso ou um bloqueio por fraude, confirme o estado com uma consulta.

O que acontece quando a entrega falha?

As novas tentativas dependem de quem envia. A documentação da Meta diz que ela repete uma entrega com falha com frequência decrescente por até 7 dias, o que pode gerar notificações duplicadas. Esse é um motivo para ser idempotente mesmo que você raramente veja duplicatas. Para eventos da nossa plataforma, confirme o comportamento de novas tentativas com o seu engenheiro de onboarding em vez de presumir que seja igual ao da Meta.

De todo modo, construa pensando tanto em perda quanto em duplicação: seu endpoint pode estar fora do ar durante um deploy, e uma regra de firewall pode descartar requisições silenciosamente.

Como recupero eventos perdidos?

Consulte o lote, não reenvie a mensagem.

Necessidade Chamada Observações
Ler o status do WhatsApp por destinatário GET /whatsapp/message/bulk-insights Filtre um lote por status ou destination; paginado com page e size
Reenviar relatórios de entrega de SMS POST /sms/resendDlr Filtre por startDate, endDate, senderId e messageStatus
curl "https://api.broadnet.me/whatsapp/message/bulk-insights?batch_Id=2609091405000000001&page=0&size=100" \
  -H "Authorization: Bearer $BROADNET_TOKEN"

batch_Id é o ID devolvido pela chamada de envio, e page começa em zero. Execute uma conciliação noturna que leia os lotes do dia anterior e preencha as lacunas.

Checklist de solução de problemas

  1. A URL está configurada na conta ou subconta correta?
  2. O endpoint é acessível por HTTPS com um certificado válido?
  3. Ele responde 2xx rapidamente ou dá timeout?
  4. Uma regra de firewall ou de WAF está bloqueando as requisições?
  5. Você registra o corpo bruto antes de fazer o parsing, para que um erro de parser não esconda o evento?

Exemplo prático: o pipeline de notificações de uma varejista

A "Souq Rafiq" (sintética), uma varejista dos Emirados Árabes Unidos, envia atualizações de pedidos por WhatsApp e quer um status preciso na sua ferramenta de pedidos.

  1. Os pedidos são enviados com sendbulk, e o batchId é guardado no pedido. Veja enviar uma mensagem de WhatsApp por API.
  2. O endpoint do webhook grava cada evento em uma tabela e depois devolve 200.
  3. Um worker ordena os status e atualiza o estado da mensagem do pedido.
  4. Eventos FAILED criam uma tarefa para o suporte com o motivo, e um fallback por SMS é avaliado conforme o fallback entre canais.
  5. As mensagens recebidas de clientes são encaminhadas à caixa de entrada compartilhada para que os atendentes respondam dentro da janela.
  6. Um job noturno chama o bulk-insights para os lotes de ontem e corrige o que tiver sido perdido.

Quais são os erros comuns?

  • Trabalho pesado antes de responder, que causa timeouts e entregas repetidas.
  • Confirmar antes de armazenar, o que perde eventos quando o armazenamento falha.
  • Confiar na ordem. Um SENT tardio sobrescrevendo DELIVERED.
  • Programar com base no payload ilustrativo em vez de eventos reais.
  • Serializar o JSON de novo antes de verificar uma assinatura, o que altera os bytes.
  • Reenviar a partir do handler, o que pode gerar loops.
  • Limites: este guia descreve o comportamento documentado por nós. A política de novas tentativas e os campos do payload da sua conta devem ser confirmados durante o onboarding.

Como a OmniChannels.ai ajuda

A OmniChannels.ai envia por push status de entrega e mensagens recebidas de WhatsApp, SMS, RCS e outros canais ao seu webhook em um único formato normalizado, com webhooks separados por subconta para revendedores. A BroadNet é uma Meta Business Solution Provider oficial, então os requisitos de webhook da própria Meta são tratados por nós, e você trabalha com a nossa API. Leia a referência de webhooks e a documentação da API de WhatsApp ou veja como os eventos aparecem na caixa de entrada compartilhada.

Perguntas frequentes

O que é um webhook do WhatsApp?

Um webhook do WhatsApp é uma URL no seu servidor que a plataforma chama com um HTTP POST sempre que algo acontece, como uma mensagem ser entregue, lida ou falhar, ou um cliente enviar uma mensagem para você. Ele substitui o polling. Você expõe um endpoint HTTPS, compartilha-o com o seu provedor e processa os eventos JSON que ele recebe.

Como verifico a assinatura de um webhook do WhatsApp?

Para um webhook que a Meta envia diretamente ao seu próprio app, a documentação da Meta diz para calcular um HMAC-SHA256 do payload bruto com o segredo do seu app e compará-lo com o cabeçalho X-Hub-Signature-256. Para o webhook da OmniChannels.ai, a especificação da API não define cabeçalho de assinatura, então conte com HTTPS, um caminho imprevisível e a validação do corpo.

O que acontece se o meu endpoint de webhook estiver fora do ar?

A documentação da Meta diz que ela repete as entregas com falha com frequência decrescente por até 7 dias, o que pode gerar duplicatas. Para eventos da nossa plataforma, confirme o comportamento de novas tentativas com o seu engenheiro de onboarding e use o endpoint bulk-insights para ler o status do WhatsApp por destinatário de um lote. No SMS, o endpoint resendDlr reenvia os relatórios.

Como trato eventos de webhook duplicados?

Torne o processamento idempotente. Busque a mensagem pelo ID, compare a ordem do status recebido com a do armazenado e ignore eventos que não representem um avanço. Aplicar o mesmo evento duas vezes deve ter o mesmo efeito que aplicá-lo uma vez. Guarde o corpo bruto de cada evento para poder reproduzi-lo depois de corrigir um bug.

Com que rapidez o meu endpoint deve responder?

Em poucos segundos. Guarde o evento bruto, devolva um 2xx e faça o trabalho de verdade em uma fila ou worker. Não chame outros serviços, não envie mensagens nem execute consultas pesadas antes de responder. Se o armazenamento falhar, devolva um 5xx para que o remetente tente de novo, em vez de confirmar um evento que você perdeu.

Posso usar um webhook para enviar uma resposta automaticamente?

Sim, mas não de dentro do handler. Confirme o evento e depois decida a resposta em um job separado. Dentro da janela de atendimento ao cliente de 24 horas você pode enviar uma mensagem livre; fora dela, precisa de um template aprovado. Nunca reenvie uma mensagem a partir do próprio handler do webhook, para evitar loops e duplicatas.

Fontes

  1. Webhooks overview — WhatsApp Business Platform, Meta for Developers
  2. Create a webhook endpoint — WhatsApp Business Platform, Meta for Developers
  3. RFC 2104: HMAC: Keyed-Hashing for Message Authentication