Rate Limits
Entenda os limites de requisição e estratégias para uso eficiente da API.
Visão Geral
Esta página registra as cotas das APIs descritas abaixo, aplicadas pelo Rack::Attack em produção. Os valores exibidos são os padrões definidos no código e podem ser alterados pelo operador nas variáveis indicadas. Quando mais de uma regra corresponde à requisição, vale a primeira cota atingida. Ao exceder uma cota, a API retorna 429 Too Many Requests.
A coluna Configuração distingue regras fixas das configuráveis e informa o padrão usado pelo código. Este inventário garante somente as regras implementadas no backend atual; cotas apenas planejadas ou descritas fora dele não fazem parte do contrato.
Em desenvolvimento e teste, esse middleware fica desabilitado. Portanto, valide limites no ambiente de produção ou em um ambiente iniciado explicitamente como produção, sem usar uma carga que afete usuários reais.
Resposta 429
O contrato atual não adiciona headers X-RateLimit-Limit, X-RateLimit-Remaining ou X-RateLimit-Reset. A opção do Rack::Attack que adicionaria Retry-After também está desabilitada. Não dependa desses headers para controlar retentativas.
HTTP/1.1 429 Too Many Requests
Content-Type: text/plain
Retry laterGlobal e Autenticação
Além das regras específicas, toda requisição conta para o limite global por IP. Não existe uma cota geral por token, inbox ou app. Login com MFA não consome as regras de login comum: usa as duas regras MFA, por IP e por token.
| Regra | Método / rota | Limite | Janela | Chave | Configuração |
|---|---|---|---|---|---|
| req/ip | Qualquer rota, exceto safelists | 3.000 | 1 minuto | IP | RACK_ATTACK_LIMIT (padrão 3000) |
| super_admin_login/ip | POST /super_admin/sign_in | 5 | 5 minutos | IP | Fixo |
| super_admin_login/email | POST /super_admin/sign_in | 5 | 15 minutos | Email normalizado | Fixo |
| login/ip | POST /auth/sign_in sem mfa_token | 5 | 5 minutos | IP | Fixo |
| login/email | POST /auth/sign_in sem mfa_token | 10 | 15 minutos | Email normalizado | Fixo |
| reset_password/ip | POST /auth/password | 5 | 30 minutos | IP | Fixo |
| reset_password/email | POST /auth/password | 5 | 1 hora | Email normalizado | Fixo |
| resend_confirmation/ip | POST /resend_confirmation | 5 | 30 minutos | IP | Fixo |
| resend_confirmation/email | POST /resend_confirmation | 5 | 1 hora | Email normalizado | Fixo |
| resend_confirmation_auth/ip | POST /api/v1/profile/resend_confirmation | 5 | 30 minutos | IP | Fixo |
| mfa_verification/ip | DELETE /api/v1/profile/mfa; POST /api/v1/profile/mfa/verify ou /api/v1/profile/mfa/backup_codes | 5 | 1 minuto | IP | Fixo |
| mfa_login/ip | POST /auth/sign_in com mfa_token | 10 | 1 minuto | IP | Fixo |
| mfa_login/token | POST /auth/sign_in com mfa_token | 10 | 1 minuto | mfa_token | Fixo |
| accounts/ip | POST /api/v1/accounts | 5 | 30 minutos | IP | Fixo |
RACK_ATTACK_ALLOWED_IPS acrescenta IPs à safelist; localhost já é permitido. A rota /health também é isenta. Em produção, ENABLE_RACK_ATTACK=false desliga todas as regras.
Widget
Estas três regras existem somente quando ENABLE_RACK_ATTACK_WIDGET_API é true, que é o padrão. O limite global continua valendo em paralelo.
| Regra | Método / rota | Limite | Janela | Chave | Configuração |
|---|---|---|---|---|---|
| api/v1/widget/conversations | POST /api/v1/widget/conversations | 6 | 12 horas | IP | Fixo; ENABLE_RACK_ATTACK_WIDGET_API |
| api/v1/widget/contacts | PATCH ou PUT /api/v1/widget/contacts | 60 | 1 hora | IP | Fixo; ENABLE_RACK_ATTACK_WIDGET_API |
| widget?website_token={website_token}&cw_conversation={x-auth-token} | Qualquer método em /widget sem cw_conversation | 5 | 1 hora | IP | Fixo; ENABLE_RACK_ATTACK_WIDGET_API |
APIs Autenticadas
Regras por conta extraem account_id da rota. As regras por usuário de relatórios e meta usam uid quando presente e, caso contrário, api_access_token; sem um desses identificadores, a requisição não entra nessa cota por usuário, mas continua sujeita às demais regras correspondentes.
| Regra | Método / rota | Limite | Janela | Chave | Configuração |
|---|---|---|---|---|---|
| /api/v1/accounts/:account_id/conversations/:conversation_id/transcript | Qualquer método no prefixo /api/v1/accounts/{account_id}/conversations/{conversation_id}/transcript | 1.000 | 1 hora | account_id | RATE_LIMIT_CONVERSATION_TRANSCRIPT (padrão 1000) |
| /api/v1/accounts/:account_id/upload | Qualquer método no prefixo /api/v1/accounts/{account_id}/upload | 60 | 1 hora | account_id | Fixo |
| /api/v1/accounts/:account_id/contacts/search | Qualquer método no prefixo /api/v1/accounts/{account_id}/contacts/search | 100 | 1 minuto | account_id | RATE_LIMIT_CONTACT_SEARCH (padrão 100) |
| /api/v2/accounts/:account_id/reports/user | Qualquer método no prefixo /api/v2/accounts/{account_id}/reports | 100 | 1 minuto | uid ou api_access_token + account_id | RATE_LIMIT_REPORTS_API_USER_LEVEL (padrão 100) |
| /api/v2/accounts/:account_id/reports | Qualquer método no prefixo /api/v2/accounts/{account_id}/reports | 1.000 | 1 minuto | account_id | RATE_LIMIT_REPORTS_API_ACCOUNT_LEVEL (padrão 1000) |
| /api/v1/accounts/:account_id/conversations/meta/user | GET /api/v1/accounts/{account_id}/conversations/meta... | 30 | 1 minuto | uid ou api_access_token + account_id | RATE_LIMIT_CONVERSATIONS_META (padrão 30) |
| whatsapp_templates/create | POST /api/v1/accounts/{account_id}/whatsapp_templates | 10 | 1 hora | account_id | RATE_LIMIT_WHATSAPP_TEMPLATE_CREATE (padrão 10) |
| whatsapp_templates/update | PUT ou PATCH /api/v1/accounts/{account_id}/whatsapp_templates/{id} | 30 | 1 hora | account_id | RATE_LIMIT_WHATSAPP_TEMPLATE_UPDATE (padrão 30) |
| whatsapp_templates/destroy | DELETE /api/v1/accounts/{account_id}/whatsapp_templates/{id} | 30 | 1 hora | account_id | RATE_LIMIT_WHATSAPP_TEMPLATE_DESTROY (padrão 30) |
| whatsapp_templates/sync | POST /api/v1/accounts/{account_id}/whatsapp_templates/sync | 5 | 5 minutos | account_id | RATE_LIMIT_WHATSAPP_TEMPLATE_SYNC (padrão 5) |
Automações e Webhooks
As credenciais dos webhooks são convertidas em SHA-256 antes de compor a chave armazenada. O webhook de automação de pipeline aceita o token no path, query ou body JSON; sem token, essa regra específica não cria uma chave, embora o limite global por IP continue ativo.
| Regra | Método / rota | Limite | Janela | Chave | Configuração |
|---|---|---|---|---|---|
| sequence_external_start_per_account | POST /api/v1/accounts/{account_id}/pipeline/cards/{id}/sequences/external_start | 60 | 1 minuto | account_id | Fixo |
| sequence_external_start_per_user | POST /api/v1/accounts/{account_id}/pipeline/cards/{id}/sequences/external_start | 10 | 1 minuto | api_access_token | Fixo |
| sequence_hmac_trigger_per_token | POST /webhooks/sequence-trigger/{token} | 120 | 1 minuto | SHA-256 do token | Fixo |
| sequence_hmac_trigger_per_ip | POST /webhooks/sequence-trigger/{token} | 240 | 1 minuto | IP | Fixo |
| pipeline_automation_webhook_per_token | POST /api/v1/pipeline_automation_webhooks ou /api/v1/pipeline_automation_webhooks/{token} | 120 | 1 minuto | SHA-256 do token de path/query/body | Fixo |
| pipeline_bulk_delete_per_token | POST /api/v1/accounts/{account_id}/pipeline/bulk_actions/delete | 30 | 1 minuto | api_access_token | Fixo |
| pipeline_bulk_delete_per_account | POST /api/v1/accounts/{account_id}/pipeline/bulk_actions/delete | 100 | 1 minuto | account_id | Fixo |
Módulo de Atendimentos — Limites por Canal
O módulo de Atendimentos está disponível em todas as licenças. O widget anônimo depende da habilitação operacional do agendamento público na conta; as APIs autenticadas não são bloqueadas por plano nem possuem uma regra própria por token ou por conta — recebem apenas as cotas gerais ou outras regras que também correspondam à rota.
| Regra | Método / rota | Limite | Janela | Chave | Configuração |
|---|---|---|---|---|---|
| public_appointments_read/ip | GET /public/api/v1/inboxes/{inbox_identifier}/appointments/services, /professionals ou /slots | 120 | 1 minuto | IP | RATE_LIMIT_PUBLIC_APPOINTMENT_READ (padrão 120) |
| public_appointments_booking/ip | POST /public/api/v1/inboxes/{inbox_identifier}/appointments | 10 | 1 hora | IP | RATE_LIMIT_PUBLIC_APPOINTMENT_BOOKING (padrão 10) |
Tratando Erro 429
Quando receber um erro 429, use backoff exponencial para retentar a requisição:
async function fetchWithRetry(url, options, maxRetries = 3) {
for (let attempt = 0; attempt < maxRetries; attempt++) {
const response = await fetch(url, options);
if (response.status !== 429) {
return response;
}
// O backend atual não envia Retry-After; mantenha o fallback.
const retryAfter = response.headers.get("Retry-After");
const delay = retryAfter
? parseInt(retryAfter) * 1000
: Math.pow(2, attempt) * 1000;
console.log(`Rate limited. Aguardando ${delay}ms...`);
await new Promise((resolve) => setTimeout(resolve, delay));
}
throw new Error("Max retries exceeded");
}Boas Práticas
- Controle localmente a taxa de chamadas; a resposta não informa quantas requisições restam
- Use backoff exponencial com jitter aleatório para retries
- Agrupe operações somente quando o endpoint oferecer uma operação em lote
- Implemente cache local para dados que não mudam frequentemente
- Use webhooks em vez de polling para receber atualizações em tempo real
- Não presuma que o valor padrão é o valor implantado: o operador pode sobrescrever as cotas configuráveis