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:

  • providerwhatsapp, instagram ou messenger
  • official — 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.

Source

3 views·1 share