Rate Limits & Versionamento
Limite global
A public-api impõe um teto global de:
200 requisições por minuto, por chave de autenticaçãoAplicado via ThrottlerModule.forRoot([{ ttl: 60000, limit: 200 }]) no backend, com janela rolante de 60 segundos. O contador é por accessToken (ou x-api-key legado) — não por IP de origem, e não por endpoint.
Headers de resposta
Toda resposta da public-api inclui os headers de throttle padrão:
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 187
X-RateLimit-Reset: 1716475860| Header | Significado |
|---|---|
X-RateLimit-Limit | Teto da janela atual (200). |
X-RateLimit-Remaining | Quantas requisições ainda cabem antes de bater o teto. |
X-RateLimit-Reset | Unix timestamp (segundos) em que o contador reseta. |
Quando você bate o teto, recebe 429 Too Many Requests:
HTTP/1.1 429 Too Many Requests
Retry-After: 23
X-RateLimit-Limit: 200
X-RateLimit-Remaining: 0
X-RateLimit-Reset: 1716475883
Content-Type: application/json
{ "statusCode": 429, "message": "Too Many Requests" }Use Retry-After (em segundos) para agendar a próxima tentativa. Implemente backoff exponencial se receber 429 repetido — geralmente sinaliza que sua App está em loop hot.
Limites por endpoint (planejado)
Hoje não há @Throttle() per-endpoint. A política planejada para o launch público (sem ETA confirmada, gap aberto em public-api-v1.md) é:
| Endpoint | Limite proposto |
|---|---|
GET /public/v1/orders | 60 req/min (paginated reads) |
GET /public/v1/menu/items | 60 req/min |
GET /public/v1/reservations | 60 req/min |
POST /public/v1/reservations | 10 req/min (writes; abuso-prone) |
Quando esses limites forem ativados, eles vão aparecer no X-RateLimit-* header e em 429. Construa sua App assumindo os limites futuros desde já — não há benefício em otimizar para o teto global temporário.
Versionamento de API
O path prefixo /public/v1 é o contrato estável de v1. Mudanças incompatíveis (breaking) viram /public/v2. Adições retrocompatíveis (novos campos, novos endpoints) acontecem na v1 sem aviso.
Política de deprecação
Quando um endpoint v1 for deprecado em favor de v2:
- Aviso público no changelog em
docs/api/changelog.md(em construção) com 90 dias de antecedência. - O endpoint deprecado passa a retornar o header:
Sunset: Wed, 23 Aug 2026 00:00:00 GMT
Deprecation: true
Link: </public/v2/orders>; rel="successor-version"- Após a data em
Sunset:, o endpoint retorna410 Gone.
Recomendação: monitore esses headers em sua telemetria. Se sua App vir
Deprecation: true, abra task de migração imediatamente.
Boas práticas para evitar bater no teto
- Cache agressivamente leituras que mudam pouco (
menu/items). TTL recomendado: 60 segundos para uso ativo, 5 minutos para uso passivo (relatório noturno). - Use webhooks em vez de polling. Se sua App polla
GET /ordersa cada 30s, troque por subscribe emorder.created+order.statusChanged— uma única request a cada evento real. - Batch quando possível. Endpoints futuros que aceitarem múltiplos IDs em query (em roadmap) reduzem chamadas drasticamente comparado a fetch-por-ID em loop.
- Backoff em 429: ao receber 429, espere
Retry-Aftersegundos. Em sequência de 429s, dobre o tempo a cada tentativa (jitter ±20% para evitar thundering herd).
CORS e clientes browser
CORS na public-api hoje está restrito a FRONTEND_URL (o frontend do PopinaFlow). Apps server-to-server funcionam normalmente — sem browser, sem CORS.
Apps single-page baseadas em browser não são suportadas em v1. Construa o backend da sua App e proxy as chamadas server-side.
Reportar abuso ou bug de rate limit
Se você suspeita que está sendo throttled incorretamente (ex: tenant alheio consumindo seu teto), abra ticket de suporte com:
installationId(visível no painel)- Window de timestamps onde ocorreu
- Sample de
X-RateLimit-Remainingobservado
Investigação fica no SLA de 2 dias úteis.