Retry automático com backoff exponencial é a estratégia mais eficaz para lidar com falhas transitórias em consultas de CPF via API. Em vez de retornar um erro imediatamente ao usuário, a aplicação tenta novamente após intervalos crescentes, recuperando-se de instabilidades de rede e picos de carga sem intervenção manual. Este guia mostra como implementar essa lógica em Python, JavaScript e Go com exemplos prontos para produção.
Introdução
Nenhuma integração com APIs externas está imune a falhas temporárias. Instabilidades de rede, picos de carga no servidor e timeouts são cenários que acontecem mesmo nas APIs mais confiáveis. Quando uma consulta de CPF falha, a decisão de simplesmente retornar um erro para o usuário ou tentar novamente pode fazer a diferença entre uma experiência fluida e uma frustração desnecessária.
Quando o retry é adequado
Nem toda falha justifica um retry. É importante distinguir entre erros temporários (que podem se resolver sozinhos) e erros permanentes (que exigem ação do desenvolvedor):
Erros que justificam retry
| Código HTTP | Significado | Ação recomendada |
|---|---|---|
| 500 | Internal Server Error | Retry com backoff |
| 503 | Service Unavailable | Retry com backoff |
| Timeout | Sem resposta no tempo limite | Retry com backoff |
Erros que NÃO justificam retry
| Código HTTP | Significado | Ação recomendada |
|---|---|---|
| 400 | Bad Request (CPF inválido) | Corrigir os dados enviados |
| 401 | Unauthorized (API key inválida) | Verificar a chave de API |
| 404 | Not Found | O CPF não existe na base |
Fazer retry em erros 400 ou 401 é inútil — o resultado será sempre o mesmo. Vale destacar que a API da CPFHub.io não retorna HTTP 429 nem bloqueia requisições quando o limite do plano gratuito é atingido: ela simplesmente cobra R$0,15 por consulta adicional, então não há necessidade de tratar 429 como erro de rate limit.
O que é backoff exponencial
O backoff exponencial é uma estratégia em que o intervalo entre cada tentativa aumenta progressivamente. Isso evita sobrecarregar a API com requisições repetidas e dá tempo para o problema ser resolvido.
Exemplo de intervalos:
| Tentativa | Intervalo base | Com jitter (aleatoriedade) |
|---|---|---|
| 1a | 1 segundo | 0,8 - 1,2 segundos |
| 2a | 2 segundos | 1,6 - 2,4 segundos |
| 3a | 4 segundos | 3,2 - 4,8 segundos |
O jitter (variação aleatória) evita que múltiplas instâncias da aplicação façam retry exatamente ao mesmo tempo, o que poderia causar um novo pico de carga na API. A OWASP recomenda backoff exponencial como controle padrão contra sobrecarga em integrações externas.
Implementação em Python
import requests
import time
import random
def consultar_cpf_com_retry(cpf, max_tentativas=3):
url = f"https://api.cpfhub.io/cpf/{cpf}"
headers = {
"x-api-key": "SUA_CHAVE_DE_API",
"Accept": "application/json"
}
codigos_retry = {500, 503}
for tentativa in range(max_tentativas):
try:
response = requests.get(url, headers=headers, timeout=10)
# Sucesso: retornar dados
if response.status_code == 200:
return response.json()
# Erro permanente: não fazer retry
if response.status_code in (400, 401, 404):
return {
"erro": f"Erro {response.status_code}",
"retry": False
}
# Erro temporário: fazer retry
if response.status_code in codigos_retry:
if tentativa < max_tentativas - 1:
espera = (2 ** tentativa) + random.uniform(0, 1)
print(f"Tentativa {tentativa + 1} falhou ({response.status_code}). "
f"Aguardando {espera:.1f}s...")
time.sleep(espera)
continue
except requests.exceptions.Timeout:
if tentativa < max_tentativas - 1:
espera = (2 ** tentativa) + random.uniform(0, 1)
print(f"Timeout na tentativa {tentativa + 1}. "
f"Aguardando {espera:.1f}s...")
time.sleep(espera)
continue
except requests.exceptions.ConnectionError:
if tentativa < max_tentativas - 1:
espera = (2 ** tentativa) + random.uniform(0, 1)
print(f"Erro de conexão na tentativa {tentativa + 1}. "
f"Aguardando {espera:.1f}s...")
time.sleep(espera)
continue
return {"erro": "Todas as tentativas falharam", "retry": True}
# Uso
resultado = consultar_cpf_com_retry("12345678900")
print(resultado)
Implementação em JavaScript (Node.js)
async function consultarCPFComRetry(cpf, maxTentativas = 3) {
const url = `https://api.cpfhub.io/cpf/${cpf}`;
const headers = {
'x-api-key': 'SUA_CHAVE_DE_API',
'Accept': 'application/json'
};
const codigosRetry = new Set([500, 503]);
for (let tentativa = 0; tentativa < maxTentativas; tentativa++) {
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), 10000);
try {
const response = await fetch(url, {
headers,
signal: controller.signal
});
clearTimeout(timeoutId);
// Sucesso
if (response.ok) {
return await response.json();
}
// Erro permanente
if ([400, 401, 404].includes(response.status)) {
return { erro: `Erro ${response.status}`, retry: false };
}
// Erro temporário
if (codigosRetry.has(response.status)) {
if (tentativa < maxTentativas - 1) {
const espera = Math.pow(2, tentativa) * 1000 + Math.random() * 1000;
console.log(
`Tentativa ${tentativa + 1} falhou (${response.status}). ` +
`Aguardando ${(espera / 1000).toFixed(1)}s...`
);
await new Promise(resolve => setTimeout(resolve, espera));
continue;
}
}
} catch (error) {
clearTimeout(timeoutId);
if (tentativa < maxTentativas - 1) {
const espera = Math.pow(2, tentativa) * 1000 + Math.random() * 1000;
const tipo = error.name === 'AbortError' ? 'Timeout' : 'Erro de conexão';
console.log(
`${tipo} na tentativa ${tentativa + 1}. ` +
`Aguardando ${(espera / 1000).toFixed(1)}s...`
);
await new Promise(resolve => setTimeout(resolve, espera));
continue;
}
}
}
return { erro: 'Todas as tentativas falharam', retry: true };
}
Implementação em Go
package main
import (
"fmt"
"io"
"math"
"math/rand"
"net/http"
"time"
)
func consultarCPFComRetry(cpf string, maxTentativas int) (string, error) {
url := fmt.Sprintf("https://api.cpfhub.io/cpf/%s", cpf)
codigosRetry := map[int]bool{500: true, 503: true}
client := &http.Client{Timeout: 10 * time.Second}
for tentativa := 0; tentativa < maxTentativas; tentativa++ {
req, err := http.NewRequest("GET", url, nil)
if err != nil {
return "", err
}
req.Header.Set("x-api-key", "SUA_CHAVE_DE_API")
req.Header.Set("Accept", "application/json")
resp, err := client.Do(req)
if err != nil {
if tentativa < maxTentativas-1 {
espera := math.Pow(2, float64(tentativa)) + rand.Float64()
fmt.Printf("Erro na tentativa %d. Aguardando %.1fs...\n",
tentativa+1, espera)
time.Sleep(time.Duration(espera * float64(time.Second)))
continue
}
return "", err
}
defer resp.Body.Close()
if resp.StatusCode == 200 {
body, _ := io.ReadAll(resp.Body)
return string(body), nil
}
if codigosRetry[resp.StatusCode] && tentativa < maxTentativas-1 {
espera := math.Pow(2, float64(tentativa)) + rand.Float64()
fmt.Printf("Status %d na tentativa %d. Aguardando %.1fs...\n",
resp.StatusCode, tentativa+1, espera)
time.Sleep(time.Duration(espera * float64(time.Second)))
continue
}
body, _ := io.ReadAll(resp.Body)
return string(body), fmt.Errorf("erro HTTP %d", resp.StatusCode)
}
return "", fmt.Errorf("todas as %d tentativas falharam", maxTentativas)
}
func main() {
resultado, err := consultarCPFComRetry("12345678900", 3)
if err != nil {
fmt.Println("Erro:", err)
return
}
fmt.Println(resultado)
}
Boas práticas para retry
-
Limite o número de tentativas — Três tentativas é um bom padrão. Mais do que isso raramente resolve o problema e mantém o usuário esperando por muito tempo.
-
Use backoff exponencial com jitter — Aumentar o intervalo entre tentativas e adicionar aleatoriedade evita sobrecarregar a API.
-
Classifique os erros — Apenas erros temporários (5xx, timeout) devem acionar o retry. Erros 4xx indicam problemas no lado do cliente e não melhoram com nova tentativa.
-
Registre cada tentativa — Mantenha logs com o número da tentativa, o código de erro e o tempo de espera para facilitar a investigação de problemas.
-
Defina um timeout total — Além do timeout individual de cada requisição, defina um limite máximo para o processo completo de retry, evitando que o usuário fique esperando indefinidamente.
-
Respeite o header Retry-After — Se a API retornar o header
Retry-After, use o valor informado em vez do backoff calculado.
Perguntas frequentes
Quantas tentativas de retry devo configurar para consultas de CPF?
Três tentativas é o padrão recomendado para a maioria dos casos. Com backoff exponencial, isso resulta em esperas de ~1s, ~2s e ~4s entre tentativas — tempo suficiente para falhas transitórias se resolverem sem deixar o usuário aguardando mais de 10 segundos no total. Aumentar para mais de 3 tentativas raramente melhora o resultado e piora a experiência percebida.
O retry funciona quando o limite de consultas do plano gratuito é atingido?
A API da CPFHub.io não bloqueia nem retorna erro quando o limite do plano gratuito (50 consultas/mês) é ultrapassado. Ela simplesmente cobra R$0,15 por consulta adicional e continua respondendo normalmente. Portanto, não há necessidade de tratar estouro de cota como cenário de retry — a consulta será processada e cobrada automaticamente.
Devo usar retry no frontend ou no backend?
A lógica de retry deve ficar exclusivamente no backend. Expor a API key no frontend já é um problema de segurança; adicionar retry lá amplia o risco ao tornar a chave ainda mais visível. No backend, você controla timeouts, logs centralizados e evita que o usuário dispare múltiplas tentativas simultâneas clicando várias vezes no botão.
Como o jitter ajuda a evitar sobrecarga na API?
Quando várias instâncias da aplicação falham ao mesmo tempo (por exemplo, durante um pico de tráfego), elas tendem a fazer retry no mesmo instante — criando uma nova onda de requisições que piora a sobrecarga. O jitter adiciona uma variação aleatória de alguns décimos de segundo ao intervalo de espera, espalhando as tentativas ao longo do tempo e reduzindo o impacto sobre a API.
Conclusão
Implementar retry automático com backoff exponencial é uma prática essencial para tornar a integração com APIs de CPF mais resiliente. Ao classificar corretamente os erros e aplicar intervalos crescentes entre as tentativas, sua aplicação consegue se recuperar de falhas temporárias sem impactar a experiência do usuário.
Cadastre-se em cpfhub.io — 50 consultas mensais gratuitas, sem cartão de crédito — e comece a testar sua lógica de retry com uma API estável e previsível.
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.



