# Access Matrix

> Every public route with the credential it needs, the plan that unlocks it, the rate bucket it is metered on, and the outcome per plan. Generated from the API route policy.

Generated by `pnpm --filter @philidor/api access:matrix -- --mdx` from `apps/api/src/lib/route-policy.ts`, the same table that drives the OpenAPI `security` declarations and the cache invariant. Do not hand-edit; regenerate.

## What each plan gets

| Plan        | API key tier  | Default rate limit | Capabilities                                          |
| ----------- | ------------- | -----------------: | ----------------------------------------------------- |
| Data        | `data`        |            100/min | Data API                                              |
| Decisioning | `decisioning` |            600/min | `overhang`, `risk_graph_signed_decisions`             |
| Embedded    | `embedded`    |          10000/min | `overhang`, `risk_graph_signed_decisions`, `webhooks` |

A key is issued with its plan's default rate limit unless a different limit was agreed (recorded on the key as `contracted_rpm`); `GET /v1/me` reports the effective limit.

## Routes

`ok` means the call is served; `401` means a key is required; `403` means the plan is too low. Anonymous callers are metered per address on the bucket shown; keyed callers on the key's own budget.

| Method | Path                                          | Plan        | Anonymous | Data | Decisioning | Embedded | Rate bucket (anonymous)             | Keyed                           |
| ------ | --------------------------------------------- | ----------- | --------- | ---- | ----------- | -------- | ----------------------------------- | ------------------------------- |
| GET    | `/v1/address/:address/positions`              | —           | ok        | ok   | ok          | ok       | portfolio (10/60s per IP)           | max(key rpm, 10)/min per key    |
| GET    | `/v1/assets`                                  | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/assets/:chain_id/:address`               | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/assets/:symbol/history`                  | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/assets/enriched`                         | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/assets/enriched/facets`                  | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/baskets`                                 | Data        | 403       | ok   | ok          | ok       | basketsRead (60/60s per IP)         | max(key rpm, 60)/min per key    |
| GET    | `/v1/baskets/:id`                             | Data        | 403       | ok   | ok          | ok       | basketsRead (60/60s per IP)         | max(key rpm, 60)/min per key    |
| GET    | `/v1/baskets/:id/changes`                     | Data        | 403       | ok   | ok          | ok       | basketsRead (60/60s per IP)         | max(key rpm, 60)/min per key    |
| GET    | `/v1/baskets/:id/methodology/versions`        | Data        | 403       | ok   | ok          | ok       | basketsRead (60/60s per IP)         | max(key rpm, 60)/min per key    |
| GET    | `/v1/baskets/:id/version/:versionId`          | Data        | 403       | ok   | ok          | ok       | basketsRead (60/60s per IP)         | max(key rpm, 60)/min per key    |
| GET    | `/v1/baskets/:id/versions`                    | Data        | 403       | ok   | ok          | ok       | basketsRead (60/60s per IP)         | max(key rpm, 60)/min per key    |
| POST   | `/v1/baskets/:id/webhooks`                    | Decisioning | 403       | 403  | ok          | ok       | basketsWebhookWrite (30/60s per IP) | family cap 30/min per key       |
| DELETE | `/v1/baskets/:id/webhooks/:whId`              | Decisioning | 403       | 403  | ok          | ok       | basketsWebhookWrite (30/60s per IP) | family cap 30/min per key       |
| POST   | `/v1/baskets/:id/webhooks/:whId/enable`       | Decisioning | 403       | 403  | ok          | ok       | basketsWebhookWrite (30/60s per IP) | family cap 30/min per key       |
| POST   | `/v1/baskets/:id/webhooks/:whId/replay`       | Decisioning | 403       | 403  | ok          | ok       | basketsWebhookWrite (30/60s per IP) | family cap 30/min per key       |
| GET    | `/v1/chains`                                  | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| POST   | `/v1/chat`                                    | —           | ok        | ok   | ok          | ok       | userChat (2/60s per IP)             | 2/60s per IP                    |
| GET    | `/v1/curators`                                | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/curators/:id`                            | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/curators/:id/events`                     | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/docs`                                    | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/events`                                  | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/events/:id`                              | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/events/group/:groupKey`                  | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/events/stream`                           | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/evidence/signers`                        | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/graph/breach`                            | Decisioning | 401       | 403  | ok          | ok       | graph (600/60s per IP)              | max(key rpm, 600)/min per key   |
| POST   | `/v1/graph/check`                             | Decisioning | 401       | 403  | ok          | ok       | graphCheck (60/60s per IP)          | family cap 60/min per key       |
| GET    | `/v1/graph/curator-exposure`                  | Decisioning | 401       | 403  | ok          | ok       | graph (600/60s per IP)              | max(key rpm, 600)/min per key   |
| GET    | `/v1/graph/decision/:id/verify`               | —           | ok        | ok   | ok          | ok       | graph (600/60s per IP)              | max(key rpm, 600)/min per key   |
| GET    | `/v1/graph/expected-dependency-loss`          | Decisioning | 401       | 403  | ok          | ok       | graph (600/60s per IP)              | max(key rpm, 600)/min per key   |
| GET    | `/v1/graph/expected-dependency-loss/summary`  | Decisioning | 401       | 403  | ok          | ok       | graph (600/60s per IP)              | max(key rpm, 600)/min per key   |
| GET    | `/v1/graph/incident-exposure`                 | Decisioning | 401       | 403  | ok          | ok       | graph (600/60s per IP)              | max(key rpm, 600)/min per key   |
| GET    | `/v1/graph/incident-exposure/summary`         | Decisioning | 401       | 403  | ok          | ok       | graph (600/60s per IP)              | max(key rpm, 600)/min per key   |
| GET    | `/v1/graph/look-through`                      | Decisioning | 401       | 403  | ok          | ok       | graph (600/60s per IP)              | max(key rpm, 600)/min per key   |
| GET    | `/v1/graph/snapshot/:id`                      | —           | ok        | ok   | ok          | ok       | graph (600/60s per IP)              | max(key rpm, 600)/min per key   |
| GET    | `/v1/health`                                  | —           | ok        | ok   | ok          | ok       | health (120/60s per IP)             | 120/60s per IP                  |
| GET    | `/v1/indices`                                 | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/indices/:id`                             | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/indices/:id/census`                      | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/indices/:id/constituents`                | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/indices/:id/levels`                      | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/indices/:id/methodology`                 | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/indices/:id/notices`                     | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/indices/:id/quality`                     | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/indices/:id/reconciliations`             | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/indices/:id/runs/:valueDate`             | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/integrations/royco/markets/:slug`        | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/markets`                                 | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/markets/:id`                             | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/markets/:id/events`                      | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/me`                                      | —           | 401       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/methodology`                             | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/methodology/vault`                       | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/newsletter/confirm`                      | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| POST   | `/v1/newsletter/subscribe`                    | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/openapi.json`                            | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/oracle-vector/freshness`                 | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/por`                                     | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/por/:issuer`                             | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/por/:issuer/history`                     | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| POST   | `/v1/portfolio/overlap`                       | Decisioning | 401       | 403  | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/protocols`                               | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/protocols/:id`                           | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/rates/:slug`                             | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/rates/:slug/history`                     | —           | ok        | ok   | ok          | ok       | internal (120/60s per IP)           | max(key rpm, 120)/min per key   |
| GET    | `/v1/research/backtests`                      | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/research/claims`                         | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/research/model-health`                   | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/research/predictions`                    | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/research/sources`                        | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/research/validation-reports`             | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/reviewers`                               | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/rwa`                                     | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/rwa/:asset_id`                           | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/rwa/coverage`                            | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/rwa/facets`                              | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/rwa/stats/history`                       | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/security-events`                         | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/security-events/losses`                  | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/signals`                                 | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/signals/:id`                             | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/stablecoins/backing`                     | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/stats`                                   | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/stats/history`                           | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/stats/rating-dynamics`                   | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/status`                                  | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/users/:address/agents`                   | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| PUT    | `/v1/users/:address/agents`                   | —           | ok        | ok   | ok          | ok       | userWrite (10/60s per IP)           | 10/60s per IP                   |
| GET    | `/v1/users/:address/agents/auth-message`      | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vault/:network/:address`                 | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vault/:network/:address/events`          | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vault/:network/:address/holders`         | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vault/:network/:address/holders/history` | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vault/:network/:address/markets`         | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vault/:network/:address/score-history`   | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vault/:network/:address/snapshots`       | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vault/:network/:address/strategies`      | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vault/:network/:address/strategy`        | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vaults`                                  | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vaults/:id`                              | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| POST   | `/v1/vaults/batch`                            | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vaults/changes`                          | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vaults/scores`                           | Data        | 403       | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |
| GET    | `/v1/vaults/with-critical-incidents`          | —           | ok        | ok   | ok          | ok       | public (10/60s per IP)              | the key rpm (X-RateLimit-Limit) |