Portal do Desenvolvedor / Rate Limits e Boas Práticas
Portal do Desenvolvedor

Rate Limits e Boas Práticas

Para garantir a estabilidade da plataforma para todos os usuários, a API do eAgenda aplica limites de taxa (rate limits) nas requisições.

Limites de taxa

TipoLimite
Requisições por minutoVaria conforme o plano
Requisições por horaVaria conforme o plano

Os limites específicos dependem do seu plano contratado. Entre em contato com o suporte para informações sobre limites do seu plano.

Headers de resposta

A API retorna headers informativos sobre o consumo de rate limit:

X-RateLimit-Limit: 60
X-RateLimit-Remaining: 45
X-RateLimit-Reset: 1717524600
HeaderDescrição
X-RateLimit-LimitMáximo de requisições permitidas no período
X-RateLimit-RemainingRequisições restantes no período atual
X-RateLimit-ResetTimestamp Unix de quando o contador reseta

Quando o limite é atingido

Se você exceder o limite, a API retorna:

HTTP/1.1 429 Too Many Requests
Retry-After: 30
{
  "detail": "Limite de requisições excedido. Tente novamente em 30 segundos."
}

Como lidar com rate limiting

Retry com backoff exponencial

import requests
import time

def api_request(url, auth, max_retries=3):
    for attempt in range(max_retries):
        response = requests.get(url, auth=auth)

        if response.status_code == 429:
            retry_after = int(response.headers.get("Retry-After", 30))
            wait = retry_after * (2 ** attempt)  # backoff exponencial
            print(f"Rate limit atingido. Aguardando {wait}s...")
            time.sleep(wait)
            continue

        return response

    raise Exception("Limite de tentativas excedido")

JavaScript

async function apiRequest(url, headers, maxRetries = 3) {
  for (let attempt = 0; attempt < maxRetries; attempt++) {
    const response = await fetch(url, { headers });

    if (response.status === 429) {
      const retryAfter = parseInt(response.headers.get("Retry-After") || "30");
      const wait = retryAfter * Math.pow(2, attempt);
      console.log(`Rate limit atingido. Aguardando ${wait}s...`);
      await new Promise(resolve => setTimeout(resolve, wait * 1000));
      continue;
    }

    return response;
  }

  throw new Error("Limite de tentativas excedido");
}

Boas práticas para integrações

1. Minimize requisições desnecessárias

  • Use filtros — Filtre por status, start_date, calendar_key em vez de buscar tudo e filtrar localmente
  • Paginação inteligente — Use page_size adequado ao seu caso (ex: 100 resultados por página)
  • Evite polling excessivo — Use webhooks em vez de consultar a API a cada poucos segundos

2. Cache quando possível

Alguns dados mudam com pouca frequência e podem ser cacheados:

RecursoTempo de cache sugerido
Contas (/accounts/)1 hora
Agendas (/calendars/)15 minutos
Serviços (/services/)15 minutos
Tags (/tags/)30 minutos
Horários disponíveis1-2 minutos (máximo)
AgendamentosSem cache (use webhooks)

3. Trate erros adequadamente

response = requests.get(url, auth=auth)

match response.status_code:
    case 200:
        data = response.json()
    case 400:
        print(f"Dados inválidos: {response.json()}")
    case 401:
        print("Credenciais inválidas")
    case 403:
        print("Sem permissão")
    case 404:
        print("Recurso não encontrado")
    case 429:
        print("Rate limit - aguarde e tente novamente")
    case _:
        print(f"Erro inesperado: {response.status_code}")

4. Use timeouts

Sempre defina timeouts para evitar que requisições travem sua aplicação:

response = requests.get(url, auth=auth, timeout=30)
const controller = new AbortController();
setTimeout(() => controller.abort(), 30000);

const response = await fetch(url, {
  headers,
  signal: controller.signal,
});

5. Logs e monitoramento

Registre as requisições para facilitar o debugging:

  • URL e método da requisição
  • Status code da resposta
  • Tempo de resposta
  • Headers de rate limit
  • Erros e retries