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ça
if (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.
Fonte: https://api-wa.me/