SuperdindaDocs

Proxies

De qual endereço cada sessão do WhatsApp sai — proxies ISP brasileiros de IP fixo, poucos por IP, comprados pela API do IPRoyal e controlados pelo backoffice.

Cada sessão WAHA conecta ao WhatsApp atrás de um proxy (config.proxy no POST /api/sessions). Qual endereço é decisão de produto, não topologia de infra (AD-002): o WhatsApp lê o IP ao julgar se um login parece de uma pessoa. Por isso o vínculo IP ↔ sessão é dado nosso, no domínio domains/proxies.

Por que ISP residencial brasileiro, de IP fixo

O consenso que a pesquisa levantou (research/2026-09-11-proxies-residenciais-br):

  • IP dedicado para poucas contas; nunca datacenter; nunca IP estrangeiro com número brasileiro;
  • sem rotação: IP que muda derruba todo pareamento daquele endereço de uma vez;
  • não existe número público de sessões por IP; 10 por IP é agressivo → começar com 3–5 e medir.

O código impõe isso: só se compra o produto isp_dedicated (qualquer outro dá PRODUCT_NOT_ALLOWED, decidido pelo tipo e não pelo nome), e a adoção recusa endereço que a sonda classifica como datacenter ou de registro estrangeiro.

Fornecedores

FornecedorSituação
IPRoyal (ISP Dedicated, BR)integrado: IPRoyalSupplier, API de revenda (IPROYAL_API_TOKEN, IPROYAL_API_URL). Primeira compra em 2026-09-29.
Decodo, Oxylabsrecomendados pela pesquisa como fornecedor principal + segunda fonte, mas não vendem ISP dedicado por API (só painel). Sem código.

Em aberto

A pesquisa recomenda manter dois fornecedores para trocar IP queimado sem parar o pool. Hoje só o IPRoyal existe no código; Decodo/Oxylabs entrariam como endereços registrados à mão (POST /admin/proxies). A rodada de duas semanas medindo quedas e bans por fornecedor ainda não aconteceu (nenhum celular real pareado até 2026-10-18).

Dois contratos separados:

  • ProxyProvider é a visão do alocador (PROXY_PROVIDER, hoje só local). Com local, o boot semeia um endereço direct (capacidade 100 000): a sessão sai do próprio servidor e nada mais muda.
  • ProxySupplier é a loja do operador (catálogo, cotação, compra, extensão, saldo, inventário). Endereços comprados entram no pool por adoção.

Capacidade: PROXY_SEATS_PER_IP

PROXY_SEATS_PER_IP (padrão 3) é a capacidade dada a cada endereço novo, registrado ou adotado. Cada endereço pode ter o seu valor depois (PATCH /admin/proxies/{uid} com capacity). No pedido do IPRoyal a pergunta "Multi-device access" (3, 5 ou 10) é literalmente essa capacidade, e "Fresh IPs every renewal" tem de ser false.

Alocação

allocateProxy(accountId, seatChannelId) roda dentro de startPairing:

  1. Se o seat_channel já tem binding vivo, reusa o mesmo endereço.
  2. Senão, prefere um endereço onde a família já está, se ainda tem vaga: vários números de uma casa saindo de IPs diferentes é um padrão que o WhatsApp lê mal.
  3. Senão, o endereço active mais cheio que ainda cabe (empacotar mantém famílias juntas e deixa endereços inteiros livres).
  4. Nada cabe → 422 NO_PROXY_CAPACITY.

Só endereços active recebem sessão nova.

Em aberto

releaseProxy só é chamado ao queimar um endereço. Um pareamento desvinculado, cancelado ou que desistiu de reconectar mantém o binding: a vaga continua ocupando aquele endereço, e o próximo pareamento do mesmo canal volta para ele.

Modelo (domains/proxies)

TabelaGuarda
proxiesendereço, protocolo (http, socks5, direct), credenciais seladas, IP, ASN, país, kind (isp, mobile, datacenter, direct), capacity, status, validade, pedido de origem
proxy_bindingsqual sessão (seat_channel) está em qual endereço, e quais estiveram — com released_reason
proxy_orderscontrato no fornecedor, com idempotency_key e placed_by (operator ou auto)
proxy_chargescada débito, em cents, com câmbio do dia
proxy_budgetstetos por fornecedor: mensal, por compra, saldo mínimo, cooldown
provider_balanceso saldo do fornecedor ao longo do tempo

Status de proxies: probing, active, draining, burned, released. As rotas nunca devolvem as credenciais.

Sonda, adoção e queima

  • Sonda (POST /admin/proxies/probe): mede connectMs (o túnel) e lookupMs separados, IP de saída, ASN, registro (RIR), tipo detectado e se o CONNECT g.whatsapp.net:443 passa (whatsapp: { ok, failure }). Devolve um probeToken válido por 15 min; o registro usa o que foi medido, não o que o formulário mandou.
  • Adoção (POST /admin/proxy-supply/adopt): grava como probing, sonda e promove a active, ou marca burned com o motivo: PROBE_FAILED, FOREIGN_REGISTRY, DATACENTER, WHATSAPP_UNREACHABLE.
  • Drenar (status: "draining"): para de receber sessão nova; quem está fica. Pode ser desfeito.
  • Queimar (status: "burned"): para endereço que o WhatsApp começou a recusar. burnAddress encerra cada pareamento no endereço como disconnected (proxy_burned), libera os bindings, notifica responsáveis e a pessoa (pairing.reconnect_required) e devolve as contas à fila de ingest na frente dos novatos. Ver o runbook.

Saldo e validade

  • Não existe endpoint de recarga no IPRoyal: o saldo pré-pago é o teto físico de gasto. Regra da pesquisa: saldo sempre, cartão nunca; auto-extend pago pelo saldo.
  • GET /admin/proxy-supply/balances mostra saldo, renovações automáticas previstas (estimadas pelo preço do plano × 1,25, porque a API não informa o preço real), shortfall e quantas sessões estão em risco. Perguntar de novo ao fornecedor tem piso de 60 s.
  • Validade com sessões dentro é incidente: critical a 3 dias ou menos, warning até 14. Todas voltariam de outro IP ao mesmo tempo.

Em aberto

proxy_budgets.auto_purchase_enabled existe, mas nenhum worker compra sozinho: toda compra hoje é feita por um operador.

Rotas de admin

RotaPara quê
GET /admin/proxiespool, do mais cheio ao mais vazio
POST /admin/proxiesregistrar endereço comprado fora (probeToken opcional)
POST /admin/proxies/probetestar sem registrar
PATCH /admin/proxies/{uid}capacity, label, status (active, draining, burned)
GET /admin/proxies/{uid}/bindingsquem está no endereço
GET /admin/proxy-supply/{catalog,inventory,orders,costs,budgets,balances}loja, contratos, custo, tetos, saldo
POST /admin/proxy-supply/{quote,orders,adopt}cotar, comprar o que a cotação travou, adotar
POST /admin/proxy-supply/orders/{uid}/extend/quote, …/extendrenovar
PUT /admin/proxy-supply/budgets/{provider}definir teto

No backoffice: Infraestrutura → Proxies, Compras e Orçamento.

Fontes

  • backend/src/domains/proxies/ (index.ts, tables/index.ts, use-cases/{allocate,probe,supply,supply-orders}.ts, providers/{contract,registry,supply}.ts)
  • backend/src/domains/channels/use-cases/{start-pairing,burn-address}.ts
  • backend/src/http/routes/admin/{proxies,proxy-supply,probe}.route.ts, backend/src/config/env.ts, backend/.env.example
  • apps/backoffice/src/components/{proxies,proxy-supply}/
  • Vault: AD-002, AD-016, research/2026-09-11-proxies-residenciais-br (e adendo 2026-09-29), problems/2026-09-29-sonda-de-proxy-dois-bugs, _state, specs/2026-10-18-redesign-blueprint (estágio real)

On this page