Por que o proxy não recebe webhooks: direção da conexão e o que usar no lugar
Sumário do artigo
- Introdução: por que a expectativa "compro um proxy e o webhook vai chegar" não se concretiza
- Fundamentos: direção da conexão, ou quem bate na porta de quem
- Imersão profunda: por que o cliente de proxy não escuta porta e não fornece endereço público
- Redes móveis e endereço compartilhado: por que o endereço do assinante não é endereçável de fora
- O que realmente resolve a tarefa de receber webhooks: quatro abordagens práticas
- Polling como substituto do webhook: como projetar para não bater nos limites
- Onde o proxy ainda é necessário ao lado dos webhooks: respostas de saída e chamadas a apis de terceiros
- Tabela "tarefa — solução adequada"
- Erros comuns: o que não se deve fazer
- Casos e resultados: como isso aparece na prática
- Faq: perguntas frequentes sobre proxy e recebimento de webhooks
- Conclusão: o modelo correto e os próximos passos
Introdução: por que a expectativa "compro um proxy e o webhook vai chegar" não se concretiza
No suporte dos serviços de proxy chega sempre o mesmo pedido, formulado de maneiras diferentes. "Comprei um proxy móvel, coloquei o endereço dele nas configurações da integração, e o gateway de pagamento não manda notificação". "Coloquei o IP do proxy como URL de webhook no CRM, dá erro de conexão". "Meu script através do proxy vê tudo, mas através desse mesmo proxy ninguém me vê, por quê?". As formulações mudam, mas a raiz é uma só: o modelo mental errado sobre o que o proxy realmente faz.
A expectativa é compreensível. O proxy te dá "outro endereço IP", e esse endereço é público, todos os serviços de verificação o mostram. A lógica sugere: se eu tenho um endereço público, então por ele é possível me encontrar. Mas não é bem assim. O proxy, incluindo o proxy móvel Proxeon, resolve o problema das requisições de saída: seu código inicia a conexão, ela passa pelo nó do proxy, e o servidor remoto vê o endereço desse nó. O problema inverso, quando o servidor remoto inicia uma conexão até você, o proxy não resolve de forma alguma. Não porque falta algo no plano, mas porque ela é estruturada de forma completamente diferente.
Neste material vamos destrinchar o assunto até a raiz. Você vai entender como uma conexão de saída difere de uma de entrada no nível do TCP, por que o cliente de proxy não abre uma porta de escuta e não te entrega um endereço para o qual seja possível se conectar de fora, por que o endereço do assinante de rede móvel por natureza não é endereçável externamente, e o mais importante: o que realmente usar para receber webhooks: servidor com endereço público, túnel reverso, fila de eventos no lado do provedor ou polling bem projetado. Vamos ver separadamente onde o proxy ainda tem seu lugar nesse esquema, e esse lugar existe. Encaminhamento de portas e configuração de roteadores domésticos ficam fora do escopo: é um assunto vizinho, vamos apenas delimitar a fronteira de aplicabilidade. O material foi escrito para desenvolvedores de integrações, engenheiros DevOps e especialistas técnicos que constroem automações em cima de APIs de terceiros. Os exemplos de código estão em Python e em comandos de shell, você pode usá-los como base.
Fundamentos: direção da conexão, ou quem bate na porta de quem
Vamos começar pelo fundamento, sem o qual não faz sentido seguir adiante. Em redes TCP/IP, toda conexão tem um iniciador e um ouvinte. O iniciador envia o primeiro pacote com flag SYN. O ouvinte abriu a porta previamente, espera nela e responde com SYN-ACK. Só depois desse handshake os dados fluem nos dois sentidos. A palavra-chave aqui é "previamente": o ouvinte precisa já estar em um endereço que seja roteável da internet, e já manter a porta aberta no momento em que o iniciador quiser bater.
Esquema de requisição de saída através do proxy
Vamos representar o esquema em texto. Seu script está em casa ou no escritório atrás de NAT, ou até num notebook com modem móvel.
- Passo 1. Seu script inicia a conexão ao nó do proxy: [seu código] bate em [nó Proxeon].
- Passo 2. O nó do proxy, em nome próprio, inicia a conexão ao site de destino: [nó Proxeon] bate em [api.example.com].
- Passo 3. O site de destino responde pela conexão já aberta no sentido inverso, o nó do proxy repassa a resposta para você pela sua conexão aberta.
Repare: a resposta do servidor não é uma conexão de entrada. São dados que voltam pelo canal que você abriu. A porta foi aberta por você, e você a mantém enquanto durar a troca. Assim que você fecha a conexão, não há caminho de volta. Ninguém de fora pode "continuar a conversa" por iniciativa própria.
Esquema do webhook
Agora o webhook. O provedor de pagamento, o mensageiro, o CRM ou o marketplace querem te avisar sobre um evento: o pagamento passou, chegou uma mensagem, mudou o status do pedido.
- Passo 1. O provedor pega a URL que você indicou na assinatura, resolve o nome de domínio para um endereço IP.
- Passo 2. O provedor inicia uma conexão a esse endereço na porta 443: [servidor do provedor] bate em [sua URL].
- Passo 3. Nesse endereço e nessa porta alguém precisa escutar, aceitar o handshake TLS com certificado válido, interpretar a requisição HTTP e responder com código 2xx.
Aqui o iniciador é o provedor. O ouvinte deve ser você. E aí surge a pergunta que este artigo responde em detalhes: qual endereço você vai dar ao provedor? O endereço do proxy? Mas o nó do proxy não escuta para você. O endereço da sua conexão doméstica? Mas ele ou é privado, ou está atrás do NAT da operadora. O notebook com modem? Ele sequer tem endereço roteável.
Analogia que põe tudo no lugar
O proxy é como um serviço de entrega para cartas de saída. Você entrega a carta ao mensageiro, ele leva até o destinatário, e no envelope está o endereço de retorno da central de entregas, não a sua casa. O destinatário pode colocar a resposta no mesmo envelope, o mensageiro volta e te entrega, porque ele lembra de quem ele pegou a carta. Mas se depois de uma semana o destinatário quiser escrever para você por conta própria, ele vai escrever para o endereço da central. A central recebe a carta e não vai saber a qual dos milhares de clientes ela se destina. Muito provavelmente ela nem chega à caixa de correio da central, porque não existe caixa de entrada lá. Para receber cartas, você precisa do seu próprio endereço postal, não de um serviço de envio de saída.
Imersão profunda: por que o cliente de proxy não escuta porta e não fornece endereço público
Vamos descer ao nível dos protocolos. Existem duas famílias massivas de proxy: HTTP-proxy e SOCKS-proxy. Vamos ver o que cada um consegue fazer, e nos convencer de que conexões de entrada para o seu serviço não estão nessa lista nem no papel nem na prática.
Como funciona o HTTP-proxy
O HTTP-proxy aceita do cliente uma requisição do tipo GET http://host/path ou, para HTTPS, o comando CONNECT host:443. No segundo caso, o proxy abre uma conexão TCP ao host de destino e depois simplesmente retransmite bytes nos dois sentidos, sem olhar para dentro do tráfego cifrado. Só isso. Não há no protocolo um comando do tipo "comece a escutar uma porta para mim" nem "registre um endereço para mim". O cliente é sempre o iniciador, o proxy é sempre intermediário no sentido "do cliente para o mundo".
Aqui vai um exemplo mínimo de requisição de saída via proxy em Python. Funciona porque a direção é a correta:
import requests
PROXY = 'http://user:pass@gate.proxeon.net:PORT'
proxies = {'http': PROXY, 'https': PROXY}
r = requests.get('https://api.example.com/v1/status', proxies=proxies, timeout=(5, 30))
print(r.status_code, r.json())E agora a tentativa que está condenada. Suponha que você descobriu o IP externo do proxy, por exemplo através de um serviço de verificação de endereço, e resolveu indicá-lo como URL de webhook:
curl -v --max-time 10 http://203.0.113.45/webhook
# resultado: connect() timed out ou Connection refusedPor que assim? No endereço 203.0.113.45 roda o software de proxy, que escuta a porta de serviço dele para receber comandos dos clientes, mas não o seu caminho /webhook. Mesmo que na porta 80 algo respondesse, não seria o seu código. Seu código está em outra máquina, atrás de outro endereço, e o servidor de proxy não faz ideia de que a requisição no caminho /webhook deveria ser repassada justamente para você, e não para um entre centenas de outros clientes usando o mesmo endereço de saída.
E o SOCKS5 e o comando BIND?
Aqui começa a parte mais interessante, que pouca gente conhece. Na especificação do SOCKS5 existem de fato três comandos: CONNECT, BIND e UDP ASSOCIATE. O comando BIND foi pensado exatamente para o cenário inverso: o cliente pede ao proxy para abrir uma porta de escuta, e depois aceitar uma conexão de entrada e repassá-la ao cliente. É herança do protocolo FTP em modo ativo, onde o servidor precisa conectar-se ao cliente para transmitir dados.
Parece que achamos a solução. Mas existem três motivos pelos quais, na prática, o BIND não vai te ajudar:
- O BIND aceita exatamente uma conexão de entrada e só depois que você já estabeleceu uma conexão de saída para o mesmo host. Não é "escutar uma porta continuamente para qualquer um", mas sim "abrir a porta para um interlocutor específico com quem eu já estou falando".
- A esmagadora maioria dos servidores de proxy comerciais não implementa o comando BIND, ou o desabilita por questões de segurança. Uma porta de escuta aberta num nó compartilhado com centenas de clientes é vetor de ataques e fonte de abusos, então ela simplesmente não existe.
- Mesmo onde o BIND existe, o endereço e a porta são alocados dinamicamente, por pouco tempo, e não servem de forma alguma para registrar como URL de webhook com certificado TLS.
Resumindo: existe a possibilidade teórica na especificação, mas ela não traz utilidade prática para receber webhooks.
O que você ganha com o proxy, e o que não ganha
Vamos formular com total clareza. Comprando um proxy, você obtém:
- um endereço IP de saída que os servidores remotos veem nas suas requisições de saída;
- a localização geográfica e de rede desse endereço, por exemplo um endereço do pool de uma operadora móvel de uma região específica;
- a possibilidade de rotacionar esse endereço ou, ao contrário, mantê-lo estável durante a sessão;
- a separação do tráfego de saída em canais diferentes, caso você conduza várias integrações independentes.
Você não obtém:
- porta de escuta no endereço de saída;
- endereço roteável para o qual terceiros possam iniciar conexão;
- nome de domínio e certificado TLS vinculados ao seu serviço;
- garantia de que o endereço de saída será o mesmo daqui a uma hora, se o plano prevê rotação.
Assim que essa tabela assenta na cabeça, a pergunta "por que o webhook não chega no proxy" deixa de ser pergunta. Torna-se obviedade.
Redes móveis e endereço compartilhado: por que o endereço do assinante não é endereçável de fora
As redes móveis merecem uma conversa à parte, porque são justamente os proxies móveis que costumam ser protagonistas das histórias de "o webhook não chega". Aqui, às limitações do próprio proxy se soma a arquitetura da rede da operadora, e ela amplifica o efeito várias vezes.
Escassez de endereços e CGNAT
Existem cerca de quatro bilhões de endereços IPv4 públicos no mundo, e conexões móveis ativas são bem mais que isso. Nenhuma operadora consegue dar a cada assinante um endereço público próprio. Por isso as operadoras usam Carrier-Grade NAT (CGNAT, tradução de endereços de nível de operadora). O dispositivo do assinante recebe um endereço privado de uma faixa especialmente reservada 100.64.0.0/10 ou da habitual 10.0.0.0/8, e na borda da rede há um potente gateway NAT, que traduz milhares de endereços de assinantes em um ou alguns públicos.
Como isso se parece do ponto de vista da endereçabilidade? Quando seu modem envia um pacote para fora, o gateway anota na tabela: "assinante 100.72.14.9, porta 51234 → endereço público 203.0.113.45, porta 40001". A resposta que chega em 203.0.113.45:40001 o gateway associa ao registro e devolve para você. Mas os registros são criados apenas pelo tráfego de saída e vivem segundos ou minutos sem atividade. Se alguém de fora enviar um pacote para 203.0.113.45 na porta 443, não haverá na tabela nenhum registro correspondente a esse pacote. O gateway vai descartá-lo. Não "bloqueá-lo", mas simplesmente não conseguirá entender para qual de milhares de assinantes ele se destina.
Por que isso é inevitável do lado do assinante
Com provedores domésticos às vezes é diferente: alguns planos dão um endereço público real ao roteador, e aí surge o assunto vizinho: encaminhamento de portas e configuração do roteador. Nós conscientemente não o descrevemos, apenas fixamos a fronteira de aplicabilidade: o encaminhamento de portas só faz sentido onde no seu equipamento há um endereço roteável de verdade. Na rede móvel esse endereço simplesmente não existe para o assinante, não há o que encaminhar e para onde, e configurar o equipamento não muda esse fato. A opção de endereço público para assinante móvel na maioria das operadoras ou não existe, ou é oferecida como serviço corporativo separado, o que já não tem relação com proxy.
Camadas adicionais: rotação e filtragem
Ao CGNAT somam-se mais dois fatores. Primeiro, o endereço público por onde o assinante sai muda periodicamente: na reconexão, no rebalanceamento de carga, na troca de estação base. Os proxies móveis Proxeon usam justamente essa propriedade como algo útil: o endereço pode ser rotacionado por agenda ou sob demanda. Mas para receber webhooks a estabilidade do endereço é crítica, e aqui ela está ausente por definição. Segundo, as operadoras filtram parte do tráfego de entrada na borda da rede, porque os dispositivos dos assinantes não são feitos para ser servidores. Mesmo onde o assinante recebe um endereço IPv6 público, conexões de entrada para ele costumam estar fechadas pelo firewall da operadora.
O resultado deste capítulo merece destaque: o endereço de um proxy móvel é uma identidade de saída, e não o endereço de um serviço. Isso não é defeito do produto, é a natureza dele. Compra-se um proxy móvel justamente para que as requisições de saída pareçam tráfego de um assinante comum de uma operadora e região específicas. Justamente porque esse tráfego é indistinguível do de um assinante, ele herdou também a não-endereçabilidade de fora do assinante.
O que realmente resolve a tarefa de receber webhooks: quatro abordagens práticas
Passamos do diagnóstico ao tratamento. Existem quatro formas maduras de receber eventos de sistemas externos quando seu código vive atrás de NAT, atrás de um modem móvel ou até num notebook. Cada uma tem seu nicho, seu custo e suas limitações. Vamos vê-las em ordem, com exemplos.
Abordagem 1. Servidor com endereço público
A forma mais direta e mais confiável. Você aluga um servidor virtual num provedor de hospedagem, recebe junto com ele um endereço IPv4 público, associa a ele um nome de domínio, emite um certificado TLS e sobe o receptor. Os provedores de webhook em 2026 quase unanimemente exigem HTTPS com certificado válido, então esse passo é obrigatório.
Plano passo a passo:
- Alugue uma VPS de configuração mínima numa jurisdição adequada aos seus requisitos de armazenamento de dados.
- Crie um registro A para o domínio do tipo
hooks.yourdomain.tld, apontando para o endereço do servidor. - Instale um proxy reverso de nível web (nginx ou similar) e emita o certificado via cliente ACME.
- Rode a aplicação receptora numa porta local, fechada para o mundo, e direcione o servidor web para ela.
- Configure verificação de assinatura e fila de processamento, para responder ao provedor rapidamente.
Exemplo de receptor em Flask com verificação de assinatura HMAC e resposta rápida. O processamento pesado deixamos em fila, porque a maioria dos provedores espera resposta em no máximo 5–10 segundos:
import hmac, hashlib, json, os
from flask import Flask, request, abort
from queue import Queue
app = Flask(__name__)
SECRET = os.environ['WEBHOOK_SECRET'].encode()
jobs = Queue()
def valid_signature(raw_body, header_sig):
expected = hmac.new(SECRET, raw_body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, header_sig or '')
@app.post('/webhook/payments')
def payments():
raw = request.get_data()
if not valid_signature(raw, request.headers.get('X-Signature')):
abort(401)
event = json.loads(raw)
jobs.put(event) # processamento em background, resposta imediata
return '', 200Repare em três detalhes. A assinatura é verificada sobre o corpo bruto da requisição, e não sobre o JSON já interpretado, senão qualquer reformatação quebraria a comparação. A comparação é feita com compare_digest, para não vazar tempo de comparação. A resposta 200 é enviada antes do processamento, e o próprio evento vai para a fila. Se o provedor não receber 2xx no tempo previsto, ele considera a entrega falha e começa a repetir, e você vai receber duplicatas.
Abordagem 2. Túnel reverso
Se o código precisa rodar justamente na sua máquina local, e não no servidor, use um túnel reverso. A ideia é elegante e perfeitamente coerente com tudo o que discutimos acima: sua máquina inicia a conexão de saída até um servidor público, e esse servidor começa a escutar uma porta em seu nome e a empacotar conexões de entrada no canal já aberto. A direção de iniciação é de saída, então NAT e CGNAT não atrapalham. O ouvinte público está no servidor, então o provedor de webhooks consegue bater nele.
Implementação mais simples com SSH. No servidor público, a configuração do sshd precisa ter a opção GatewayPorts habilitada, ou então usar um servidor web local como front. Da máquina local:
# receptor local escutando em 127.0.0.1:8080
# pedimos ao servidor para escutar 127.0.0.1:9000 e empacotar o tráfego para nós
ssh -N -R 9000:127.0.0.1:8080 tunnel@hooks.yourdomain.tld
# no servidor, nginx faz proxy de https://hooks.yourdomain.tld/webhook -> 127.0.0.1:9000Para uso industrial, um processo ssh sozinho não é confiável o suficiente: a conexão pode cair. Use um wrapper com reconexão automática (autossh ou um supervisor equivalente) e habilite ServerAliveInterval, para que as quedas sejam detectadas em segundos. Existem também serviços de túnel especializados e soluções auto-hospedadas baseadas no mesmo princípio, com emissão automática de certificados e painel web. O princípio é sempre um: o agente local mantém uma conexão de saída, o lado público recebe webhooks.
Vale lembrar das limitações. Enquanto o túnel estiver rompido, os webhooks se perdem ou vão para as retentativas do provedor. Endereços temporários de alguns serviços de túnel mudam ao reiniciar, o que é inadmissível em produção: é preciso um domínio fixo. E o túnel adiciona latência e ponto de falha. Para desenvolvimento e depuração é a ferramenta ideal, para operação serve apenas em conjunto com monitoramento.
Abordagem 3. Fila de eventos do lado do provedor
Muitas APIs maduras oferecem alternativa ao modelo push: os eventos são acumulados num log ou fila do lado do provedor, e você os busca quando for conveniente. Isso muda a direção da conexão para de saída, no seu caso, e todo o problema de endereçabilidade desaparece.
Exemplo canônico é a Bot API de um dos mensageiros com o método getUpdates: o servidor guarda as atualizações não lidas por até 24 horas, e o cliente as busca periodicamente, passando o offset da última processada. Mecanismos parecidos existem em sistemas de pagamento como lista de eventos com cursor, em marketplaces como fila de alterações de pedidos, em provedores de nuvem como filas gerenciadas de mensagens, para onde é possível direcionar webhooks e consumi-los com um cliente.
import requests, time
TOKEN = 'your-bot-token'
BASE = f'https://api.messenger.example/bot{TOKEN}'
offset = 0
while True:
resp = requests.get(f'{BASE}/getUpdates',
params={'offset': offset, 'timeout': 50},
timeout=60)
for upd in resp.json().get('result', []):
handle(upd)
offset = upd['update_id'] + 1O parâmetro timeout=50 aqui ativa o long polling: o servidor mantém a conexão aberta até aparecer um evento ou até expirar o timeout, e você obtém entrega quase instantânea sem requisições vazias frequentes. É uma conexão de saída, funciona tranquilamente através de NAT, de modem móvel e, se necessário, de proxy.
Se o provedor não oferece fila embutida, é possível construí-la você mesmo a partir da primeira abordagem: um receptor mínimo numa VPS recebe os webhooks e os joga numa fila de mensagens, e sua máquina local consome a fila. É um híbrido que combina a confiabilidade do endereço público com a flexibilidade da execução local.
Abordagem 4. Polling em vez de assinatura
Quando o provedor não tem nem webhooks nem fila de eventos, resta o clássico polling de estado: você consulta o recurso periodicamente e compara com o estado anterior. É a abordagem mais universal, porque não exige do provedor nada além de uma API de leitura comum. Mas é também a mais exigente em termos de projeto: um loop ingênuo com intervalo fixo rapidamente bate nos limites de requisições, gasta orçamento em respostas vazias e ainda chega atrasado nos eventos. A próxima seção é inteiramente dedicada a como evitar isso.
Ferramentas que vão ser úteis
- Servidor web de front (nginx ou equivalente) para terminação TLS e roteamento para a aplicação.
- Cliente ACME para emissão e renovação automática de certificados.
- Fila de mensagens (Redis Streams, RabbitMQ ou fila gerenciada da nuvem) para armazenar eventos entre recebimento e processamento.
- Supervisor de túnel com reconexão automática para túneis reversos.
- Inspetor local de requisições para depuração: qualquer servidor HTTP mínimo que registre cabeçalhos e corpo ajuda a ver exatamente o que o provedor envia.
- Proxy Proxeon para chamadas de saída a APIs de terceiros a partir dos handlers, o que é detalhado abaixo.
Polling como substituto do webhook: como projetar para não bater nos limites
O polling é criticado por ser perdulário, e muitas vezes com razão. Mas o perdulário não é o polling em si, e sim sua má implementação. Um poller bem projetado, em carga sobre a API, é comparável aos webhooks e ainda é mais confiável, porque não depende da entregabilidade de conexões de entrada. Vamos ver os princípios.
Princípio 1. Cursor em vez de seleção completa
Nunca consulte "todos os pedidos" e não procure mudanças do seu lado. Use parâmetros como since, updated_after, cursor ou page_token, que existem em quase toda API moderna. Salve o último cursor de forma persistente, para que reiniciar o processo não recarregue o histórico inteiro. A resposta por cursor é pequena, processada rápido e não gera carga para o provedor.
Princípio 2. Requisições condicionais
Se o recurso suporta os cabeçalhos ETag e If-None-Match ou Last-Modified e If-Modified-Since, use-os. A resposta 304 Not Modified não traz corpo e muitas vezes não conta no limite ou conta em tarifa mais leve. É uma forma gratuita de reduzir o tráfego várias vezes.
Princípio 3. Intervalo adaptativo com jitter
Intervalo fixo é ruim em dois sentidos: em horas tranquilas gasta requisições à toa, em picos chega atrasado. O esquema adaptativo é simples: após uma resposta vazia, aumente o intervalo (por exemplo multiplique por 1,5 até um teto), após uma não vazia, volte ao mínimo. Adicione uma variação aleatória de 10–20 por cento, para que várias de suas instâncias não batam na API em sincronia.
Princípio 4. Respeito aos sinais do servidor
Os cabeçalhos Retry-After, X-RateLimit-Remaining e X-RateLimit-Reset não existem por estética. Ao receber 429, espere exatamente o que foi indicado. Ao ver que o restante do limite cai abaixo de um limiar, desacelere com antecedência. Isso não é só educação, é proteção contra bloqueios temporários da chave.
Princípio 5. Idempotência no processamento
O polling por natureza pode retornar o mesmo evento duas vezes: na borda do cursor, após uma falha, em sobreposição de janelas. Todo evento deve ter um identificador único, e o handler deve ter uma tabela de identificadores já processados com prazo razoável de retenção. Essa mesma regra protege contra duplicatas de webhooks em reentregas.
Esqueleto pronto de poller adaptativo
import random, time, requests
MIN_INTERVAL, MAX_INTERVAL = 5, 300
interval = MIN_INTERVAL
cursor = load_cursor() # do BD ou arquivo
etag = None
seen = SeenStore(ttl_hours=48) # armazenamento de ids processados
while True:
headers = {'If-None-Match': etag} if etag else {}
r = requests.get('https://api.example.com/v1/events',
params={'cursor': cursor, 'limit': 100},
headers=headers, timeout=(5, 30))
if r.status_code == 429:
time.sleep(int(r.headers.get('Retry-After', 60)))
continue
if r.status_code == 304:
interval = min(interval * 1.5, MAX_INTERVAL)
elif r.ok:
etag = r.headers.get('ETag')
events = r.json()['data']
for ev in events:
if not seen.contains(ev['id']):
handle(ev)
seen.add(ev['id'])
if events:
cursor = r.json()['next_cursor']
save_cursor(cursor)
interval = MIN_INTERVAL
else:
interval = min(interval * 1.5, MAX_INTERVAL)
remaining = int(r.headers.get('X-RateLimit-Remaining', 1000))
if remaining < 50:
interval = max(interval, 60)
time.sleep(interval * random.uniform(0.9, 1.2))Check-list de projeto de polling
- Cursor ou marca temporal salvos de forma persistente e que sobrevivem a reinícios.
- Requisições condicionais usadas, se a API as suportar.
- Intervalo adaptativo, com teto e jitter.
- Código 429 e cabeçalho Retry-After tratados explicitamente.
- Cada evento é processado de forma idempotente, por identificador único.
- Timeouts de conexão e de leitura definidos explicitamente e separadamente.
- Métricas: frequência de requisições, proporção de respostas vazias, latência entre evento e processamento.
- Se o provedor suporta long polling, ele está ativo e o polling normal está desativado.
Com esse design, um poller com intervalo mínimo de 5 segundos, em momento de silêncio, chega ao intervalo de 5 minutos e faz em torno de 300 requisições por dia por recurso. Isso é dezenas de vezes menos que o loop ingênuo a cada 10 segundos, que faz 8640 requisições por dia com a mesma latência média de entrega em horas ativas.
Onde o proxy ainda é necessário ao lado dos webhooks: respostas de saída e chamadas a APIs de terceiros
Seria incorreto terminar com a ideia de que "o proxy não tem relação com webhooks". Tem, e muito específica, só que do outro lado do esquema. Tendo recebido o evento, seu handler quase sempre faz requisições de saída: confirma a operação, busca detalhes do pedido, envia dados para outro sistema, notifica o usuário. Todas essas requisições são de saída, e aí o proxy está no seu lugar.
Cenário 1. Verificação do evento por requisição reversa
Boa prática de segurança: não confiar cegamente no corpo do webhook, mas, após verificar a assinatura, consultar o objeto junto ao provedor pelo seu identificador. Essa requisição sai do seu servidor para a API do provedor. Se o provedor restringe acesso por região ou faz análise comportamental da origem das requisições, um endereço de saída estável da região desejada via Proxeon torna o padrão de tráfego previsível.
Cenário 2. Chamadas a APIs de terceiros a partir do handler
O handler de um webhook de marketplace pode chamar a API do serviço de entrega, do serviço de verificação de fornecedores, da API de mapas. Cada uma tem seus limites por endereço IP. Distribuir as integrações em endereços de saída diferentes isola uma da outra: esgotar o limite de uma integração não paralisa as demais.
Cenário 3. Separação de identidade do tráfego de saída
Quando um mesmo servidor atende vários clientes ou projetos independentes, é útil que seu tráfego de saída para APIs externas saia de endereços diferentes. Isso facilita o diagnóstico (pelo endereço se vê de quem é a requisição) e reduz o risco de que problemas de um projeto afetem outros.
Exemplo: receptor direto, saída via proxy
Regra principal: o receptor de webhooks escuta diretamente num endereço público, e o proxy é usado apenas para chamadas de saída. Não tente "empacotar" o receptor num proxy, isso é sem sentido por todas as razões discutidas acima.
import requests
from flask import Flask, request
app = Flask(__name__)
OUT_PROXY = 'http://user:pass@gate.proxeon.net:PORT'
outbound = requests.Session()
outbound.proxies = {'http': OUT_PROXY, 'https': OUT_PROXY}
@app.post('/webhook/orders')
def orders():
event = request.get_json()
# recebimento é direto, sem proxy
order_id = event['order_id']
# verificação de saída e chamadas a APIs de terceiros - via proxy
full = outbound.get(f'https://api.marketplace.example/orders/{order_id}',
timeout=(5, 20)).json()
outbound.post('https://api.delivery.example/shipments',
json={'order': full}, timeout=(5, 20))
return '', 200Algumas observações práticas. Mantenha uma Session separada para chamadas de saída, para que as configurações de proxy não vazem para outras partes da aplicação. Defina timeouts explicitamente: pelo proxy o caminho é mais longo, e uma chamada de saída travada não deve atrasar a resposta ao provedor do webhook. Idealmente, faça chamadas de saída não no handler da requisição HTTP, mas num worker em background que consome da fila. E se a API de terceiros exigir que seu endereço esteja na lista de permitidos, use um plano com endereço de saída estático, e não rotativo.
Tabela "tarefa — solução adequada"
Vamos consolidar tudo num guia único. Para cada tarefa típica indica-se se o proxy a resolve, e o que usar em vez dele ou junto com ele.
- Tarefa: fazer requisições de saída a APIs externas de uma região ou operadora específica. Solução: proxy Proxeon, plano estático ou rotativo conforme os requisitos. Papel do proxy: principal.
- Tarefa: receber webhooks de um gateway de pagamento em produção. Solução: VPS com endereço público, domínio, TLS, receptor com verificação de assinatura e fila. Papel do proxy: apenas para chamadas de saída a partir do handler.
- Tarefa: depurar o recebimento de webhooks na máquina local do desenvolvedor. Solução: túnel reverso até um servidor público com domínio fixo. Papel do proxy: nenhum.
- Tarefa: receber eventos de um mensageiro ou API com fila, com o código rodando em casa ou atrás de modem móvel. Solução: long polling de métodos do tipo getUpdates, consumo da fila do provedor. Papel do proxy: opcional para requisições de saída.
- Tarefa: acompanhar mudanças numa API sem webhooks nem filas. Solução: polling adaptativo com cursor, requisições condicionais e respeito aos limites. Papel do proxy: distribuição de carga por endereços de saída dentro dos limites do provedor.
- Tarefa: receber webhooks num computador conectado via modem móvel. Solução: impossível diretamente por causa do CGNAT; use túnel reverso ou fila. Papel do proxy: nenhum.
- Tarefa: várias integrações num mesmo servidor não devem interferir entre si nos limites das APIs de terceiros. Solução: endereços de saída Proxeon separados por integração, mais filas separadas. Papel do proxy: principal para a parte de saída.
- Tarefa: uma API de terceiros exige que o endereço esteja numa lista de permitidos. Solução: endereço de saída estático; para receber webhooks, endereço público do seu servidor. Papel do proxy: plano estático para a parte de saída.
- Tarefa: obter um endereço público no roteador doméstico. Solução: assunto vizinho, depende do provedor doméstico; aplicável apenas havendo endereço público real no equipamento. Papel do proxy: nenhum.
Erros comuns: o que não se deve fazer
Vamos reunir as pedras em que mais se tropeça. Algumas custam horas de depuração, outras custam pagamentos perdidos.
Erro 1. Indicar o endereço do proxy como URL de webhook
Já foi detalhado acima, mas repetimos: no endereço de saída do proxy não há o seu ouvinte. O provedor receberá timeout ou recusa de conexão e, após algumas falhas, cancelará a assinatura. Alguns provedores, em erros repetidos, bloqueiam a URL por longo prazo.
Erro 2. Indicar endereço local ou privado
Uma URL como http://192.168.1.10:8080/hook ou http://localhost/hook é roteável apenas dentro da sua rede. O provedor não tem como chegar até ela fisicamente. Muitos provedores rejeitam de imediato essas URLs no cadastro da assinatura, mas não todos.
Erro 3. Certificado autoassinado ou HTTP comum
Os provedores de webhook verificam o certificado. Certificado autoassinado ou vencido leva a recusa silenciosa da entrega. HTTP comum sem TLS a maioria dos provedores não admite de forma alguma.
Erro 4. Processamento longo dentro do handler HTTP
Se o handler puxa dados de três APIs externas e grava no banco antes de responder ao provedor, ele facilmente ultrapassa o timeout de espera. O provedor considera a entrega malsucedida e repete. Você processa o mesmo evento várias vezes. A resposta deve sair em centenas de milissegundos, o processamento deve ir para a fila.
Erro 5. Ausência de idempotência
Reentregas são a norma, não a exceção. Sem considerar os identificadores processados, você vai criar um pedido duas vezes, enviar uma notificação duas vezes ou lançar um débito duas vezes no sistema contábil.
Erro 6. Confiar cegamente no corpo do webhook
A URL pública é acessível a todos. Sem verificação de assinatura, qualquer um pode te enviar um evento falso de "pagamento aprovado". Verifique o HMAC e, para operações críticas, consulte o objeto junto ao provedor.
Erro 7. Endereço temporário de túnel em produção
Um domínio gerado aleatoriamente por um serviço de túnel muda ao reiniciar. A assinatura no provedor continua vinculada à URL antiga. Os eventos se perdem até alguém notar. Em operação, o túnel é admissível apenas com domínio fixo e monitoramento.
Erro 8. Polling com intervalo fixo e curto
A cada segundo, sem cursor e sem requisições condicionais, é caminho direto para 429 e bloqueio temporário da chave. Pior: durante o bloqueio, você deixa de receber qualquer coisa, e a latência de entrega vira infinita.
Erro 9. Deixar chamadas de saída via proxy sem timeouts
O proxy adiciona um nó intermediário. Sem timeouts explícitos, uma chamada de saída travada segura o worker, e, se for feita dentro do handler HTTP, também quebra a resposta ao provedor. Sempre defina timeout de conexão e de leitura separadamente.
Erro 10. Esperar que o comando BIND do SOCKS5 te transforme em servidor
Aparece em quem leu a especificação. Nos nós comerciais o comando, em regra, não está implementado, e onde está, dá uma conexão única por pouco tempo. Não serve para webhooks.
Casos e resultados: como isso aparece na prática
Três histórias, montadas a partir de situações típicas de desenvolvimento de integração. Os números estão arredondados, mas a ordem de grandeza é real.
Caso 1. Notificações de pagamento de uma loja online
Uma equipe pequena desenvolvia uma loja em um construtor de sites e escreveu um handler de pagamentos em Python, que rodava num computador do escritório atrás de um modem móvel. Nas configurações do provedor de pagamento indicaram o endereço do proxy móvel, porque "ele é público". O provedor repetia a entrega segundo a agenda 1, 5, 30 minutos, 2 horas, e depois desativou a assinatura. Em uma semana acumularam cerca de 40 pedidos com status "aguardando pagamento", embora os pagamentos tivessem sido efetivamente feitos, o que exigiu conciliação manual.
Solução: alugou-se uma VPS mínima, subiu-se um receptor com verificação de assinatura e fila no Redis, o handler continuou local e consome a fila por conexão de saída. Adicionalmente, uma vez por hora roda um polling de conciliação da lista de pagamentos das últimas 24 horas com cursor, que captura eventos perdidos por qualquer falha. Resultado: divergências entre o provedor e a contabilidade nos três meses seguintes não foram registradas, e o tempo entre pagamento e mudança de status do pedido ficou em média 1,2 segundo.
Caso 2. Bot de suporte num notebook com modem
Um desenvolvedor escrevia um bot para a equipe interna e queria rodá-lo do notebook, conectado por modem móvel. A tentativa de registrar o webhook no endereço do proxy, como esperado, não deu certo. Mudar para long polling via getUpdates com timeout de 50 segundos resolveu a tarefa em meia hora: a conexão é de saída, nem o modem nem o CGNAT atrapalham. O consumo de requisições é da ordem de 1700 por dia em pleno ocioso, o que para essa API é irrelevante. Para depurar a integração com um CRM externo, que só sabe trabalhar com webhooks, subiu-se um túnel SSH reverso até um servidor alugado com domínio fixo, e em produção o receptor migrou para o próprio servidor.
Caso 3. Monitoramento de status num marketplace sem webhooks
O operador de várias lojas num marketplace acompanhava status de pedidos por API, que não tinha webhooks. Um polling ingênuo a cada 10 segundos por loja dava cerca de 50 mil requisições por dia e vivia batendo no 429. Após reprojetar segundo os princípios da sexta seção (cursor updated_after, intervalo adaptativo de 15 segundos a 10 minutos, tratamento de Retry-After, idempotência por identificador de pedido), a carga caiu para aproximadamente 4 mil requisições por dia, ou seja, mais de 12 vezes menos, e a latência média de detecção de mudança em horário comercial ficou dentro de 20 segundos. As chamadas de saída para a API do marketplace e para a API do serviço de entrega foram separadas em endereços de saída Proxeon distintos, para que os limites de uma integração não afetem a outra e para que, pelo endereço de origem nos logs, se veja de imediato qual loja iniciou a requisição.
FAQ: perguntas frequentes sobre proxy e recebimento de webhooks
Se eu tenho um IP estático dedicado de proxy, posso receber webhooks nele?
Não. A estabilidade do endereço resolve a questão da previsibilidade para requisições de saída e para listas de endereços permitidos no lado de APIs de terceiros. Mas porta de escuta com o seu código nesse endereço continua não existindo: ali roda o software do proxy, não o seu receptor. Para receber, você precisa de um servidor que você controla.
Por que serviços de verificação de IP mostram um endereço público, se ele não é endereçável de fora?
O serviço de verificação vê o endereço de origem da requisição de entrada que chega a ele, ou seja, o endereço do gateway NAT da operadora ou do nó do proxy. É o endereço de onde o tráfego sai, e não o endereço no qual se pode entrar até você. Visibilidade do endereço de fora e possibilidade de iniciar conexão até ele são propriedades distintas.
É possível receber webhooks via SOCKS5 com o comando BIND?
Na prática, não. O comando está descrito na especificação, mas em nós comerciais normalmente não está implementado por razões de segurança, e onde está implementado, aceita uma conexão de entrada por pouco tempo após uma conexão de saída para o mesmo host. Para registrar uma URL permanente de webhook com TLS, isso é inaplicável.
Qual a diferença entre túnel reverso e encaminhamento de portas no roteador?
O encaminhamento de portas só funciona se no seu equipamento houver um endereço público real: o roteador recebe a conexão de entrada e a repassa para dentro da rede. O túnel reverso não exige endereço público nenhum do seu lado: sua máquina inicia a conexão de saída até um servidor público, e este escuta em seu nome. Em redes móveis com CGNAT, o primeiro é impossível por princípio, o segundo funciona.
O túnel reverso é confiável para produção?
Sob condições: domínio fixo, reconexão automática, verificação de vivacidade da conexão, monitoramento de quedas e bufferização no lado público durante a indisponibilidade. Sem essas condições, o túnel serve para desenvolvimento, mas não para operação. Para integrações críticas, é mais confiável colocar o receptor diretamente num servidor público.
O polling não é pior que os webhooks em latência?
O long polling dá latência comparável à dos webhooks: o evento chega no momento em que aparece. O polling adaptativo comum dá latência desde o intervalo mínimo nas horas ativas até o máximo no silêncio. Para muitos processos de negócio, uma latência de 15–30 segundos é aceitável. Já os webhooks dependem da entregabilidade da conexão de entrada e exigem mecanismo de conciliação para o caso de perdas, de modo que, em sistemas reais, o polling frequentemente complementa os webhooks em vez de perder para eles.
Preciso de proxy se já tenho uma VPS com endereço público?
Para receber webhooks, não. Para requisições de saída a partir dos handlers, é útil quando a API de terceiros é sensível à região de origem, quando é preciso isolar limites de integrações diferentes por endereço ou quando se quer que as requisições pareçam tráfego de um assinante móvel de uma operadora específica. É uma tarefa separada, e resolvida com uma ferramenta separada.
Como saber se o provedor está ao menos tentando entregar o webhook?
A maioria dos provedores mantém um log de entregas com códigos de resposta e motivos de erro. Olhe nele em primeiro lugar: ali se verá se o domínio resolve, se o TLS é estabelecido, que código o seu servidor devolveu e em quantos milissegundos. Para diagnóstico local, suba um servidor HTTP mínimo que registre cabeçalhos e corpo e direcione o túnel para ele.
O que fazer se o provedor exige resposta em 3 segundos, e o processamento leva 10?
Separar recebimento do processamento. O receptor verifica a assinatura, coloca o evento na fila e responde 200 em dezenas de milissegundos. O worker consome a fila e processa o evento o tempo que for necessário, fazendo chamadas de saída a APIs de terceiros, se preciso via proxy, com timeouts explícitos e retentativas.
Conclusão: o modelo correto e os próximos passos
Se resumirmos o artigo numa ideia só, ela soa assim: o proxy muda de onde você sai para a rede, mas não cria um lugar por onde dá para entrar até você. A direção da conexão é uma propriedade fundamental, e nenhum plano a inverte. O proxy móvel Proxeon faz das suas requisições de saída tráfego de um assinante de uma operadora específica, e é justamente por isso que ele herda a não-endereçabilidade de fora do assinante: atrás do CGNAT não há portas de escuta, e o endereço muda por natureza da rede.
O recebimento de webhooks se resolve com ferramentas de outra classe. Servidor público com domínio e TLS é a variante básica para operação. Túnel reverso é para desenvolvimento e para casos em que o código precisa rodar localmente. Fila de eventos e long polling no lado do provedor é a variante mais elegante, quando o provedor a oferece. Polling adaptativo com cursor, requisições condicionais e respeito aos limites é o caminho alternativo universal, que, com bom design, não fica atrás dos webhooks em valor prático.
E o proxy volta ao esquema onde é o seu lugar: nas chamadas de saída a partir dos handlers, na verificação de eventos por requisição reversa, no isolamento de limites de integrações diferentes por endereços de saída. O receptor escuta diretamente, as saídas vão pelo proxy — essa fórmula cobre a esmagadora maioria das tarefas reais.
O que fazer depois de ler
- Abra as configurações de cada uma das suas assinaturas de webhook e verifique para onde aponta a URL: para um servidor que você controla e que escuta na porta 443 com certificado válido.
- Certifique-se de que o receptor responde rápido, e que o processamento está em fila; verifique a existência de verificação de assinatura e de controle de identificadores processados.
- Para integrações sem webhooks, reescreva o polling segundo o check-list da sexta seção e meça como mudaram o número de requisições e a latência.
- Revise as chamadas de saída a partir dos handlers: onde for necessário endereço regional estável ou isolamento de limites, conecte um proxy com sessão separada e timeouts explícitos.
- Adicione um polling de conciliação como seguro para webhooks críticos: uma vez por hora, consulte os eventos do último intervalo e compare com os processados.
Separar as tarefas em saída e entrada não é pedantismo, é uma forma de parar de gastar horas depurando o que não pode funcionar por definição, e direcioná-las ao que vai funcionar.