Pular para o conteúdo principal

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 fetch a partir de *.lovable.app ou *.replit.app é bloqueado — nenhuma chave muda isso.
Os builders de IA erram nesses três pontos por padrão. Todos os prompts abaixo repetem as regras, porque a IA que lê cada prompt não tem acesso a esta página.

Antes de começar

  1. Uma chave de API ps_ com escopo de tenant, na aba API do seu perfil (/profile). Uma chave com escopo de número recebe 403 NUMBER_SCOPE_NOT_ALLOWED em todo endpoint /v1/phone-lines. Você não precisa de nenhum número de WhatsApp conectado.
  2. 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.
  3. 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_FAILED e nada é cobrado.
  4. 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 https pública.
A chave ps_ é um segredo de servidor. Nunca pode aparecer em código de frontend, nem em variável com prefixo VITE_, NEXT_PUBLIC_, REACT_APP_ ou PUBLIC_ — esses prefixos são compilados dentro do bundle JavaScript que seus usuários baixam. O mesmo vale para o segredo plwh_ do webhook.

Como as peças se encaixam

A chave 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.
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.
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.
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.
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.
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.
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.
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.