Pular para o conteúdo principal

Rate Limiting

O EloFiel aplica limites de requisições para proteger a plataforma contra uso abusivo.

Limites atuais

EndpointLimiteJanelaCritério
POST /api/v1/authadmin/login5 tentativas1 minutoPor IP
Demais endpoints PDVSem limite fixo documentadoUso razoável esperado
Limites nos endpoints PDV

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ódigoFazer retry?Motivo
400NãoRequisição inválida — corrigir antes de reenviar
401NãoChave inválida — verificar configuração
422NãoRegra de negócio — tratar a causa
429Sim (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.