Um webhook para WhatsApp, Instagram e Messenger — o formato de payload que elimina o if/else
Se você já integrou WhatsApp num produto, conhece o roteiro. Integra o WhatsApp. Aí o cliente pede Instagram Direct. Depois Messenger. Três APIs, três credenciais, três formatos de webhook e três parsers para manter — para fazer, no fim, a mesma coisa: alguém mandou uma mensagem e você precisa responder.
Este artigo é sobre colapsar isso em uma integração só. Na prática: um endpoint, uma chave, um envelope de webhook, com um campo dizendo de qual canal a mensagem veio.
A ideia: normalizar o envelope, não o conteúdo
A Cloud API da Meta já tem um envelope bem definido: entry[] → changes[] → value → messages[]. Instagram Direct e Messenger também entregam conversas pelo grafo da Meta, mas o payload que chega não é idêntico entre os produtos.
A normalização é direta: manter o envelope da Meta exatamente como ele é e acrescentar um campo na raiz dizendo qual é o canal.
{ "object": "wame", "provider": "instagram", "official": true, "instance": "552199999999", "entry": [{ "changes": [{ "field": "messages", "value": { "messages": [{ "from": "5511999998888", "type": "text", "text": { "body": "Chegou meu pedido?" } }] } }] }]}
Dois campos carregam toda a informação de roteamento:
provider—whatsapp,instagramoumessengerofficial— se veio pela Cloud API da Meta ou pela conexão não oficial por QR Code
O resto é byte por byte a mesma estrutura nos três canais. É esse o truque inteiro, e é por isso que o handler abaixo não tem ramificação.
Lendo: um parser, três canais
A versão ingênua ramifica por canal e duplica o caminho de acesso:
// não façaif (body.provider === 'whatsapp') { const m = body.entry[0].changes[0].value.messages[0]; salvar(m.from, m.text.body);} else if (body.provider === 'instagram') { const m = body.entry[0].changes[0].value.messages[0]; salvar(m.from, m.text.body);}// ...e mais um else pro messenger
Como o envelope não muda, o if não tem motivo para existir:
app.post('/webhook', (req, res) => { const { provider, official, entry } = req.body; const msg = entry?.[0]?.changes?.[0]?.value?.messages?.[0]; if (!msg) return res.sendStatus(200); salvar({ canal: provider, de: msg.from, tipo: msg.type, texto: msg.text?.body, }); res.sendStatus(200);});
Duas observações que evitam incidente em produção:
Responda 200 rápido. Webhooks no padrão da Meta tentam de novo quando a resposta não é 2xx. Confirme o recebimento primeiro e processe numa fila depois — senão um banco lento vira entrega duplicada.
Nunca assuma que messages[0] existe. Eventos de status (entregue, lido) chegam no mesmo endpoint com outro formato dentro de value. O optional chaining ali em cima não é enfeite.
Enviando: a mesma chamada, muda um campo
curl -X POST "https://us.api-wa.me/SUA_KEY/message/text" \ -H "Content-Type: application/json" \ -d '{ "to": "5511999998888", "text": "Seu pedido saiu para entrega", "provider": "whatsapp" }'
Node / TypeScript:
import { Wame, TypeMessage } from '@raphaelvserafim/client-api-whatsapp';const wa = new Wame({ server, key });await wa.message.send({ type: TypeMessage.TEXT, body: { to: '5511999998888', text: 'Seu pedido saiu para entrega', provider: 'instagram', // a única diferença },});
PHP:
use Api\Wame\Wame;$wa = new Wame([ 'server' => 'https://server.api-wa.me', 'key' => 'SUA_KEY',]);$wa->message->sendText('5511999998888', 'Seu pedido saiu para entrega');
Mesmo endpoint, mesma credencial, mesmo formato de resposta. Trocar de canal é trocar uma string.
API oficial ou não oficial: o que muda de verdade
Toda integração de WhatsApp chega nessa bifurcação, e ela merece uma resposta honesta em vez de uma resposta comercial.
Oficial (Cloud API da Meta)
Não oficial (QR Code)
Custo
Mensalidade da instância + cobrança da Meta por template que você inicia
Mensalidade fixa, sem custo por mensagem
Risco de bloqueio
Não existe por usar a API — o número opera dentro das regras da Meta
Existe. Depende do comportamento do número: volume, velocidade e denúncias
Selo verde
Elegível, mediante aprovação da Meta
Não
Limite de disparo
Tier da Meta: começa limitado e cresce com a qualidade do número
Sem limite da plataforma; o limite prático é o comportamento do número
Ativação
Embedded Signup, o fluxo OAuth da própria Meta
Leitura de QR Code, como o WhatsApp Web
Uso ideal
Conformidade, selo verde, campanha em volume
Atendimento, automação, protótipo, custo previsível
A parte que costuma ser omitida: ninguém pode garantir que um número na conexão não oficial não será bloqueado. Quem promete isso está vendendo alguma coisa. O risco vem do comportamento, não da plataforma. Se previsibilidade importa mais que preço, o caminho é a oficial.
Desde 1º de julho de 2025, a Meta cobra por mensagem de template entregue, e não mais por conversa de 24 horas. Responder dentro da janela de 24h aberta pelo cliente é gratuito — a maior parte do atendimento do dia a dia não gera custo por mensagem. Você paga pelos templates que inicia.
O que essa abordagem não resolve
Vale dizer com todas as letras, porque alinha expectativa:
- Paridade de recursos não é total. Instagram e Messenger não têm o sistema de templates do WhatsApp, e o WhatsApp não tem o contexto de resposta a story do Instagram. Um envelope unificado normaliza o transporte, não as capacidades de cada produto.
- Webhook unificado não é caixa de entrada unificada. Se vários atendentes precisam responder do mesmo número, ainda falta algo como o Chatwoot ou uma inbox sua por cima.
- Rate limit continua por canal. Uma credencial só não funde o sistema de tiers da Meta entre os produtos.
Perguntas frequentes
Preciso criar um app no Meta for Developers?
Pelo caminho oficial via Business Partner, não. O app aprovado, o webhook e o token ficam do lado do provedor. Indo direto, sim — mais verificação de negócio, verify token, validação de assinatura HMAC e renovação de token de System User.
Preciso virar Tech Provider para revender?
Não. Dá para conectar a conta oficial dos seus clientes por meio de um parceiro que já tenha a aprovação da Meta.
Consigo continuar usando o número no celular?
Sim, pela Coexistência da Meta: o mesmo número funciona no app WhatsApp Business e na Cloud API ao mesmo tempo. Requisitos: o número precisa estar no app Business, o app precisa ser aberto pelo menos a cada duas semanas, e não pode ser desinstalado nem registrado em outro serviço.
Dá para migrar da não oficial para a oficial depois?
Sim, mantendo o mesmo número. É a principal razão para manter os dois tipos de conexão atrás do mesmo SDK: a migração vira configuração, não reescrita.
E agentes de IA?
Existe um servidor MCP, então assistentes como o Claude conseguem ler e responder conversas nos três canais. Vale saber o limite: o MCP roda dentro de um turno do usuário — o agente age quando você pede. Atendimento automático 24 horas é webhook ou um fluxo no n8n, não MCP.
Resumo
Se você está colocando WhatsApp dentro de um produto, a decisão que mais economiza manutenção não é qual biblioteca usar — é se o seu handler de webhook vai precisar ramificar por canal. Normalize o envelope e o if desaparece.
Documentação, especificação OpenAPI, coleção do Postman e um llms.txt (para integrar com ajuda de IA) estão em api-wa.me/docs. SDKs no npm e no Composer.
Se você integrou Instagram Direct ou Messenger de outro jeito, comenta como estruturou o handler — quero ler.
