# Rate limits and cache

## Rate limit

**120 requests / 60 seconds / key** (`kid`). Over the limit:

```json
{ "error": { "code": "rate_limited", "message": "…" } }
```

Status `429`. MCP calls count against the same budget (they hit the API over a service binding).

`/health` and `/openapi.json` are not rate-limited.

## Point-lookup cache

These GETs are cached at the Worker **after** auth. The cache key is the URL only (24h).

- `GET /v1/isbn/:isbn`
- `GET /v1/books/:id`
- `GET /v1/works/:id`
- `GET /v1/authors/:id`

Response header: `X-Cache: HIT` or `MISS`.

Hot ISBN lookups should land well under 200ms on a hit. Misses pay Hyperdrive + join.

Search, match, recommend, author search, and changes are short-TTL and hit Postgres.

## Metering

Authenticated `/v1` calls are written to `usage_events` asynchronously. Do not expect a usage field on the response.

## See also

- [Errors](/docs/errors)
- [Known gaps](/docs/gaps)
