Cadastro de WhatsApp para builders de IA
Você está construindo um CRM ou SaaS no Lovable, Replit, Bolt, v0 ou Cursor, e seus clientes precisam conectar o próprio número oficial de WhatsApp. Esta página entrega quatro prompts. Cole no seu builder, na ordem, e o fluxo de cadastro funciona.Prefere partir de um código que já roda? Baixe o demo (licença MIT) deste fluxo exato (backend Node + frontend React, com modelos de botão prontos): embedded-signup-demo.zip. Jogue no seu builder, ou rode local com
npm run dev.Por que o botão hospedado, e não FB.login na sua página
Seu builder publica num domínio dele — algo.lovable.app, algo.replit.app, uma URL de preview nova a cada deploy. Esse domínio muda por projeto, e quase sempre por push.
A Meta valida o domínio que executa o FB.login. Colocar o botão do Facebook direto na sua própria página significaria registrar cada um desses domínios no app Meta da Pilot Status, um a um, para sempre. Isso não escala, e não está disponível.
O botão hospedado resolve isso rodando o cadastro dentro de um iframe servido por connect.pilotstatus.com.br — um domínio que a Pilot Status já possui e já registrou. O Facebook checa a origem do iframe, não a da sua página. Sua página pode viver em qualquer domínio, inclusive numa URL de preview que não existia cinco minutos atrás, e o popup abre normalmente.
Nada para registrar. Nada para esperar. Este é o caminho certo para apps hospedados em builder, não um remendo.
Se você tem um domínio fixo e quer o botão do Facebook na sua própria marcação, use Embedded Signup no seu próprio app — controle total do botão, ao custo de operar o SDK JavaScript do Facebook por conta própria. Para todos os detalhes do embed hospedado (parâmetros da URL, eventos de
postMessage e branding.button), veja Incorpore a Página de Conexão.Antes de começar
- Uma conta Pilot Status com um slot de número livre no plano.
- Uma chave de API
ps_com escopo de tenant, na aba API do seu perfil (/profile). Chave com escopo de número não serve — gerar um link de cadastro cria um número novo, então a chave não pode estar presa a um número existente. - Um backend. Todos os builders acima conseguem rodar um: um servidor no Replit, um route handler Next.js no v0, uma Supabase Edge Function no Lovable ou no Bolt. Ele é necessário porque o browser não pode chamar a API da Pilot Status diretamente.
Como as peças se encaixam
ps_ só existe na última linha.
Os quatro prompts
Cole na ordem. Cada um é autossuficiente — a IA que lê o prompt não tem acesso a esta página, então tudo que ela precisa está escrito dentro dele.Prompt 1 — Rota de backend que gera o token de cadastro
Gerar um link cria um número placeholder e consome um slot do plano na hora. Gere quando o cliente estiver realmente prestes a clicar, não no carregamento da página.
Prompt 2 — Iframe no frontend com o sandbox correto
Prompt 3 — Tratar o connect:paired e salvar o número
Prompt 4 — Registrar o webhook que entrega as mensagens recebidas
Erros que a IA costuma cometer
Estes cinco respondem por quase toda integração quebrada. Se algo não funcionar, confira nesta ordem.A chave ps_ vaza para o browser
A chave ps_ vaza para o browser
O builder lê de
VITE_PILOT_KEY ou NEXT_PUBLIC_PILOT_KEY porque é o caminho mais rápido para o fetch compilar. Esses prefixos embutem o valor no bundle publicado, então quem abrir o DevTools é dono da sua conta. A chave fica numa variável de servidor comum, como PILOT_TENANT_KEY, lida só por código de backend. Se você achar a chave no bundle, rotacione ela no painel antes de corrigir o código.Falta allow-popups no sandbox do iframe
Falta allow-popups no sandbox do iframe
Sem
allow-popups e allow-popups-to-escape-sandbox, o popup do Facebook é bloqueado pelo browser sem erro, sem aviso no console e sem falha visível. O botão simplesmente não faz nada ao ser clicado, o que faz todo mundo caçar bug na lógica do token. O atributo completo é sandbox="allow-scripts allow-same-origin allow-forms allow-popups allow-popups-to-escape-sandbox".Chamar a API da Pilot Status direto do browser
Chamar a API da Pilot Status direto do browser
O código gerado faz
fetch("https://pilotstatus.com.br/v1/...") — ou lê GET /api/health — de dentro de um componente. O CORS da API é uma allowlist estrita dos domínios da própria Pilot Status, então uma requisição de *.lovable.app ou *.replit.app nunca recebe o header Access-Control-Allow-Origin e é bloqueada. Nenhuma chave de API muda isso. Neste fluxo o frontend nem precisa disso: o botão já vem pronto dentro do iframe. Toda chamada à Pilot Status passa pelo seu backend, e a única serve para gerar o link.Registrar webhook sem o array events
Registrar webhook sem o array events
POST /v1/webhooks aceita um corpo sem events, responde sucesso e depois não entrega nada. Não há aviso. Envie um array explícito — ["messages"] para número META, ou ["*"] para tudo.Tentar rodar FB.login no domínio do próprio builder
Tentar rodar FB.login no domínio do próprio builder
A IA conhece a receita padrão do Facebook Embedded Signup e vai produzi-la com prazer. Numa URL
*.lovable.app ou *.replit.app isso não funciona: a Meta valida a origem que executa o FB.login, e esse domínio não está registrado no app Meta da Pilot Status — nem pode estar, já que muda por projeto e por deploy. O iframe hospedado existe exatamente para evitar isso: o SDK do Facebook, o appId e o config_id vivem dentro dele, no domínio da Pilot Status. Se um prompt começar a puxar connect.facebook.net/en_US/sdk.js, servir appId/config_id para o cliente ou ler /api/health no browser, você está no caminho errado — neste fluxo nada disso existe no seu app; o iframe cuida de tudo.Sobre o estilo do botão
A aparência do botão hospedado vem do objetobranding.button enviado na geração do token — veja o Prompt 1. Essa requisição é autenticada pela sua chave ps_, então o estilo é sempre atribuível à sua conta.
Deliberadamente não existe query parameter para o estilo do botão. Não tente passar cores, rótulos ou logo na URL do iframe; serão ignorados.
O marcador “secured by pilotstatus.com.br” abaixo do botão aparece por padrão. O branding.button.hideProvenance consegue escondê-lo, mas só no modo botão e só quando esse recurso estiver habilitado para a sua conta — caso contrário o valor é ignorado e o marcador continua aparecendo. Fale com o suporte se precisar disso.
Próximos passos
O número está conectado e os webhooks estão chegando. Agora envie alguma coisa.Enviar mensagens
Seu primeiro envio com
POST /v1/messages/send — templates, texto livre e mídia.Referência do embed hospedado
Todos os parâmetros da URL do iframe, os eventos de
postMessage e as opções de branding.button.Embedded Signup no seu próprio app
A alternativa com controle total, para quando você tem um domínio fixo e integra o SDK do Facebook.