Integração

WhatsApp Business API no n8n e Make: automação oficial

Tutorial: automatize a WhatsApp Business API no n8n e no Make com webhook assinado e API REST, sem risco de bloqueio. Inclui fluxo com IA e CRM.

Pessoa programando em um computador na mesa de trabalho
Foto ilustrativa · Pexels
Neste artigo

Para automatizar a WhatsApp Business API no n8n ou no Make você precisa de duas peças: um webhook que recebe cada mensagem no seu fluxo e uma chamada HTTP que envia a resposta pela API oficial da Meta. Não existe nó mágico. O que muda em relação a uma ferramenta de sessão é que o número está na Cloud API, então o envio segue regras da Meta (janela de 24 horas, template aprovado fora dela) e o risco de bloqueio por "automação não autorizada" desaparece. Este guia monta quatro receitas, do responder simples ao atendimento com IA, com JSON pronto para importar no n8n.

O que você vai montar

Qualquer fluxo de WhatsApp em n8n ou Make se reduz a três movimentos:

  1. Receber: a mensagem chega num nó Webhook, assinada, com o corpo cru que a Meta entregou.
  2. Decidir: o fluxo olha o que chegou, consulta o CRM, chama um modelo de IA ou apenas bate uma regra.
  3. Enviar: um nó HTTP Request faz POST na API REST com texto livre ou com um template aprovado.

Com um número conectado ao Frame Conexa, o token da Meta não passa pelo n8n. O fluxo fala com https://frameconexa.com/api/v1 usando um token fc_ de escopo limitado, e o Conexa faz o resto: assina o webhook, deduplica reenvios da Meta, serializa o ritmo de envio e devolve o motivo de cada recusa. Se você quer entender o que existe por baixo, o pilar WhatsApp Cloud API: como integrar com webhook e API REST explica cada peça. Aqui o foco é o fluxo.

Por que não usar a API de sessão nos seus fluxos

Há duas famílias de "API de WhatsApp". Uma é a Cloud API da Meta, em que a empresa cadastra o número na plataforma oficial e envia mensagens por HTTP com regras públicas. A outra é a API de sessão: um servidor abre o WhatsApp Web com o seu número, lê a tela e injeta mensagens como se fosse você digitando. Evolution API, Z-API e similares são exemplos dessa categoria. O comparativo completo está em API oficial vs não oficial do WhatsApp; para um fluxo de automação, três diferenças pesam.

A Meta proíbe a sessão automatizada. As Messaging Guidelines do WhatsApp vetam "clientes não oficiais, envio em massa, mensagens automáticas ou automação que prejudique o WhatsApp ou seus usuários", com sanção que vai do aviso ao banimento permanente, e a Central de Ajuda aponta a WhatsApp Business Platform como a alternativa legítima. Um fluxo de n8n rodando 24 horas por dia sobre uma sessão é exatamente o padrão que a detecção por aprendizado de máquina procura.

A sessão não tem regra, e por isso não tem proteção. Na API oficial, mandar mensagem livre fora da janela de 24 horas devolve o erro 131047 e nada sai. Na sessão, sai. O fluxo "funciona" até o número ser banido, sem nenhum sinal intermediário.

A sessão cai sozinha. Celular sem bateria, WhatsApp Web deslogado, atualização do app: o fluxo para e ninguém avisa. Na Cloud API o número fica na infraestrutura da Meta, e quando a autorização é revogada existe um evento para isso, que é a receita 4 deste guia.

Se o seu número hoje está no aplicativo do celular, não é preciso abrir mão dele: a modalidade de coexistência mantém o app funcionando e liga o mesmo número à API.

Pré-requisitos: número conectado, token de API e URL de webhook

Antes do primeiro nó, três coisas precisam existir:

Peça Onde sai Para que serve
Número conectado Painel do Frame Conexa, "Conectar WhatsApp" É a instância que envia e recebe. O id dela é um UUID que aparece em GET /api/v1/instances
Token fc_ Configurações → API Autentica cada chamada do fluxo: Authorization: Bearer fc_SEU_TOKEN
URL de webhook e segredo Configurações → API, ou PUT /api/v1/webhook-config É para onde o Conexa entrega os eventos. O segredo assina cada entrega

O token aparece uma única vez e o servidor guarda só o hash. Crie um token por fluxo: se um vazar, você revoga sem derrubar os outros. No n8n, guarde-o numa credencial do tipo Header Auth, nunca dentro do nó, para que ele não vá junto quando você exportar o workflow. As regras completas estão em Autenticação.

A URL de webhook precisa ser HTTPS e pública. IP privado, localhost, credenciais na URL e redirecionamento são recusados na hora de salvar. No n8n Cloud a URL de produção do nó Webhook já atende; num n8n próprio é preciso um proxy com TLS na frente.

Importante: mensagem livre só pode sair dentro da janela de 24 horas que a pessoa abre ao escrever para você. Fora dela, só template aprovado pela Meta. Toda receita abaixo respeita isso, e vale ler a janela de 24 horas antes de desenhar qualquer fluxo que envie horas depois do contato.

Receita 1 (n8n): responder mensagens recebidas

O fluxo mais simples: alguém escreve, o n8n recebe, valida a assinatura, monta uma resposta e envia. Quatro nós.

Nó Webhook, verificação da assinatura, decisão e envio

Nó Webhook. Método POST, caminho próprio, resposta "Immediately" e a opção Raw Body ligada. Os dois últimos são obrigatórios. Responder na hora é o que a doc do Conexa pede: devolva 200 e processe depois. Sem isso, um nó de IA lento na sequência segura a resposta e a entrega entra em retentativa. O corpo cru é necessário porque a assinatura X-Frame-Signature-256 é um HMAC-SHA256 dos bytes exatos que chegaram; se o n8n reformatar o JSON antes, o hash nunca bate.

Nó Code. Recalcula o HMAC com o segredo do webhook, compara em tempo constante e descarta o que não interessa. Aqui mora a decisão mais importante da receita: o evento messages traz tanto mensagens recebidas (payload.messages[]) quanto confirmações de entrega das suas (payload.statuses[]). Responder a um status é conversar sozinho. E o tipo smb_message_echoes é o que você mesmo mandou pelo aplicativo do celular; responder a ele cria um laço infinito em que o fluxo responde à própria resposta.

Nó HTTP Request. POST https://frameconexa.com/api/v1/instances/SUA_INSTANCIA/messages, autenticação pela credencial Header Auth, corpo JSON no formato da Cloud API e o header Idempotency-Key com o id da mensagem recebida. Assim, se a Meta reentregar o webhook e o n8n rodar o fluxo de novo, a segunda tentativa de envio volta como duplicada em vez de mandar duas respostas.

O código do nó Code, que é a parte que mais dá trabalho para acertar:

javascript
const crypto = require('crypto');
const item = $input.first();
const raw = Buffer.from(item.binary.data.data, 'base64');
const received = item.json.headers['x-frame-signature-256'] || '';
const expected = 'sha256=' + crypto
  .createHmac('sha256', 'SEU_SEGREDO_DO_WEBHOOK')
  .update(raw)
  .digest('hex');

const a = Buffer.from(received);
const b = Buffer.from(expected);
if (a.length !== b.length || !crypto.timingSafeEqual(a, b)) return [];

const event = JSON.parse(raw.toString('utf8'));
if (event.type !== 'messages') return [];
const msg = (event.payload.messages || [])[0];
if (!msg || msg.type !== 'text') return [];

return [{
  json: {
    idempotencyKey: msg.id,
    body: {
      to: msg.from,
      type: 'text',
      text: { body: `Recebemos sua mensagem: "${msg.text.body}". Já respondemos.` },
    },
  },
}];

Retornar um array vazio encerra a execução naquele ramo: sem assinatura válida, sem mensagem de texto recebida, nada segue para o envio.

Nota: o nó Code do n8n só enxerga o módulo crypto se o servidor estiver com NODE_FUNCTION_ALLOW_BUILTIN=crypto. Sem essa permissão, use o nó Crypto (ação HMAC, SHA256, saída em hex) sobre o corpo cru e compare com um nó IF. A comparação deixa de ser em tempo constante, o que é aceitável para um webhook de baixo volume, mas não para um endpoint exposto a muita tentativa.

Workflow JSON pronto para importar

Copie, importe em Workflows → Import from file e troque o id da instância, o segredo e a credencial.

json
{
  "name": "Frame Conexa - responder mensagens",
  "nodes": [
    {
      "name": "Webhook",
      "type": "n8n-nodes-base.webhook",
      "typeVersion": 2,
      "position": [0, 0],
      "parameters": {
        "httpMethod": "POST",
        "path": "frame-conexa",
        "responseMode": "onReceived",
        "options": { "rawBody": true }
      }
    },
    {
      "name": "Validar e decidir",
      "type": "n8n-nodes-base.code",
      "typeVersion": 2,
      "position": [260, 0],
      "parameters": { "jsCode": "// cole aqui o código do nó Code acima" }
    },
    {
      "name": "Enviar resposta",
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [520, 0],
      "credentials": { "httpHeaderAuth": { "name": "Frame Conexa" } },
      "parameters": {
        "method": "POST",
        "url": "https://frameconexa.com/api/v1/instances/SUA_INSTANCIA/messages",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpHeaderAuth",
        "sendHeaders": true,
        "headerParameters": {
          "parameters": [
            { "name": "Idempotency-Key", "value": "={{ $json.idempotencyKey }}" }
          ]
        },
        "sendBody": true,
        "specifyBody": "json",
        "jsonBody": "={{ JSON.stringify($json.body) }}"
      }
    }
  ],
  "connections": {
    "Webhook": { "main": [[{ "node": "Validar e decidir", "type": "main", "index": 0 }]] },
    "Validar e decidir": { "main": [[{ "node": "Enviar resposta", "type": "main", "index": 0 }]] }
  }
}

A credencial "Frame Conexa" é do tipo Header Auth, com nome Authorization e valor Bearer fc_SEU_TOKEN. Depois de ativar o workflow, cole a URL de produção do nó Webhook em Configurações → API do painel, mande um "oi" para o número de um celular e acompanhe a execução.

Receita 2 (n8n): atendimento com IA que respeita a janela de 24h

A receita 1 vira um atendente com IA trocando o texto fixo por um nó de modelo (OpenAI, Anthropic ou o nó AI Agent do n8n) entre o Code e o HTTP Request. O modelo recebe a mensagem da pessoa, um prompt de sistema com o escopo do negócio e, se você quiser, as últimas mensagens da conversa via GET /api/v1/instances/SUA_INSTANCIA/messages. Ele devolve o texto; o fluxo envia.

O que a IA não pode decidir é o tipo da mensagem. Essa escolha é do fluxo.

Quando a IA pode responder livre e quando precisa de template

A regra é da Meta e tem um único critério: houve mensagem da pessoa nas últimas 24 horas? Se sim, texto livre. Se não, só template aprovado.

Quando o fluxo responde a um webhook de mensagem recebida, a janela está aberta por definição: a pessoa acabou de escrever. O problema aparece nos fluxos que agem depois: o lembrete que sai quatro horas mais tarde, o "ainda tem interesse?" do dia seguinte, o retorno de uma consulta ao estoque que demorou. Para esses, o fluxo precisa guardar o instante da última mensagem recebida por contato (uma Data Table do n8n, um Postgres, um Redis) e, antes de enviar, comparar:

  • Menos de 24 horas desde a última mensagem da pessoa: type: "text", o modelo escreve.
  • Mais de 24 horas: type: "template", com um template aprovado pela Meta, e o modelo no máximo preenche variáveis dentro do que o template permite.

Quem chegou por um anúncio Click-to-WhatsApp tem uma janela maior: se a empresa responde em até 24 horas, a Meta abre um período de 72 horas em que qualquer mensagem é gratuita. O contato traz um campo referral na primeira mensagem, e o painel do Conexa sinaliza essa janela na conversa. Na sua automação, trate a extensão como o que ela é: regra documentada pela Meta e aplicada de boa-fé, sem confirmação por mensagem. Os detalhes estão em anúncio Click-to-WhatsApp.

Dois cuidados que não são de código. Primeiro, custo: até hoje a resposta livre dentro da janela não é cobrada pela Meta, mas a partir de 1º de outubro de 2026 ela passa a ser cobrada por mensagem, com a tarifa da categoria de utilidade do país do destinatário; um atendente de IA que manda cinco balões onde um bastaria vai custar cinco vezes mais, e o artigo sobre preço da WhatsApp Business API acompanha a tabela. Segundo, saída humana: o prompt precisa de um caminho para "não sei, vou chamar alguém", e o fluxo precisa avisar o time nesse caso, porque a Meta mede bloqueios e denúncias, e um bot que insiste é o jeito mais rápido de derrubar a qualidade do número.

Dica: o Conexa publica um guia de integração com IA com prompts prontos para o modelo gerar o receptor de webhook e o cliente de envio conforme o contrato da API. Serve tanto para o n8n quanto para código próprio.

O que a Meta diz sobre bots de atendimento e o que é "AI Provider"

Usar IA para atender o seu próprio negócio é uso normal da plataforma. A página da Meta sobre o tema cita como exemplo permitido uma empresa de viagens operando um bot de suporte. Agendar, confirmar pedido, tirar dúvida de produto, fazer triagem: tudo isso é atendimento, com ou sem modelo de linguagem por trás.

O que a Meta passou a restringir, segundo a mesma página, são os AI Providers: empresas cujo produto principal é um assistente de IA de propósito geral distribuído pelo WhatsApp. Esse caso tem termos e cobrança próprios. A Meta também vende um agente de IA dela, o Meta Business Agent, com cobrança separada por uso; é um produto à parte e não entra no que este guia monta. A receita 2 está do lado do atendimento comum.

Receita 3 (Make): lead do CRM vira mensagem de utilidade

No Make a lógica é a mesma, e a receita mais útil nem precisa de webhook: o gatilho é o CRM. Um cenário com dois módulos:

  1. Gatilho do CRM (HubSpot, Pipedrive, RD Station, o que você usa): "novo negócio" ou "etapa alterada".
  2. HTTP → Make a request: POST na API do Conexa com um template de utilidade, por exemplo a confirmação de que a proposta foi enviada.

Como o lead em geral não escreveu para você nas últimas 24 horas, a mensagem é obrigatoriamente um template. A categoria certa é utilidade, porque a mensagem é consequência de uma ação da pessoa e não uma oferta. O corpo:

json
{
  "to": "5511999990000",
  "type": "template",
  "template": {
    "name": "proposta_enviada",
    "language": { "code": "pt_BR" },
    "components": [
      {
        "type": "body",
        "parameters": [
          { "type": "text", "text": "Ana" },
          { "type": "text", "text": "PROP-2041" }
        ]
      }
    ]
  }
}

No módulo HTTP, informe os headers Authorization: Bearer fc_SEU_TOKEN, Content-Type: application/json e Idempotency-Key com o id do negócio no CRM, para que uma reexecução do cenário não mande duas vezes. O telefone vai em E.164 sem o sinal de mais: 5511999990000. A quantidade de variáveis tem que ser exatamente a do template aprovado, senão a Meta recusa com o código 132000.

Dois pontos sobre política. Template de utilidade ainda exige que a pessoa tenha dado o número e aceitado receber mensagens da sua empresa; o consentimento é da Business Messaging Policy da Meta, não do provedor. E se o fluxo for um convite comercial, e não uma consequência de algo que a pessoa fez, a categoria é marketing, o que exige um número de marketing no Conexa e entra nas regras de envio em massa oficial.

Para receber webhooks no Make, o módulo Custom Webhook funciona, mas confira se a sua versão consegue expor o corpo bruto para o cálculo do HMAC. Se não conseguir, use um caminho longo e aleatório na URL como barreira mínima e trate o conteúdo como não confiável: antes de qualquer ação com efeito, confirme a mensagem pela API com GET /instances/:id/messages.

Receita 4: avisar o time quando um número cai

Todo número da Cloud API pode perder a autorização: o dono revoga o acesso no Business Manager, a Meta remove o parceiro, ou uma assinatura vence. Quando isso acontece, o envio passa a devolver 409 e nada mais sai. Sem aviso, o time descobre pelo cliente que reclamou.

O Conexa emite um evento instance_status no mesmo webhook, com o mesmo envelope dos demais:

json
{
  "type": "instance_status",
  "clientId": "8",
  "instanceId": "6ed76b84-4d65-4f3d-88c1-8d4174bdce73",
  "customerId": null,
  "customerRef": null,
  "payload": {
    "status": "disconnected",
    "phoneNumberId": "1234567890",
    "displayPhone": "+55 11 99999-0000",
    "kind": "marketing",
    "disconnectReason": {
      "code": "token_revoked",
      "message": "A autorização do Frame Conexa na Meta expirou ou foi revogada. Reconecte este número para emitir uma nova autorização."
    }
  }
}

O fluxo é curto: no nó Code da receita 1, adicione um ramo para event.type === 'instance_status' e mande payload.displayPhone, payload.status e payload.disconnectReason.message para um nó de Slack, e-mail ou Telegram. Os códigos que chegam em disconnectReason.code são token_revoked, account_offboarded, partner_removed, removed_from_frame_conexa e subscription_expired, e a mensagem já vem escrita para ser mostrada a uma pessoa.

Quando alguém reconecta o número no painel, chega um instance_status com status: "connected". É o evento que permite ao fluxo voltar a enviar sozinho, sem ninguém precisar lembrar de reativá-lo. Guarde o estado por instanceId, que é o mesmo UUID de GET /api/v1/instances; o clientId existe por compatibilidade e não aparece em nenhuma resposta da API.

Atenção: um fluxo que envia com o número caído acumula erros 409 e, se tiver retentativa automática, pode disparar dezenas de chamadas inúteis por minuto. Ao receber disconnected, pause os cenários de envio; ao receber connected, retome.

Alternativa ao webhook: agente com MCP

Nem toda automação precisa de um fluxo desenhado. Quando a tarefa é do operador, e não do cliente ("resuma o que ficou sem resposta hoje", "confirme as consultas de amanhã"), um agente de IA conectado por MCP faz o trabalho em linguagem natural, sem nó nenhum. O Conexa expõe um servidor MCP em /mcp, autenticado pelo mesmo token fc_, com as mesmas ferramentas da API e uma confirmação dupla antes de qualquer envio: o agente mostra o preview, você aprova, e só então a mensagem ou a campanha sai.

As duas abordagens convivem no mesmo número. O n8n cuida do que precisa acontecer toda vez, sem ninguém olhando; o MCP cuida do que uma pessoa pede quando quer. O guia MCP para WhatsApp mostra a configuração no Claude, no Cursor e no Claude Code.

Erros comuns nos fluxos

Os erros abaixo aparecem em quase todo fluxo novo. A coluna "de quem" importa: a suspeita natural é que o limite seja do provedor, e na maior parte das vezes é da Meta.

Sintoma Código De quem O que fazer
Fluxo responde à própria mensagem sem parar nenhum do fluxo Ignore smb_message_echoes e payload.statuses; responda só a payload.messages
Mesma resposta enviada duas vezes nenhum da Meta, esperado Reentregas são normais. Use messages[].id como Idempotency-Key
401 em toda chamada 401 do token Token ausente, revogado ou colado com espaço. Gere outro em Configurações → API
"instância desconectada" 409 (Graph 190) da autorização na Meta Reconecte o número no painel. A receita 4 avisa antes
Mensagem livre recusada 131047 da Meta A janela de 24 horas fechou. Envie um template aprovado
Destinatário sem entrega 131026 da Meta O número não tem WhatsApp ativo. Tire do público, reenviar dá o mesmo resultado
Marketing não entregue 131049 da Meta, por pessoa A pessoa já recebeu marketing demais somando todas as empresas. Espere pelo menos 24 horas
Variáveis não batem 132000 do template A quantidade de parâmetros não é a do template aprovado
Muitas chamadas 429 do Conexa 120 requisições por minuto por token. Respeite o Retry-After
"resultado incerto" 502 com ambiguous: true da rede ou da Meta A mensagem pode ter saído. Não reenvie às cegas; confira em GET .../messages

O último merece uma regra no fluxo: a retentativa automática do nó HTTP Request do n8n precisa ficar desligada para essa rota, ou ser condicionada a ambiguous ausente. Com Idempotency-Key no envio, repetir a mesma chave e o mesmo corpo é seguro e devolve 409 SEND_IN_PROGRESS enquanto o primeiro ainda roda; sem a chave, cada repetição é uma mensagem nova. O dicionário completo, com o que fazer em cada caso, está em erros da API do WhatsApp e em Erros e limites.

Perguntas frequentes

Dá para usar o nó nativo WhatsApp Business Cloud do n8n com o Frame Conexa?

Não diretamente. O nó nativo do n8n fala com o Graph API da Meta usando o token de acesso e o phone number id da sua conta, que são justamente o que o Conexa guarda cifrado para o número não depender de um token solto num workflow. Com o Conexa, o envio é pelo nó HTTP Request contra https://frameconexa.com/api/v1, e o recebimento é pelo nó Webhook genérico com Raw Body ligado, como na receita 1. O formato do corpo de envio é o mesmo da Cloud API, então quem já montou um payload para o nó nativo só troca a URL e o header.

Meu bot de IA pode responder qualquer mensagem no WhatsApp?

Pode responder o que for atendimento do seu negócio, dentro da janela de 24 horas aberta pela pessoa. É o uso que a Meta descreve como permitido, e o exemplo dela é um bot de suporte de uma empresa de viagens. O que a Meta restringe, segundo a página sobre AI Providers, é oferecer um assistente de IA de propósito geral como produto pelo WhatsApp. E fora da janela nem o bot nem uma pessoa mandam texto livre: é template aprovado ou nada.

O que acontece se o fluxo mandar mensagem fora da janela de 24h?

A Meta recusa com o código 131047 e a mensagem não sai. Não é cobrada, porque a Meta só cobra mensagem entregue, mas também não chega. O Conexa devolve o erro no corpo da resposta com o código da Meta, e o painel mostra o motivo como "janela fechada". A correção é no desenho do fluxo: guardar o instante da última mensagem recebida por contato e trocar para type: "template" quando passaram mais de 24 horas.

Como saber no n8n se a mensagem foi entregue?

Pela confirmação de entrega, que chega no mesmo webhook. A resposta do POST traz o id da mensagem em result.messages[0].id, um valor que começa com wamid.. Depois disso o Conexa entrega eventos messages com payload.statuses[], cada um com o mesmo id e um status que evolui por sent, delivered, read ou failed; em failed, o motivo vem em errors[]. Guarde o id ao enviar e case no webhook. Se preferir consultar em vez de escutar, GET /api/v1/instances/:id/messages lista as mensagens com o estado atual.

Preciso de VPS para rodar a automação?

Não, desde que o webhook tenha uma URL HTTPS pública. O n8n Cloud e o Make já fornecem isso. Um n8n instalado no seu servidor precisa de um proxy com certificado TLS na frente, porque o Conexa recusa URL sem HTTPS, com IP privado ou apontando para localhost. O que não dá é rodar o n8n no seu notebook e esperar que o webhook chegue: a entrega precisa encontrar o endereço na internet.

Próximo passo

Conecte um número e gere o primeiro token nos planos por número; o webhook e a API vêm no mesmo plano, sem cobrança por mensagem da nossa parte. Com o token em mãos, o quickstart mostra a primeira chamada em um minuto, e a receita 1 acima é o workflow para importar em seguida.

Leia também

Conecte o número que você já usa à API oficial do WhatsApp.

Sem trocar de número, sem perder o aplicativo e sem cobrança por mensagem da nossa parte. Você paga por número; a Meta, você paga direto.