
O que é webhook e por que é muito melhor do que polling
Polling parece óbvio quando você começa. Funciona. Até você entender webhook e perceber que estava resolvendo o problema do jeito mais caro possível.
Minha primeira integração com pagamento fazia polling.
A cada 5 segundos, meu sistema perguntava ao gateway: "esse pagamento foi aprovado?" O gateway respondia "não" — novamente — e eu esperava mais 5 segundos.
Funcionava. Era o jeito mais ineficiente possível de resolver o problema, mas funcionava.
Quando aprendi sobre webhook, me perguntei por que não tinha pensado nisso antes.
Polling: o que é e por que parece intuitivo
Polling é perguntar repetidamente até ter resposta.
while True:
status = verificar_pagamento(pagamento_id)
if status == 'aprovado':
processar_pedido()
break
time.sleep(5)
Intuitivo porque segue o modelo mental de "fico esperando até saber". É como você verifica se o ônibus chegou olhando pela janela a cada 5 minutos.
O problema: para cada pagamento em andamento, você faz uma requisição a cada 5 segundos. 100 pagamentos simultâneos = 20 requisições por segundo. Você está batendo na API do gateway 20 vezes por segundo para ouvir "não" 19 vezes e "sim" uma.
Isso tem custo. A maioria das APIs tem rate limit. E você está usando toda essa capacidade para ouvir "ainda não".
Webhook: o modelo inverso
Webhook inverte a lógica. Em vez de você perguntar, o sistema externo te avisa quando algo acontece.
Você registra uma URL no gateway: "quando um pagamento mudar de status, manda um POST para https://meusite.com/webhooks/pagamento".
Quando o pagamento é aprovado, o gateway faz uma requisição HTTP para sua URL com os dados do evento. Você processa, responde 200, pronto.
Zero polling. Zero "ainda não". Você recebe exatamente quando o evento acontece.
Como implementar o lado receptor
@app.route('/webhooks/pagamento', methods=['POST'])
def receber_webhook():
# 1. valida assinatura (importante!)
signature = request.headers.get('X-Webhook-Signature')
if not validar_assinatura(request.data, signature, WEBHOOK_SECRET):
return '', 401
# 2. parseia o evento
evento = request.json
if evento['tipo'] == 'pagamento.aprovado':
processar_pedido(evento['pagamento_id'])
elif evento['tipo'] == 'pagamento.recusado':
notificar_usuario(evento['pagamento_id'])
# 3. responde 200 RÁPIDO
return '', 200
Três regras que aprendi na prática: valida a assinatura (qualquer pessoa pode fazer POST para sua URL — o gateway envia uma assinatura HMAC do payload, valida antes de processar), responde 200 rápido (o gateway tem timeout — aceita o evento, coloca numa fila, processa assincronamente, responde 200 imediatamente), e trata duplicatas (gateways enviam webhook mais de uma vez se não recebem 200 a tempo — seu handler precisa ser idempotente).
Quando polling ainda faz sentido
Nem sempre webhook é possível.
Se o sistema externo não suporta webhook — e tem muitos sistemas legados que não suportam — polling é a única opção.
Se você precisa de estado em tempo real contínuo (dashboards de métricas, por exemplo), polling ou websocket fazem mais sentido do que webhook.
Se você está em ambiente local de desenvolvimento, receber webhook de sistema externo exige tunnel (ngrok, por exemplo) porque seu localhost não é acessível da internet.
Mas quando o sistema externo suporta webhook e o evento é assíncrono por natureza (pagamento aprovado, email entregue, build concluído), webhook é sempre a escolha certa.
O modelo mental que fica
Polling = você busca a informação.
Webhook = a informação te encontra.
Para qualquer integração nova, primeiro pergunta: esse sistema suporta webhook? Se sim, usa. Se não, polling com intervalo inteligente (exponential backoff, não intervalo fixo).
Essa semana: olha as integrações do seu projeto atual. Tem alguma usando polling que poderia usar webhook? Vale verificar se o sistema externo suporta — economiza requisições, reduz latência, simplifica o código.