Rate Limits e Throttling
O Tarefa AI implementa rate limiting para proteger a infraestrutura e garantir qualidade de serviço para todos os usuários. Este guia explica os limites, como monitorá-los e como lidar com erros de rate limit.
Visão Geral
Por que Rate Limiting?
- Proteção contra abuso: Previne uso excessivo (intencional ou não)
- Estabilidade: Garante que a API permaneça responsiva para todos
- Custos: Controla uso de recursos computacionais e APIs de terceiros (OpenRouter, etc)
- Segurança: Mitiga ataques de força bruta e DDoS
Tipos de Limites
- Rate Limits: Requisições por unidade de tempo
- Quotas: Limites totais por período (diário/mensal)
- Concurrent Limits: Execuções simultâneas máximas
Rate Limits por Endpoint
Autenticação
| Endpoint | Limite | Janela | Escopo |
|---|---|---|---|
POST /api/auth/login | 5 tentativas | 15 min | IP + Email |
POST /api/auth/register | 3 cadastros | 1 hora | IP |
POST /api/auth/forgot-password | 3 requests | 1 hora | IP + Email |
POST /api/auth/reset-password | 5 tentativas | 1 hora | IP + Token |
GET /api/auth/session | 60 requests | 1 min | Usuário |
Motivo: Endpoints sensíveis têm limites agressivos para prevenir ataques.
Tarefas
| Endpoint | Limite | Janela | Escopo |
|---|---|---|---|
POST /api/agent/create-task | 10 criações | 1 min | Usuário |
GET /api/tasks | 100 requests | 1 min | Usuário |
GET /api/tasks/{id} | 120 requests | 1 min | Usuário |
PATCH /api/tasks/{id} | 20 updates | 1 min | Usuário |
DELETE /api/tasks/{id} | 10 deletes | 1 min | Usuário |
Execuções
| Endpoint | Limite | Janela | Escopo |
|---|---|---|---|
POST /api/agent/process | 30 requests | 1 min | Usuário |
POST /api/tasks/{id}/execute | 20 execuções | 1 min | Usuário |
GET /api/executions | 100 requests | 1 min | Usuário |
GET /api/executions/{id} | 150 requests | 1 min | Usuário |
Upload
| Endpoint | Limite | Janela | Escopo |
|---|---|---|---|
POST /api/upload | 10 uploads | 1 min | Usuário |
DELETE /api/upload | 20 deletes | 1 min | Usuário |
Limite adicional: Máximo 100MB de storage por usuário.
Integrações
| Endpoint | Limite | Janela | Escopo |
|---|---|---|---|
POST /api/integrations/*/validate | 5 validações | 1 min | Usuário |
POST /api/coupons/activate | 5 ativações | 1 hora | Usuário |
Admin
| Endpoint | Limite | Janela | Escopo |
|---|---|---|---|
GET /api/admin/stats | 60 requests | 1 min | Admin |
GET /api/admin/users | 100 requests | 1 min | Admin |
POST /api/admin/coupons | 20 criações | 1 min | Admin |
PATCH /api/admin/users/* | 30 updates | 1 min | Admin |
Webhooks
| Endpoint | Limite | Janela | Escopo |
|---|---|---|---|
POST /api/webhooks | 5 criações | 1 min | Usuário |
POST /api/webhooks/*/test | 10 testes | 1 min | Usuário |
| Entregas de webhook | 100 requests | 1 min | Webhook |
Quotas Diárias e Mensais
Plano Free (Trial)
| Recurso | Limite Diário | Limite Mensal |
|---|---|---|
| Execuções de tarefas | 50 | 500 |
| Tokens de IA (input+output) | 100.000 | 1.000.000 |
| Tarefas ativas | 10 | - |
| Webhooks | 3 | - |
| Upload storage | - | 100MB |
Plano Pro (Exemplo)
| Recurso | Limite Diário | Limite Mensal |
|---|---|---|
| Execuções de tarefas | 500 | 10.000 |
| Tokens de IA (input+output) | 1.000.000 | 20.000.000 |
| Tarefas ativas | 100 | - |
| Webhooks | 20 | - |
| Upload storage | - | 10GB |
Limites de Concorrência
Por Usuário
- Execuções simultâneas: 5 tarefas rodando ao mesmo tempo
- Uploads simultâneos: 3 arquivos ao mesmo tempo
- Sessões ativas: 10 dispositivos/tokens
Global
- Execuções totais simultâneas: 1000 (sistema completo)
- Webhooks simultâneos: 500 entregas paralelas
Headers de Rate Limit
Todos os responses incluem headers informativos:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 85
X-RateLimit-Reset: 1674820800000
X-RateLimit-Window: 60
X-RateLimit-Policy: userHeaders Detalhados
| Header | Descrição | Exemplo |
|---|---|---|
X-RateLimit-Limit | Limite máximo de requests na janela | 100 |
X-RateLimit-Remaining | Requests restantes na janela atual | 85 |
X-RateLimit-Reset | Timestamp (ms) quando o limite reseta | 1674820800000 |
X-RateLimit-Window | Duração da janela em segundos | 60 |
X-RateLimit-Policy | Política aplicada (user, ip, endpoint) | user |
Exemplo de Response
curl -I https://api.tarefaai.com/api/tasks \
-H "Authorization: Bearer {token}"Response:
HTTP/1.1 200 OK
Content-Type: application/json
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 85
X-RateLimit-Reset: 1674820800000
X-RateLimit-Window: 60
X-RateLimit-Policy: userErro de Rate Limit
Response (429 Too Many Requests)
{
"success": false,
"error": "Rate limit exceeded",
"message": "Too many requests. Please try again in 45 seconds.",
"details": {
"limit": 100,
"remaining": 0,
"reset": 1674820800000,
"resetIn": 45,
"retryAfter": 45
}
}Headers de Erro
HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 45
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1674820800000Estratégias de Tratamento
1. Backoff Exponencial
async function fetchWithRetry(url: string, options: RequestInit, maxRetries = 3) {
for (let i = 0; i < maxRetries; i++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
// Ler Retry-After do header
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
// Exponential backoff: 1s, 2s, 4s, 8s...
const delay = Math.min(retryAfter * 1000, Math.pow(2, i) * 1000);
console.log(`Rate limited. Retrying in ${delay}ms...`);
await new Promise(resolve => setTimeout(resolve, delay));
}
throw new Error('Max retries exceeded');
}
// Uso
try {
const response = await fetchWithRetry('https://api.tarefaai.com/api/tasks', {
headers: { Authorization: `Bearer ${token}` }
});
const data = await response.json();
} catch (error) {
console.error('Failed after retries:', error);
}2. Cliente com Rate Limit Awareness
class TarefaAIClient {
private remaining: number = 100;
private resetAt: number = Date.now() + 60000;
async request(endpoint: string, options: RequestInit) {
// Aguardar reset se necessário
if (this.remaining <= 0) {
const waitTime = this.resetAt - Date.now();
if (waitTime > 0) {
console.log(`Waiting ${waitTime}ms for rate limit reset...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
}
}
const response = await fetch(endpoint, options);
// Atualizar contadores
this.remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
this.resetAt = parseInt(response.headers.get('X-RateLimit-Reset') || '0');
if (response.status === 429) {
const retryAfter = parseInt(response.headers.get('Retry-After') || '60');
await new Promise(resolve => setTimeout(resolve, retryAfter * 1000));
return this.request(endpoint, options); // Retry
}
return response;
}
}
// Uso
const client = new TarefaAIClient();
const response = await client.request('https://api.tarefaai.com/api/tasks', {
headers: { Authorization: `Bearer ${token}` }
});3. Queue de Requisições
class RateLimitedQueue {
private queue: Array<() => Promise<any>> = [];
private processing = false;
private requestsPerMinute = 100;
private delay = 60000 / this.requestsPerMinute; // ~600ms entre requests
async enqueue<T>(fn: () => Promise<T>): Promise<T> {
return new Promise((resolve, reject) => {
this.queue.push(async () => {
try {
const result = await fn();
resolve(result);
} catch (error) {
reject(error);
}
});
this.process();
});
}
private async process() {
if (this.processing || this.queue.length === 0) return;
this.processing = true;
while (this.queue.length > 0) {
const task = this.queue.shift()!;
await task();
await new Promise(resolve => setTimeout(resolve, this.delay));
}
this.processing = false;
}
}
// Uso
const queue = new RateLimitedQueue();
for (let i = 0; i < 200; i++) {
queue.enqueue(async () => {
const response = await fetch('https://api.tarefaai.com/api/tasks');
return response.json();
});
}Monitoramento de Uso
Dashboard de Quotas
Acesse Configurações > Uso & Quotas para ver:
- Requisições por endpoint (últimas 24h)
- Tokens de IA consumidos
- Storage utilizado
- Progresso em relação aos limites
- Histórico de rate limits atingidos
API de Usage
curl -X GET https://api.tarefaai.com/api/usage \
-H "Authorization: Bearer {token}"Response:
{
"success": true,
"usage": {
"period": "2025-01-17",
"executions": {
"used": 35,
"limit": 50,
"remaining": 15,
"percentage": 70.0
},
"tokens": {
"used": 45000,
"limit": 100000,
"remaining": 55000,
"percentage": 45.0
},
"storage": {
"usedBytes": 25000000,
"limitBytes": 104857600,
"usedMB": 23.8,
"limitMB": 100,
"percentage": 23.8
},
"rateLimits": {
"hitToday": 3,
"endpoints": [
{
"endpoint": "/api/agent/process",
"hits": 2,
"lastHit": "2025-01-17T14:30:00.000Z"
}
]
}
}
}Alertas de Quota
Configure alertas quando atingir % do limite:
curl -X POST https://api.tarefaai.com/api/usage/alerts \
-H "Authorization: Bearer {token}" \
-H "Content-Type: application/json" \
-d '{
"threshold": 80,
"notifyEmail": true,
"notifyWebhook": true
}'Quando atingir 80%:
- Email enviado
- Webhook disparado (se configurado)
- Notificação no dashboard
Exceções e Allowlist
Requisições Isentas
Alguns endpoints não contam para rate limits:
GET /api/health- Health checkGET /api/docs/*- DocumentaçãoGET /- Landing page- Assets estáticos (
/images/*,/styles/*)
Requisitar Aumento de Limite
Para planos personalizados ou necessidades especiais:
- Acesse Configurações > Planos
- Clique em Solicitar Plano Enterprise
- Preencha formulário com suas necessidades
- Nosso time responde em até 24h
Ou via email: enterprise@tarefaai.com
Best Practices
1. Implemente Caching
// ✅ BOM: Cache de dados que não mudam frequentemente
const cache = new Map<string, { data: any; expiresAt: number }>();
async function getTasks() {
const cached = cache.get('tasks');
if (cached && cached.expiresAt > Date.now()) {
return cached.data;
}
const response = await fetch('https://api.tarefaai.com/api/tasks');
const data = await response.json();
cache.set('tasks', {
data,
expiresAt: Date.now() + 60000 // Cache 1 min
});
return data;
}2. Use Webhooks ao invés de Polling
// ❌ RUIM: Polling constante
setInterval(async () => {
const executions = await fetch('/api/executions');
// Consome rate limit desnecessariamente
}, 5000);
// ✅ BOM: Configure webhook
// Você recebe notificação quando algo muda
app.post('/webhook', (req, res) => {
const { event, data } = req.body;
if (event === 'task.completed') {
handleTaskCompleted(data);
}
res.status(200).send('OK');
});3. Batch Operations
// ❌ RUIM: Múltiplas requisições individuais
for (const task of tasks) {
await fetch(`/api/tasks/${task.id}`); // 100 requests
}
// ✅ BOM: Uma requisição batch
const response = await fetch('/api/tasks', {
method: 'POST',
body: JSON.stringify({ ids: tasks.map(t => t.id) })
});4. Monitore Headers
// ✅ BOM: Sempre verifique headers
const response = await fetch('https://api.tarefaai.com/api/tasks');
const remaining = parseInt(response.headers.get('X-RateLimit-Remaining') || '0');
const limit = parseInt(response.headers.get('X-RateLimit-Limit') || '100');
if (remaining < limit * 0.1) {
console.warn(`Rate limit baixo: ${remaining}/${limit}`);
// Reduzir velocidade de requisições
}5. Graceful Degradation
// ✅ BOM: Falhe graciosamente
async function fetchData() {
try {
const response = await fetch('https://api.tarefaai.com/api/tasks');
if (response.status === 429) {
// Usar cache antigo ou dados estáticos
return getCachedData();
}
return await response.json();
} catch (error) {
// Fallback para dados locais
return getLocalFallbackData();
}
}Códigos de Erro Relacionados
| Código | Descrição | Ação |
|---|---|---|
| 429 | Rate limit excedido | Aguardar Retry-After |
| 402 | Quota excedida (upgrade) | Fazer upgrade do plano |
| 503 | Sistema sobrecarregado | Retry com backoff exponencial |
Ferramentas de Debug
Visualizar Rate Limits
# Ver limites atuais
curl -I https://api.tarefaai.com/api/tasks \
-H "Authorization: Bearer {token}" | grep -i ratelimitOutput:
X-RateLimit-Limit: 100
X-RateLimit-Remaining: 85
X-RateLimit-Reset: 1674820800000
Simular Rate Limit (Dev)
Para testar como sua aplicação lida com rate limits:
# Fazer muitas requisições rápidas
for i in {1..150}; do
curl https://api.tarefaai.com/api/tasks \
-H "Authorization: Bearer {token}" &
done
waitPróximos Passos
Documentação de Rate Limiting: As políticas podem mudar. Sempre consulte os headers dos responses para informações atualizadas.
Referência: Implementação em /src/middleware/rate-limit.ts