Para implementar webhooks em consultas de CPF, sua aplicação cria um endpoint HTTP que recebe notificações automáticas quando o resultado de uma consulta fica pronto — sem precisar fazer polling. O fluxo envolve uma fila de mensagens (Redis, RabbitMQ ou SQS), um worker que chama a API CPFHub.io e um mecanismo de assinatura HMAC para garantir autenticidade das notificações.
Introdução
Em muitos fluxos de negócio, a validação de CPF não precisa ser sincrona. Processos como análise de crédito, onboarding em lote ou verificação de beneficiarios podem se beneficiar de um modelo assincrono, onde a sua aplicação dispara a consulta e recebe o resultado via webhook quando ele estiver pronto.
O que são webhooks
Webhooks são callbacks HTTP que permitem que um serviço envie dados automaticamente para a sua aplicação quando um evento ocorre. Em vez de fazer polling (verificar repetidamente se algo mudou), sua aplicação recebe uma notificação proativa.
-
Polling -- Sua aplicação pergunta: "Ja tem resultado?" repetidamente.
-
Webhook -- O serviço avisa: "O resultado esta pronto" enviando uma requisição POST para o seu endpoint.
Arquitetura do sistema
O fluxo assincrono com webhooks funciona da seguinte forma:
- Sua aplicação recebe um pedido de validação de CPF.
- Em vez de chamar a API e esperar, enfileira a consulta em uma fila (Redis, RabbitMQ, SQS).
- Um worker consome a fila, faz a chamada a API da CPFHub.io e armazena o resultado.
- O worker envia o resultado para o endpoint de webhook da aplicação solicitante.
- A aplicação processa a notificação e atualiza o status.
Criando o endpoint de webhook (Express)
O primeiro passo e criar um endpoint na sua aplicação para receber as notificações:
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const WEBHOOK_SECRET = process.env.WEBHOOK_SECRET;
function verificarAssinatura(payload, assinatura) {
const hash = crypto
.createHmac('sha256', WEBHOOK_SECRET)
.update(JSON.stringify(payload))
.digest('hex');
return crypto.timingSafeEqual(
Buffer.from(hash),
Buffer.from(assinatura)
);
}
app.post('/webhooks/cpf-resultado', (req, res) => {
const assinatura = req.headers['x-webhook-signature'];
if (!assinatura || !verificarAssinatura(req.body, assinatura)) {
return res.status(401).json({ error: 'Assinatura invalida' });
}
const { cpf, resultado, requestId } = req.body;
console.log(`Resultado recebido para CPF ${cpf}: ${JSON.stringify(resultado)}`);
// Processar o resultado (atualizar banco, notificar usuario, etc.)
// processarResultado(cpf, resultado, requestId);
res.status(200).json({ received: true });
});
app.listen(3000, () => console.log('Webhook listener na porta 3000'));
Criando o worker que consulta a API
O worker consome a fila e faz a consulta real:
import requests
import json
import hashlib
import hmac
import os
import redis
import time
CPFHUB_API_KEY = os.environ['CPFHUB_API_KEY']
WEBHOOK_URL = os.environ['WEBHOOK_URL']
WEBHOOK_SECRET = os.environ['WEBHOOK_SECRET']
r = redis.Redis(host='localhost', port=6379, db=0)
def consultar_cpf(cpf):
url = f'https://api.cpfhub.io/cpf/{cpf}'
headers = {
'x-api-key': CPFHUB_API_KEY,
'Accept': 'application/json'
}
response = requests.get(url, headers=headers, timeout=15)
return response.json()
def enviar_webhook(payload):
body = json.dumps(payload)
assinatura = hmac.new(
WEBHOOK_SECRET.encode(),
body.encode(),
hashlib.sha256
).hexdigest()
requests.post(
WEBHOOK_URL,
data=body,
headers={
'Content-Type': 'application/json',
'x-webhook-signature': assinatura
},
timeout=10
)
def processar_fila():
while True:
item = r.brpop('fila:consulta_cpf', timeout=5)
if item:
dados = json.loads(item[1])
cpf = dados['cpf']
request_id = dados['requestId']
resultado = consultar_cpf(cpf)
enviar_webhook({
'cpf': cpf,
'resultado': resultado,
'requestId': request_id
})
time.sleep(0.1)
if __name__ == '__main__':
processar_fila()
Enfileirando consultas
Quando sua aplicação recebe um pedido de validação, ela enfileira em vez de processar diretamente:
import redis
import json
import uuid
r = redis.Redis(host='localhost', port=6379, db=0)
def solicitar_validacao(cpf):
request_id = str(uuid.uuid4())
r.lpush('fila:consulta_cpf', json.dumps({
'cpf': cpf,
'requestId': request_id
}))
return request_id
O requestId permite rastrear a consulta do inicio ao fim.
Boas práticas para webhooks
Idempotencia
Sua aplicação pode receber a mesma notificação mais de uma vez. Use o requestId para garantir que o processamento ocorra apenas uma vez:
const processados = new Set();
app.post('/webhooks/cpf-resultado', (req, res) => {
const { requestId } = req.body;
if (processados.has(requestId)) {
return res.status(200).json({ received: true, duplicate: true });
}
processados.add(requestId);
// processar resultado...
res.status(200).json({ received: true });
});
Retentativas com backoff exponencial
Se o webhook falhar, implemente retentativas com intervalos crescentes:
- 1a tentativa -- imediata.
- 2a tentativa -- apos 5 segundos.
- 3a tentativa -- apos 30 segundos.
- 4a tentativa -- apos 2 minutos.
- 5a tentativa -- apos 10 minutos.
Validação de assinatura
Sempre valide a assinatura do webhook para garantir que a notificação vem de uma fonte confiável, conforme mostrado no exemplo acima.
Resposta rápida
O endpoint de webhook deve responder com status 200 o mais rápido possível. Processe o payload de forma assincrona para evitar timeouts.
Quando usar webhooks vs. consulta sincrona
| Cenário | Abordagem recomendada |
|---|---|
| Checkout em tempo real | Sincrona |
| Onboarding interativo | Sincrona |
| Validação em lote | Assincrona (webhook) |
| Análise de crédito em background | Assincrona (webhook) |
| Atualização cadastral periódica | Assincrona (webhook) |
Perguntas frequentes
O que é necessário para receber notificações via webhook em consultas de CPF?
Você precisa de um endpoint HTTP acessível publicamente que aceite requisições POST, uma fila de mensagens para desacoplar as consultas (Redis ou similar) e um worker que chame a API CPFHub.io. Implemente validação de assinatura HMAC-SHA256 para garantir que apenas notificações legítimas sejam processadas.
Como garantir que o mesmo webhook não seja processado duas vezes?
Use o campo requestId retornado em cada consulta para implementar idempotencia. Armazene os IDs já processados em um Set em memória ou no banco de dados e, ao receber um webhook, verifique se o requestId já foi visto antes de executar qualquer ação.
Qual fila de mensagens é mais indicada para esse padrão?
Depende da sua infraestrutura. Redis com o módulo de filas simples atende bem volumes até alguns milhares de consultas por hora. Para volumes maiores ou garantias de entrega mais robustas, considere RabbitMQ ou AWS SQS. A OWASP documenta boas práticas de segurança para sistemas de mensageria que processam dados pessoais.
Quantas tentativas de reenvio devo configurar no worker?
Cinco tentativas com backoff exponencial cobrem a maioria dos cenários de indisponibilidade temporária: imediata, 5s, 30s, 2min e 10min. Após a quinta falha, mova o item para uma dead-letter queue e gere um alerta para investigação manual.
Conclusão
Implementar webhooks para consultas de CPF permite desacoplar seus fluxos, melhorar a experiência do usuário e processar grandes volumes de forma eficiente. Com uma fila de mensagens, um worker dedicado e um endpoint de webhook seguro, você cria uma arquitetura resiliente e escalável.
Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito.
CPFHub.io
Pronto para integrar a API?
50 consultas gratuitas para testar agora. Sem cartão de crédito. Acesso imediato à documentação.
Sobre a redação
Redação CPFHub.io
Time editorial especializado em APIs de CPF, identidade digital e compliance no mercado brasileiro. Produzimos guias técnicos, análises regulatórias e tutoriais sobre LGPD e KYC para desenvolvedores e líderes de produto.



