Rate Limiting
O EloFiel aplica limites de requisições para proteger a plataforma contra uso abusivo.
Limites atuais
| Endpoint | Limite | Janela | Critério |
|---|---|---|---|
POST /api/v1/authadmin/login | 5 tentativas | 1 minuto | Por IP |
| Demais endpoints PDV | Sem limite fixo documentado | — | Uso razoável esperado |
Os endpoints de venda e resgate (/api/v1/venda, /api/v1/resgate) não possuem um limite rígido documentado publicamente, mas estão sujeitos a proteções contra picos anormais. Em integrações normais de PDV, esses limites não serão atingidos.
Como detectar o rate limit
Quando o limite é atingido, a API retorna HTTP 429 com o envelope padrão:
{
"sucesso": false,
"dados": null,
"mensagem": "Limite de requisições excedido.",
"erros": [
"Muitas tentativas. Aguarde 1 minuto."
]
}
Sempre verifique o código HTTP antes de processar o corpo da resposta:
const response = await fetch(url, options);
if (response.status === 429) {
// Rate limit atingido — aplicar backoff
await sleep(60_000); // aguardar 1 minuto
return retry();
}
Implementando retry com backoff exponencial
Para lidar com erros temporários (429 e 5xx), implemente um retry com espera crescente entre tentativas:
async function fetchComRetry(url, options, maxTentativas = 3) {
for (let tentativa = 1; tentativa <= maxTentativas; tentativa++) {
try {
const response = await fetch(url, options);
// Sucesso — retornar imediatamente
if (response.ok) {
return response.json();
}
// Erros que NÃO devem ser retentados
if (response.status === 400 || response.status === 401 || response.status === 422) {
const resultado = await response.json();
throw new Error(resultado.erros?.[0] ?? `HTTP ${response.status}`);
}
// Rate limit — aguardar janela fixa
if (response.status === 429) {
if (tentativa < maxTentativas) {
console.warn(`Rate limit atingido. Aguardando 60s antes da tentativa ${tentativa + 1}...`);
await sleep(60_000);
continue;
}
throw new Error('Rate limit excedido após múltiplas tentativas.');
}
// Erro 5xx — backoff exponencial
if (response.status >= 500) {
if (tentativa < maxTentativas) {
const espera = Math.pow(2, tentativa) * 1000; // 2s, 4s, 8s...
console.warn(`Erro ${response.status}. Tentativa ${tentativa}/${maxTentativas}. Aguardando ${espera}ms...`);
await sleep(espera);
continue;
}
throw new Error(`Erro do servidor (HTTP ${response.status}) após ${maxTentativas} tentativas.`);
}
} catch (erro) {
// Erro de rede (timeout, DNS, etc.)
if (tentativa < maxTentativas) {
const espera = Math.pow(2, tentativa) * 1000;
console.warn(`Erro de rede. Tentativa ${tentativa}/${maxTentativas}. Aguardando ${espera}ms...`);
await sleep(espera);
continue;
}
throw erro;
}
}
}
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
Regra de ouro: nunca faça retry em 4xx
| Código | Fazer retry? | Motivo |
|---|---|---|
| 400 | Não | Requisição inválida — corrigir antes de reenviar |
| 401 | Não | Chave inválida — verificar configuração |
| 422 | Não | Regra de negócio — tratar a causa |
| 429 | Sim (com espera) | Rate limit — aguardar a janela |
| 500+ | Sim (com backoff) | Erro temporário do servidor |
Boas práticas no PDV
Para operações de vendas: implemente uma fila local em vez de retry síncrono. Se a API falhar, grave a venda localmente e reprocesse em background sem travar o caixa.
Para consulta de saldo: defina um timeout de 5-8 segundos. Se a API não responder, exiba uma mensagem ao operador e permita continuar o atendimento sem o benefício.
Para o painel admin: o retry com backoff é suficiente — o usuário pode aguardar alguns segundos.