Rate Limiting
Quick Reference
WhatPolítica de rate limiting da API A55 e estratégias de retry
WhyEvite interrupções de serviço durante períodos de alto tráfego
Reading Time7 min
DifficultyIntermediate
PrerequisitesIntegração com a API funcional
Política
| Parâmetro | Valor |
|---|---|
| Rate limit | 100 requisições por minuto por chave de API |
| Janela | Janela deslizante de 60 segundos |
| Escopo | Por client_id em todos os endpoints |
| Resposta ao atingir o limite | HTTP 429 Too Many Requests |
Headers de Rate Limit
Toda resposta da API inclui headers de rate limit:
HTTP/1.1 200 OK
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 73
X-RateLimit-Reset: 1711036800
Content-Type: application/json
| Header | Descrição |
|---|---|
X-RateLimit-Limit | Máximo de requisições permitidas por janela |
X-RateLimit-Remaining | Requisições restantes na janela atual |
X-RateLimit-Reset | Timestamp Unix de quando a janela é reiniciada |
Resposta HTTP 429
Quando você excede o limite:
{
"error": {
"code": "RATE_LIMIT_EXCEEDED",
"message": "Too many requests. Retry after 23 seconds.",
"details": [
{
"field": "rate_limit",
"reason": "100 requests per minute exceeded"
}
]
},
"request_id": "req_abc123..."
}
O header Retry-After indica quantos segundos esperar:
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1711036823
Estratégia de Retry com Backoff Exponencial
- cURL
- Python
- Node.js
#!/bin/bash
MAX_RETRIES=3
RETRY_DELAY=1
for i in $(seq 1 $MAX_RETRIES); do
RESPONSE=$(curl -s -w "\n%{http_code}" \
-X POST "https://sandbox.api.a55.tech/api/v1/bank/wallet/charge/" \
-H "Authorization: Bearer ${A55_ACCESS_TOKEN}" \
-H "Content-Type: application/json" \
-d '{"amount": "100.00", "currency": "BRL"}')
HTTP_CODE=$(echo "$RESPONSE" | tail -1)
BODY=$(echo "$RESPONSE" | head -n -1)
if [ "$HTTP_CODE" -ne 429 ] && [ "$HTTP_CODE" -lt 500 ]; then
echo "$BODY"
exit 0
fi
echo "Attempt $i failed (HTTP $HTTP_CODE). Retrying in ${RETRY_DELAY}s..."
sleep $RETRY_DELAY
RETRY_DELAY=$((RETRY_DELAY * 2))
done
echo "All retries exhausted"
exit 1
import os
import time
import random
import requests
def request_with_backoff(method, url, max_retries=3, **kwargs):
headers = {
"Authorization": f"Bearer {os.environ['A55_ACCESS_TOKEN']}",
**kwargs.pop("headers", {}),
}
for attempt in range(max_retries + 1):
try:
response = requests.request(method, url, headers=headers, **kwargs)
remaining = response.headers.get("X-RateLimit-Remaining")
if remaining and int(remaining) < 10:
print(f"Warning: {remaining} requests remaining in window")
if response.status_code == 429:
retry_after = int(response.headers.get("Retry-After", 2 ** attempt))
jitter = random.uniform(0, 1)
time.sleep(retry_after + jitter)
continue
if response.status_code >= 500:
delay = (2 ** attempt) + random.uniform(0, 1)
time.sleep(delay)
continue
return response
except requests.ConnectionError:
if attempt == max_retries:
raise
time.sleep(2 ** attempt)
raise Exception(f"Request failed after {max_retries} retries")
async function requestWithBackoff(method, url, options = {}, maxRetries = 3) {
const headers = {
Authorization: `Bearer ${process.env.A55_ACCESS_TOKEN}`,
"Content-Type": "application/json",
...options.headers,
};
for (let attempt = 0; attempt <= maxRetries; attempt++) {
try {
const res = await fetch(url, { method, headers, ...options });
const remaining = res.headers.get("X-RateLimit-Remaining");
if (remaining && parseInt(remaining) < 10) {
console.warn(`Warning: ${remaining} requests remaining in window`);
}
if (res.status === 429) {
const retryAfter = parseInt(res.headers.get("Retry-After") || 2 ** attempt);
const jitter = Math.random();
await new Promise(r => setTimeout(r, (retryAfter + jitter) * 1000));
continue;
}
if (res.status >= 500) {
const delay = (2 ** attempt + Math.random()) * 1000;
await new Promise(r => setTimeout(r, delay));
continue;
}
return res;
} catch (err) {
if (attempt === maxRetries) throw err;
await new Promise(r => setTimeout(r, 2 ** attempt * 1000));
}
}
throw new Error(`Request failed after ${maxRetries} retries`);
}
Boas Práticas
- Leia os headers de rate limit — Monitore
X-RateLimit-Remaininge desacelere antes de chegar a zero - Nunca retente erros 4xx (exceto
429) — Erros do cliente indicam um bug na sua requisição, não uma falha transitória - Adicione jitter ao backoff — Evita o efeito de manada quando múltiplos clientes retentam simultaneamente
- Use uma fila de requisições — Suavize picos de tráfego enfileirando requisições e drenando a uma taxa controlada
- Use cache quando possível — Faça cache de respostas GET (detalhes do wallet, status da cobrança) para reduzir o volume de requisições
- Agrupe operações — Se você precisa criar muitas cobranças, distribua-as ao longo da janela em vez de enviar todas de uma vez