Linhas telefônicas para builders de IA
Você está construindo um CRM ou SaaS no Lovable, Replit, Bolt, v0 ou Cursor, e quer que os seus clientes comprem e ativem linhas telefônicas — números fixos brasileiros para ativar contas do WhatsApp Business — sem sair do seu produto. Esta página entrega quatro prompts. Cole no seu builder, na ordem, e você tem o mesmo fluxo de Linhas telefônicas no seu app pela API.Prefere partir de um código que já roda? Baixe o demo (licença MIT) deste fluxo exato (backend Node + TypeScript que guarda a chave e frontend React + Vite): phone-lines-demo.zip. Jogue no seu builder, ou rode local com
npm run dev.Por que tudo passa pelo seu backend
Aqui não há página hospedada nem iframe. A sua página mostra os números, o botão de compra e o código de ativação, mas quem fala com a API da Pilot Status é o seu backend, por três motivos:- A chave
ps_autoriza tudo na sua conta — inclusive comprar linhas, que cobra dinheiro. - O código de ativação é uma credencial. Quem o tiver pode registrar uma conta do WhatsApp na linha, e a gravação da ligação o fala.
- O browser não consegue chamar a API. O CORS da API é uma allowlist estrita dos domínios da própria Pilot Status, então um
fetcha partir de*.lovable.appou*.replit.appé bloqueado — nenhuma chave muda isso.
Antes de começar
- Uma chave de API
ps_com escopo de tenant, na aba API do seu perfil (/profile). Uma chave com escopo de número recebe 403NUMBER_SCOPE_NOT_ALLOWEDem todo endpoint/v1/phone-lines. Você não precisa de nenhum número de WhatsApp conectado. - Um titular da conta verificado (CNPJ ou CPF, o documento e a confirmação de contato), feito uma única vez antes da primeira compra. O caminho mais simples é o painel: Linhas → Comprar linhas. O Prompt 2 só lê esse estado e manda o cliente para lá quando falta.
- Créditos na carteira ou um cartão salvo. A compra não tem link de checkout: sem saldo e sem cartão, o número falha com
PAYMENT_FAILEDe nada é cobrado. - 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. Para o webhook (Prompt 4), ele precisa de uma URL
httpspública.
Como as peças se encaixam
ps_ só existe na seta do seu backend.
Os quatro prompts
Cole na ordem. Cada um é autossuficiente — tudo que a IA precisa está escrito dentro dele.Prompt 1 — Backend que guarda a chave e compra com Idempotency-Key
Cada número custa o preço mensal cheio, descontado primeiro da carteira e, no que faltar, do cartão salvo. Um
PAYMENT_PROVIDER_ERROR significa que o cartão pode ter sido cobrado: confira a fatura antes de tentar de novo. Todas as regras estão em Comprar linhas.Prompt 2 — Tela de compra com a checagem da verificação
Prompt 3 — Código de ativação, gravação e cancelamento
Os estados do pedido, os valores de
failureReason e os tempos (verificação da linha a cada 15 segundos, até 3 tentativas de transcrição) estão em Códigos de ativação.Prompt 4 — Webhook das linhas, com assinatura
Erros que a IA costuma cometer
Estes 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, e quem abrir o DevTools pode comprar linhas na sua conta. A chave fica numa variável de servidor comum, como PILOT_TENANT_KEY. Se você achar a chave no bundle, rotacione ela no painel antes de corrigir o código.Uma chave de idempotência nova a cada tentativa
Uma chave de idempotência nova a cada tentativa
A IA gera
crypto.randomUUID() dentro da função que faz o fetch, então cada retentativa — e cada clique repetido — vira uma compra nova, cobrada de novo. A Idempotency-Key nasce uma vez por compra, é gravada antes do envio e é reenviada igual em timeout, erro de rede ou 5xx. Chave nova só para uma compra nova, depois de corrigir a causa de um PAYMENT_FAILED ou SUPPLIER_UNAVAILABLE. Veja Idempotência.Tratar o 200 da compra como sucesso
Tratar o 200 da compra como sucesso
POST /v1/phone-lines responde 200 quando processou a requisição, mesmo que todos os números tenham falhado. O resultado de cada número está em results[i].ok. E um REQUEST_ALREADY_PROCESSED não diz se o número foi comprado: compare com GET /v1/phone-lines por number.Mandar tocar em Me ligue antes de abrir o pedido
Mandar tocar em Me ligue antes de abrir o pedido
Uma ligação que chega antes de
POST /v1/phone-lines/{id}/activations não é capturada. A instrução “toque em Me ligue” só aparece depois que o pedido responde 201. E a linha é fixa: esperar por um SMS só consome os 5 minutos da janela.Parar de consultar no CAPTURED
Parar de consultar no CAPTURED
A IA para no primeiro status diferente de
WAITING. Mas CAPTURED com failureReason: null é o estado intermediário enquanto o código é lido, e pode durar alguns minutos. Continue consultando até um estado definitivo, e confira o code — TRANSCRIBED não garante um código. Todos os estados: Status.Cadastrar o webhook em POST /v1/webhooks
Cadastrar o webhook em POST /v1/webhooks
POST /v1/webhooks é o cadastro dos webhooks de número e nunca recebe eventos phone_line.*, nem com "*". O das linhas é POST /v1/phone-lines/webhooks — e o segredo plwh_ que ele devolve aparece só nessa resposta. Veja Webhooks das linhas.Verificar a assinatura sobre o JSON já interpretado
Verificar a assinatura sobre o JSON já interpretado
O framework faz o parse do corpo antes do handler, e a IA calcula o HMAC sobre
JSON.stringify(req.body). O resultado nunca bate. A assinatura é sobre os bytes recebidos: leia o corpo bruto (express.raw, request.text()) só nessa rota, verifique, e só então faça o parse.Próximos passos
Linhas pela API
O mesmo fluxo passo a passo, com o backend de exemplo da compra e o receptor do webhook.
Referência da API de linhas
Todos os campos, estados e códigos de erro de
/v1/phone-lines.Verificação do titular
Para conduzir a verificação dentro do seu produto, em vez de mandar o cliente ao painel.
Webhooks das linhas
Eventos, payloads, assinatura e retentativas.