1

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ç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)
CustoMensalidade da instância + cobrança da Meta por template que você iniciaMensalidade fixa, sem custo por mensagem
Risco de bloqueioNão existe por usar a API — o número opera dentro das regras da MetaExiste. Depende do comportamento do número: volume, velocidade e denúncias
Selo verdeElegível, mediante aprovação da MetaNão
Limite de disparoTier da Meta: começa limitado e cresce com a qualidade do númeroSem limite da plataforma; o limite prático é o comportamento do número
AtivaçãoEmbedded Signup, o fluxo OAuth da própria MetaLeitura de QR Code, como o WhatsApp Web
Uso idealConformidade, selo verde, campanha em volumeAtendimento, 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.

Carregando publicação patrocinada...