---
title: Rate limits
---

# Rate limits

Limits apply per `client_id` **and** per IP. The stricter of the two wins.

## Defaults

| Endpoint | Public client | Confidential client | Anonymous IP |
|---|---|---|---|
| `/oidc/authorize` | 1 000 / hour | 10 000 / hour | 200 / hour |
| `/oidc/token` | 1 000 / hour | 10 000 / hour | 200 / hour |
| `/oidc/userinfo` | 5 000 / hour | 50 000 / hour | n/a |
| `/oidc/revoke` | 100 / hour | 1 000 / hour | 50 / hour |
| `/oidc/introspect` | n/a | 50 000 / hour | n/a |
| `/oidc/onetap` (iframe) | 60 / minute / IP | 60 / minute / IP | 60 / minute / IP |
| `/oidc/iframe/check_session` | 120 / minute / IP | 120 / minute / IP | 120 / minute / IP |
| `/.well-known/*` | uncapped (cached) | uncapped (cached) | uncapped (cached) |
| `/sdk.js` | uncapped (cached) | uncapped (cached) | uncapped (cached) |

## Headers

Every response includes:

```http
X-RateLimit-Limit:     1000
X-RateLimit-Remaining: 942
X-RateLimit-Reset:     1714684800
```

When throttled, you get:

```http
HTTP/1.1 429 Too Many Requests
Retry-After: 47
X-RateLimit-Reset: 1714684847
```

with body:

```json
{ "error": "lxl_rate_limited", "error_description": "Hourly cap exceeded for /oidc/token" }
```

## Raising your limits

Apply through the [developer portal](https://app.littlexlittle.org/developers) — pick the client, **Settings → Rate limits → Request increase**. Provide:

- Expected sustained QPS.
- Endpoint(s).
- Brief justification (use case).

We approve in business hours. Burst allowance is configurable separately.

## Best practices

- **Cache `/oidc/userinfo` for the duration of the access token.** It rarely changes.
- **Honor `Retry-After`.** Implement exponential backoff with jitter; don't hammer.
- **Use webhooks instead of polling** for account state changes.
- **Reuse the discovery document** — it's cacheable.
