Guia de implementação · WhatsApp

Qual anúncio trouxe esta conversa?

O cliente pode apagar a mensagem pronta e enviar apenas “oi”. Em anúncios do Facebook ou Instagram que abrem diretamente o WhatsApp, a mensagem pode chegar pela API oficial com dados de origem separados do texto. Este guia ensina a guardar essa origem e identificar anúncio, conjunto, campanha e criativo no atendimento. Referência da Meta.

Começar o guia 4 etapas · Prompts para Claude ou ChatGPT

O caminho: anúncio → WhatsApp oficial → Chatwoot → integração → consulta à Meta → origem visível na conversaVocê pode usar Claude ou ChatGPT para construir o código dessa integração. A conversa com a IA produz os arquivos e as instruções; o programa precisa ser instalado em um ambiente que receba os eventos e permaneça funcionando.

Antes de começar

Separe acesso administrativo ao portfólio empresarial, aplicativo Meta, conta WhatsApp Business e número; acesso autorizado à conta de anúncios; Chatwoot com API e webhooks disponíveis. Para executar o programa, você precisará de hospedagem com HTTPS e armazenamento durável, definidos nas instruções de implantação. Cadastre tokens como variáveis de ambiente no servidor; não os cole na conversa com a IA.

A conexão manual abaixo serve para um número novo ou preparado para Cloud API. Se você mantém o WhatsApp Business no aplicativo, verifique o fluxo de coexistência e sua elegibilidade: ele é separado e pode manter aplicativo e API no mesmo número. Não apague sua conta para executar este guia. Chatwoot: requisitos da conexão, Meta: coexistência.

Etapa 1 de 4

Conecte o WhatsApp pelo caminho oficial

1A. Prepare a conexão na Meta

Abra Meta Developers — Meus aplicativos e siga My Apps → Create App → Connect with customers through WhatsApp. Vincule o portfólio empresarial e a conta WhatsApp Business. Entre em Use cases → Customize → API Setup; interfaces anteriores mostram WhatsApp → API Setup. Adicione o número e conclua a verificação por SMS ou ligação. Anote o Phone Number ID e o WhatsApp Business Account ID. Início oficial.

Para produção, abra as Configurações empresariais da Meta, selecione o portfólio correto e entre em Users → System users. Crie/selecione o usuário do sistema, atribua aplicativo e conta WhatsApp e gere o token com whatsapp_business_management e whatsapp_business_messaging; operações de gestão podem exigir business_management. O token temporário do teste não serve como configuração duradoura. Permissão e acesso ao ativo precisam existir juntos. Tokens e ativos.

Verificar a posse do número e registrá-lo na Cloud API são operações diferentes. Se ainda não estiver registrado, a integração deve executar a chamada abaixo, com o PIN de seis dígitos da verificação em duas etapas — não o código recebido por SMS. Não repita o registro de um número já conectado. Registro do número.

Registrar um número ainda não conectadoExemplo HTTP
HTTP · adapte os campos
POST https://graph.facebook.com/{VERSAO_GRAPH}/{PHONE_NUMBER_ID}/register
Authorization: Bearer {TOKEN_WHATSAPP}
Content-Type: application/json

{"messaging_product":"whatsapp","pin":"{PIN_DE_6_DIGITOS}"}

1B. Ligue o número ao Chatwoot

Acesse o painel Chatwoot da sua equipe. Se você usa a versão hospedada, entre no Chatwoot Cloud. Em instalação própria, use o endereço fornecido pela sua empresa. Os menus de caixas de entrada, atributos e webhooks abaixo ficam nesse painel; o endereço exato depende da instalação.

Abra Settings → Inboxes → Add Inbox → WhatsApp → Manual Setup. Informe telefone, Phone Number ID, WhatsApp Business Account ID e token. Escolha os atendentes. O Chatwoot fornece o endereço de recebimento e o token de verificação. Configuração manual.

Na Meta, entre em Use cases → Customize → Configuration — ou WhatsApp → Configuration — e preencha Callback URL e Verify token com esses dados. Confirme em Verify and save e assine o campo messages. Verifique também a inscrição do aplicativo na conta WhatsApp: GET /{WABA_ID}/subscribed_apps; quando ausente, faça a inscrição com POST no mesmo caminho. Callback, inscrição da conta.

Envie uma mensagem de outro telefone e responda pelo painel. Só avance depois de confirmar entrada e resposta.

Etapa 2 de 4

Peça à IA o programa que guarda a origem

No painel Chatwoot da sua equipe, em Settings → Custom Attributes → Add Custom Attribute, crie atributos de Conversation, tipo Text: rastreio_anuncio_id, rastreio_clique_id, rastreio_mensagem_id, rastreio_data, rastreio_anuncio, rastreio_conjunto, rastreio_campanha e rastreio_criativo. Use nomes de exibição legíveis, como “Anúncio” e “Campanha”. IDs ficam como texto para preservar todos os dígitos. Atributos personalizados.

O programa receberá notificações do Chatwoot, extrairá a origem e preencherá esses campos. A origem fica em content_attributes.referral: o source_id dentro desse objeto identifica o anúncio; ctwa_clid identifica o clique, quando presente. O source_id fora dele é outro campo. Implementação do Chatwoot.

Abra o Claude ou o ChatGPT e cole o prompt abaixo em uma nova conversa. Depois envie o trecho técnico deste guia e, se necessário, um exemplo de evento com dados pessoais e segredos removidos. Informe também a versão do seu Chatwoot.

Para Claude ou ChatGPT

Prompt 1 — construir a integração de origem

Ler o prompt completo
Quero construir uma integração para identificar qual anúncio trouxe uma conversa ao WhatsApp. O número já usa API oficial e Chatwoot. Sou gestor, não programador: entregue arquivos completos, dependências, testes, .env.example sem segredos e README com comandos de instalação, execução e implantação. Não entregue apenas pseudocódigo. Explique onde salvar cada arquivo e como conferir cada etapa.

Crie um serviço HTTP com POST /webhooks/chatwoot e GET /health, usando runtime com suporte ativo. Inclua armazenamento durável e migrações. Informe os requisitos de hospedagem, HTTPS e persistência; não suponha que deixar esta conversa aberta mantenha a integração funcionando.

Configurações por ambiente: CHATWOOT_URL, CHATWOOT_ACCOUNT_ID, CHATWOOT_INBOX_ID, CHATWOOT_API_TOKEN, CHATWOOT_WEBHOOK_SECRET e DATABASE_URL. Nunca solicite nem inclua credenciais reais nos arquivos ou logs.

No recebimento, valide X-Chatwoot-Signature com HMAC-SHA256 sobre timestamp + ponto + corpo bruto, antes de interpretar JSON; confira X-Chatwoot-Timestamp e rejeite assinatura inválida. Processe apenas message_created, message_type=incoming, não privado, da conta e caixa configuradas.

Leia content_attributes.referral. Exija source_type=ad e source_id válido, mantido como texto. Não confunda esse campo com source_id externo da mensagem. Preserve ctwa_clid quando existir. Ausência de referral não deve inventar origem nem apagar a anterior.

Guarde conta, caixa, conversa, mensagem, código do anúncio, clique e instante. Use unicidade por conta+mensagem, histórico de ocorrências e tarefa durável de sincronização. Confirme recebimento somente depois de salvar o evento. Reenvios não podem duplicar o registro; falhas devem permitir nova tentativa.

Para atualizar o Chatwoot, use api_access_token e:
GET /api/v1/accounts/{account_id}/conversations/{conversation_id}
POST /api/v1/accounts/{account_id}/conversations/{conversation_id}/custom_attributes
Corpo: custom_attributes com os campos anteriores preservados, mais os de rastreio; merge:true quando suportado. Serialize tarefas da mesma conversa. A origem visível é a ocorrência válida mais recente, sem apagar o histórico.

Preencha rastreio_anuncio_id, rastreio_clique_id, rastreio_mensagem_id e rastreio_data. Reserve rastreio_anuncio, rastreio_conjunto, rastreio_campanha e rastreio_criativo como “Consulta pendente” para cada nova origem.

Inclua testes de: origem válida; origem ausente; conta/caixa erradas; assinatura inválida; mensagem enviada; duplicata; novo clique; falha temporária no Chatwoot. Mostre como executar os testes sem acessar uma conta real. Confira os contratos na documentação oficial citada no guia.

Peça que a IA corrija os testes que falharem antes de seguir. A resposta deve incluir o programa, o banco e sua instalação; um arquivo que apenas lê um JSON ainda não atende ao pedido.

A API atual documenta merge: true, mas versões anteriores podem substituir todos os atributos. Por isso o prompt exige ler, preservar e mesclar os campos, além de serializar as gravações. Leitura da conversa, gravação dos atributos.

Etapa 3 de 4

Peça à IA a consulta que identifica o anúncio

Volte à mesma conversa no Claude ou no ChatGPT e peça a segunda parte. Ela usará o código salvo para consultar a Meta, preservando tanto o identificador quanto o nome. A credencial precisa de ads_read e acesso à conta de anúncios; o acesso WhatsApp, sozinho, não concede essa consulta. Objeto anúncio, consulta oficial de exemplo.

Para Claude ou ChatGPT

Prompt 2 — consultar e gravar os nomes

Ler o prompt completo
Continue o projeto anterior. Acrescente a consulta à Meta usando o código do anúncio já salvo. Entregue os arquivos completos alterados, novos testes e README atualizado; mantenha os requisitos anteriores.

Adicione META_GRAPH_VERSION, META_AD_ACCOUNT_ID e META_MARKETING_TOKEN como variáveis de ambiente. O token deve ter ads_read e acesso autorizado à conta. Não coloque token na URL nem nos logs.

Consulte:
GET https://graph.facebook.com/{META_GRAPH_VERSION}/{AD_ID_SALVO}
Authorization: Bearer {META_MARKETING_TOKEN}
Parâmetro fields: id,account_id,name,adset{id,name},campaign{id,name},creative{id,name}

Valide se o id retornado é o solicitado e se account_id corresponde à conta autorizada. Preserve IDs, nomes e data da consulta no armazenamento da ocorrência.

Atualize estes atributos da conversa:
rastreio_anuncio = name
rastreio_conjunto = adset.name
rastreio_campanha = campaign.name
rastreio_criativo = creative.name
Não apague os códigos nem os atributos de outras integrações.

Antes de escrever, confirme que essa ocorrência continua sendo a origem válida mais recente. Uma resposta atrasada não pode sobrescrever nomes de um clique posterior. Se faltar nome, indique “Nome indisponível”; se a consulta falhar, preserve o ID e marque a consulta como pendente, com erro registrável sem segredos e possibilidade de reprocessar. Trate limites de chamadas e falhas temporárias sem repetição infinita.

Teste resposta válida, acesso negado, conta diferente, nome ausente e duas consultas que terminam fora de ordem. Explique como implantar a atualização e conferir os quatro nomes na conversa do Chatwoot. Não considere a integração pronta apenas porque o código foi gerado.

Nomes podem mudar; os IDs preservados mantêm a referência. O nome do objeto criativo também não identifica necessariamente cada variação exibida em um anúncio dinâmico.

Etapa 4 de 4

Coloque a integração no ar e teste

Siga o README gerado: instale dependências, crie o banco, execute as migrações, cadastre as variáveis de ambiente e publique o serviço em hospedagem compatível com esse runtime. A hospedagem deve fornecer HTTPS, execução dos trabalhos pendentes e armazenamento persistente. Uma página estática, sozinha, não recebe e processa esses eventos. Confira /health e os testes antes de conectar o tráfego real.

No painel Chatwoot da sua equipe, abra Settings → Integrations → Webhooks → Configure → Add new webhook. Informe a URL pública do programa, terminando em /webhooks/chatwoot, e selecione message_created. Copie o segredo mostrado pelo Chatwoot para a variável CHATWOOT_WEBHOOK_SECRET do serviço e aplique a configuração. São dois endereços diferentes: Meta → Chatwoot recebe o WhatsApp; Chatwoot → seu programa aciona o rastreio. Cadastro e assinatura dos webhooks.

Agora clique em um anúncio real do Facebook ou Instagram que abra esse WhatsApp. Antes de enviar, apague a mensagem pronta e digite “oi”. Confira o recebimento nos registros da integração e os campos da conversa no Chatwoot. Compare o código com o anúncio clicado. Enviar uma mensagem diretamente ao número, sem passar pelo anúncio, não testa esse caminho.

O exemplo do carrossel é ilustrativo: conversa 1048 → anúncio Vestido de linho → conjunto Público local → campanha Coleção de verão → criativo Vídeo do vestido. Na sua conta, os valores devem corresponder à consulta real.

Verifique também: mensagem comum não apaga a origem; reenvio não duplica histórico; novo clique válido cria ocorrência; falha ao consultar nomes preserva o código. Se algo falhar, leve à IA o erro e um exemplo sem dados pessoais ou credenciais e peça a correção com um teste que reproduza o problema. A implantação está concluída quando esse percurso funciona, não quando a IA termina a resposta.

Referência técnica para a IA

Estes trechos ajudam a conferir a implementação gerada. São exemplos para adaptação, não o serviço completo. O parser recebe o JSON depois da validação da assinatura; config.accountId e config.inboxId são strings provenientes da configuração do servidor.

Exemplo — extrair a origem de um evento validado

JS · adapte os campos
function id(v) {
  if (typeof v === "number" && !Number.isSafeInteger(v)) return null;
  if (typeof v !== "string" && typeof v !== "number") return null;
  const s = String(v).trim();
  return /^[1-9]\d*$/.test(s) ? s : null;
}

export function extrairOrigem(body, config) {
  if (body?.event !== "message_created" ||
      body.message_type !== "incoming" || body.private === true) return null;

  const accountId = id(body.account?.id);
  const inboxId = id(body.inbox?.id ?? body.conversation?.inbox_id);
  const conversationId = id(body.conversation?.id ?? body.conversation?.display_id);
  const messageId = id(body.id);
  if (accountId !== config.accountId || inboxId !== config.inboxId ||
      !conversationId || !messageId) return null;

  const r = body.content_attributes?.referral;
  if (!r || Array.isArray(r) || r.source_type !== "ad") return null;
  const adId = id(r.source_id);
  if (!adId) return null;

  const time = typeof body.created_at === "number"
    ? body.created_at * 1000 : Date.parse(body.created_at);
  if (!Number.isFinite(time)) throw new Error("Data da mensagem inválida");

  return {
    account_id: accountId, inbox_id: inboxId,
    conversation_id: conversationId, message_id: messageId,
    message_key: `${accountId}:${messageId}`,
    ad_id: adId,
    click_id: typeof r.ctwa_clid === "string" ? r.ctwa_clid : "",
    message_at: new Date(time).toISOString()
  };
}

Exemplo — gravar os campos da conversa

A credencial api_access_token vem do perfil de um usuário autorizado do Chatwoot. Leia os atributos atuais antes do POST; não use o conteúdo do webhook como cópia atual do cadastro.

HTTP · adapte os campos
GET {CHATWOOT_URL}/api/v1/accounts/{ACCOUNT_ID}/conversations/{CONVERSATION_ID}
api_access_token: {CHATWOOT_API_TOKEN}

POST {CHATWOOT_URL}/api/v1/accounts/{ACCOUNT_ID}/conversations/{CONVERSATION_ID}/custom_attributes
api_access_token: {CHATWOOT_API_TOKEN}
Content-Type: application/json

JS · adapte os campos
// Montagem do corpo do POST com os resultados reais da integração.
const corpo = {
  merge: true,
  custom_attributes: {
    ...conversaAtual.custom_attributes,
    rastreio_anuncio_id: origem.ad_id,
    rastreio_clique_id: origem.click_id,
    rastreio_mensagem_id: origem.message_id,
    rastreio_data: origem.message_at,
    rastreio_anuncio: anuncio.name || "Nome indisponível",
    rastreio_conjunto: anuncio.adset?.name || "Nome indisponível",
    rastreio_campanha: anuncio.campaign?.name || "Nome indisponível",
    rastreio_criativo: anuncio.creative?.name || "Nome indisponível"
  }
};

O resultado

A conversa passa a carregar sua origem fora do texto do cliente. Na N—RS, esse rastreio já roda: a origem fica registrada e a consulta identifica anúncio, conjunto, campanha e criativo. Construímos o projeto para a sua operação.

Claude ou ChatGPT ajudam a produzir e revisar o programa. O serviço instalado executa a integração, com credenciais, validação dos eventos, armazenamento e acompanhamento das falhas. Identificar a conversa não exige registrar vendas nem configurar retorno de conversões.

NRS · Sistemas sob medida

Esse rastreio na sua operação.

Conectamos os dados, o atendimento e as ferramentas que fazem parte do seu projeto.

Falar com a NRS