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
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
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.
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// 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.