Radar DOU
Voltar para API e Desenvolvedores
API e Desenvolvedores

Rate limits e quotas

5 min de leitura

A API do Radar DOU implementa rate limits para garantir a estabilidade do servico e uso justo entre todos os usuarios. Este guia explica os limites de cada plano e como otimizar suas requisicoes.

O que sao Rate Limits?

Rate limits sao restricoes no numero de requisicoes que voce pode fazer em um determinado periodo de tempo. Esses limites protegem a infraestrutura e garantem que todos os usuarios tenham acesso justo ao servico.

  • Requisicoes por minuto (RPM): Numero maximo de requisicoes em uma janela de 60 segundos
  • Requisicoes por dia (RPD): Limite diario total de requisicoes
  • Quota mensal: Total de requisicoes permitidas no ciclo de faturamento

Limites por Plano

PlanoRPMRPDQuota MensalItens/Pagina
Free101001.00020
Starter301.00010.00050
Professional605.00050.000100
Enterprise12020.000200.000100
CustomSob consultaSob consultaSob consulta100

Headers de Rate Limit

Todas as respostas da API incluem headers que informam o status atual dos seus limites:

HeaderDescricaoExemplo
X-RateLimit-LimitLimite total de requisicoes por minuto60
X-RateLimit-RemainingRequisicoes restantes na janela atual45
X-RateLimit-ResetTimestamp Unix quando o limite reseta1706284800
X-DailyLimit-RemainingRequisicoes restantes no dia4500
X-MonthlyQuota-RemainingRequisicoes restantes no mes48500

Erro 429 - Too Many Requests

Quando voce excede o limite de requisicoes, a API retorna o status 429:

HTTP/1.1 429 Too Many Requests
Content-Type: application/json
Retry-After: 30
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1706284830

{
  "sucesso": false,
  "erro": {
    "codigo": "RATE_LIMIT_EXCEEDED",
    "mensagem": "Limite de requisicoes excedido. Tente novamente em 30 segundos.",
    "retry_after": 30,
    "tipo_limite": "rpm"
  }
}

Importante: O header Retry-After indica quantos segundos voce deve aguardar antes de fazer uma nova requisicao.

Implementando Rate Limiting no Cliente

Python - Retry com Backoff Exponencial

import time
import requests

class RateLimitHandler:
    def __init__(self, api_key):
        self.api_key = api_key
        self.base_url = 'https://radardou.com.br/api/v1'

    def request(self, endpoint, params=None, max_retries=3):
        headers = {'X-API-Key': self.api_key}

        for attempt in range(max_retries):
            response = requests.get(
                f'{self.base_url}{endpoint}',
                headers=headers,
                params=params
            )

            # Verificar rate limit restante
            remaining = int(response.headers.get('X-RateLimit-Remaining', 0))
            if remaining < 5:
                print(f"Aviso: Apenas {remaining} requisicoes restantes")

            if response.status_code == 429:
                retry_after = int(response.headers.get('Retry-After', 60))
                wait_time = retry_after * (2 ** attempt)  # Backoff exponencial
                print(f"Rate limit excedido. Aguardando {wait_time}s...")
                time.sleep(wait_time)
                continue

            response.raise_for_status()
            return response.json()

        raise Exception("Max retries exceeded")

# Uso
handler = RateLimitHandler(api_key='sua_api_key')
resultado = handler.request('/buscar', {'termo': 'licitacao'})

JavaScript - Rate Limiter com Fila

class RateLimiter {
  constructor(requestsPerMinute) {
    this.requestsPerMinute = requestsPerMinute;
    this.queue = [];
    this.requestTimes = [];
  }

  async throttle() {
    const now = Date.now();
    // Remover requisicoes antigas (mais de 1 minuto)
    this.requestTimes = this.requestTimes.filter(
      time => now - time < 60000
    );

    if (this.requestTimes.length >= this.requestsPerMinute) {
      const oldestRequest = this.requestTimes[0];
      const waitTime = 60000 - (now - oldestRequest);
      console.log(`Rate limit proximo. Aguardando ${waitTime}ms...`);
      await new Promise(resolve => setTimeout(resolve, waitTime));
    }

    this.requestTimes.push(Date.now());
  }
}

// Uso
const limiter = new RateLimiter(60); // 60 req/min

async function buscarComLimite(termo) {
  await limiter.throttle();

  const response = await fetch(
    `https://radardou.com.br/api/v1/buscar?termo=${termo}`,
    { headers: { 'X-API-Key': API_KEY } }
  );

  return response.json();
}

Otimizacao de Requisicoes

Estrategias para Otimizar o Uso

  • Use paginacao eficiente: Solicite o maximo de itens por pagina (ate 100) para reduzir o numero de requisicoes
  • Implemente cache: Armazene resultados localmente para evitar buscas repetidas
  • Filtre na API: Use parametros de filtro ao inves de filtrar apos receber os dados
  • Busque em lote: Agrupe buscas relacionadas em menos requisicoes
  • Monitore uso: Acompanhe os headers de rate limit para ajustar o ritmo

Implementando Cache Local

import json
import hashlib
from datetime import datetime, timedelta
from pathlib import Path

class CacheManager:
    def __init__(self, cache_dir='.cache', ttl_minutes=30):
        self.cache_dir = Path(cache_dir)
        self.cache_dir.mkdir(exist_ok=True)
        self.ttl = timedelta(minutes=ttl_minutes)

    def _get_cache_key(self, endpoint, params):
        """Gera uma chave unica para a requisicao."""
        data = json.dumps({'endpoint': endpoint, 'params': params}, sort_keys=True)
        return hashlib.md5(data.encode()).hexdigest()

    def get(self, endpoint, params):
        """Recupera dados do cache se validos."""
        key = self._get_cache_key(endpoint, params)
        cache_file = self.cache_dir / f'{key}.json'

        if cache_file.exists():
            with open(cache_file, 'r') as f:
                cached = json.load(f)

            cached_time = datetime.fromisoformat(cached['timestamp'])
            if datetime.now() - cached_time < self.ttl:
                print("Cache hit!")
                return cached['data']

        return None

    def set(self, endpoint, params, data):
        """Armazena dados no cache."""
        key = self._get_cache_key(endpoint, params)
        cache_file = self.cache_dir / f'{key}.json'

        with open(cache_file, 'w') as f:
            json.dump({
                'timestamp': datetime.now().isoformat(),
                'data': data
            }, f)

# Uso com a API
cache = CacheManager(ttl_minutes=15)

def buscar_com_cache(termo, **params):
    # Tentar cache primeiro
    cached = cache.get('/buscar', {'termo': termo, **params})
    if cached:
        return cached

    # Buscar da API
    resultado = radar.buscar(termo=termo, **params)

    # Salvar no cache
    cache.set('/buscar', {'termo': termo, **params}, resultado)

    return resultado

Monitoramento de Uso

Acompanhe seu consumo de API no dashboard ou atraves dos headers:

def monitorar_uso(response):
    """Exibe informacoes de uso apos cada requisicao."""
    headers = response.headers

    print("=== Status de Uso ===")
    print(f"RPM: {headers.get('X-RateLimit-Remaining')}/{headers.get('X-RateLimit-Limit')}")
    print(f"Diario restante: {headers.get('X-DailyLimit-Remaining')}")
    print(f"Mensal restante: {headers.get('X-MonthlyQuota-Remaining')}")

    # Alertas
    rpm_restante = int(headers.get('X-RateLimit-Remaining', 0))
    if rpm_restante < 10:
        print("ALERTA: Poucas requisicoes RPM restantes!")

    diario_restante = int(headers.get('X-DailyLimit-Remaining', 0))
    if diario_restante < 100:
        print("ALERTA: Proximo do limite diario!")

Quando Fazer Upgrade

Considere fazer upgrade do seu plano quando:

  • Voce frequentemente atinge os limites de RPM durante o dia
  • Sua quota mensal e consumida antes do fim do ciclo
  • Precisa de mais itens por pagina para otimizar buscas
  • Seu caso de uso requer processamento em lote intensivo

Dica: O dashboard do Radar DOU mostra graficos de uso historico e projecoes, ajudando voce a identificar o momento ideal para upgrade.

Perguntas Frequentes

O que acontece se eu exceder o limite mensal?

Suas requisicoes serao bloqueadas ate o proximo ciclo de faturamento. Voce pode fazer upgrade a qualquer momento para aumentar sua quota.

Os limites sao por API Key ou por conta?

Os limites sao compartilhados por conta. Todas as API Keys da mesma conta utilizam a mesma quota.

Requisicoes com erro contam no limite?

Requisicoes que retornam erro 4xx ou 5xx nao sao contabilizadas na sua quota mensal, mas ainda contam para o rate limit por minuto.

Precisa de limites customizados? Entre em contato com nossa equipe comercial para discutir um plano Enterprise com limites personalizados para sua necessidade.

Ainda tem dúvidas?

Converse com nosso assistente virtual especializado para obter ajuda personalizada sobre qualquer funcionalidade.

Abrir Assistente