# Rate limit

A API aplica um limite de requisições por janela de tempo para proteger o serviço contra abuso e garantir disponibilidade. Quando o limite é atingido, novas requisições recebem `HTTP 429 Too Many Requests` até a janela ser liberada.

## Limite padrão

- **60 requisições por 60 segundos** por origem.
- Janela deslizante (sliding window): cada requisição é registrada com o seu instante e expira após 60s.
- Endpoints específicos podem ter limites próprios — consulte a referência do endpoint.

## Como a origem é identificada

A chave de limitação é resolvida automaticamente, do mais específico para o mais genérico:

1. **Empresa** (`audience: "empresa"`) — quando há `Token` válido no header e ele resolve para uma empresa cadastrada. **É o cenário recomendado** — o limite é aplicado por empresa, independentemente do IP de origem.
2. **Token** (`audience: "token"`) — quando há `Token` no header mas ele não resolve para uma empresa (token inválido/desconhecido). O bucket usa um hash do token.
3. **Usuário** (`audience: "user"`) — quando a requisição está autenticada por sessão (painel web), sem `Token`.
4. **IP** (`audience: "ip"`) — fallback quando não há nenhuma das opções acima.

Sempre envie o header `Token` para garantir que o limite seja contabilizado por empresa, e não pelo IP de saída do seu servidor (que pode ser compartilhado).

## Headers de resposta

Toda resposta da API inclui os headers de telemetria do limite:

| Header | Descrição |
| --- | --- |
| `X-RateLimit-Limit` | Limite máximo da janela atual. |
| `X-RateLimit-Remaining` | Quantas requisições ainda podem ser feitas antes do limite. |
| `X-RateLimit-Reset` | Timestamp Unix (em segundos, UTC) em que a janela será totalmente liberada. |
| `Retry-After` | **Apenas em 429.** Segundos a aguardar antes de tentar novamente. |

## Resposta quando o limite é excedido

Status: `429 Too Many Requests`

```json
{
  "error": "rate_limited",
  "message": "Limite de 60 requisições por 60s atingido para esta empresa. Tente novamente em 12s.",
  "scope": "Fiscal",
  "audience": "empresa",
  "limit": 60,
  "retryAfterSeconds": 12,
  "resetAt": "2026-04-28T14:32:18Z"
}
```

Headers acompanhando o 429:

```http
HTTP/1.1 429 Too Many Requests
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1761661938
Retry-After: 12
Content-Type: application/json; charset=utf-8
```

## Como tratar o 429 no seu cliente

A regra de ouro: **sempre respeite o `Retry-After`**. Não tente reenviar imediatamente — você só vai prolongar o bloqueio.

Estratégia recomendada:

1. Ao receber `429`, leia o header `Retry-After` (em segundos).
2. Aguarde esse tempo antes da próxima requisição àquele recurso.
3. Para requisições em lote, considere espaçar emissões (ex.: ao emitir 1000 NF-e, distribua ao longo do minuto em vez de disparar tudo de uma vez).
4. Implemente **backoff exponencial com jitter** caso o `Retry-After` esteja ausente: 1s, 2s, 4s, 8s… com até ±20% de variação aleatória.

### Exemplo (C#)

```csharp
async Task<HttpResponseMessage> EnviarComRetryAsync(HttpClient client, HttpRequestMessage req)
{
    for (int tentativa = 0; tentativa < 3; tentativa++)
    {
        var resp = await client.SendAsync(req);
        if ((int)resp.StatusCode != 429) return resp;

        var retryAfter = resp.Headers.RetryAfter?.Delta ?? TimeSpan.FromSeconds(5);
        await Task.Delay(retryAfter);
    }
    throw new InvalidOperationException("Rate limit não liberado após 3 tentativas.");
}
```

### Exemplo (Node.js)

```js
async function enviarComRetry(url, options, maxTentativas = 3) {
  for (let i = 0; i < maxTentativas; i++) {
    const resp = await fetch(url, options);
    if (resp.status !== 429) return resp;

    const retryAfter = Number(resp.headers.get("retry-after") ?? 5);
    await new Promise((r) => setTimeout(r, retryAfter * 1000));
  }
  throw new Error("Rate limit não liberado após múltiplas tentativas.");
}
```

## Boas práticas

- **Monitore `X-RateLimit-Remaining`** em respostas de sucesso. Se esse valor estiver consistentemente baixo, distribua melhor a carga.
- **Não use múltiplos tokens** para contornar o limite — todos os tokens da mesma empresa caem no mesmo bucket (`audience: "empresa"`).
- **Cache local de consultas** (ex.: `Status`, `ConsultarNFe`) reduz chamadas redundantes.
- **Webhooks ao invés de polling**: configure [webhooks](/webhooks) para receber atualizações ao invés de consultar a API repetidamente.

## Precisa de um limite maior?

Empresas com volume alto podem solicitar um aumento de limite. Entre em contato pelo [suporte](/support) informando:

- Token ou CNPJ da empresa.
- Volume médio e de pico esperado (req/min).
- Tipo de operação (emissão, consulta, eventos, etc.).
