# Scopes & tiers

Two orthogonal gates sit on every call. **Scopes** decide which surfaces you
can reach. **Tiers** decide how far you can write on the trading surface. A
credential carries both.

## Scopes

| Scope | Unlocks |
| --- | --- |
| `firm:operate` | Operate the **firm**: create, configure, deploy, go live, pause, and approve payouts. `/api/v1/firms/*`. |
| `prop:manage` | Manage **accounts inside** a firm: challenge templates, risk profiles, trading groups, account resets and promotions. `/api/v1/prop-templates/*`, `/api/v1/risk-profiles/*`, `/api/v1/trading-groups/*`, `/api/v1/prop-accounts/*`. |
| `tenant:config` | Write your own tenant's branding, theme, and feature flags — for partners bringing their own front end. |

The scopes are independent; a full prop-firm operator credential carries
`firm:operate` and `prop:manage` together.

## Credential tiers

Tiers gate the OMS write surface, enforced per endpoint. The rule is
**`liquidation` may reduce risk, never add it**:

| Tier | Reads | `/oms/cancel` · `/oms/cancel-all` · `/oms/flatten` | Every other `/oms/*` write |
| --- | --- | --- | --- |
| `readonly` | ✓ | ✗ | ✗ |
| `liquidation` | ✓ | ✓ | ✗ |
| `fullTrading` | ✓ | ✓ | ✓ |

"Every other `/oms/*` write" means `/oms/intents`, `/oms/modify`,
`/oms/reverse`, `/oms/chase`, and the three `/oms/brackets/*` routes. Placing,
modifying, reversing a position and chasing a working order to a new price all
establish or re-establish exposure, so each of them requires `fullTrading`.
Cancelling and flattening only ever shrink the book, so `liquidation` reaches
them.

A rejected `/api/v1/oms/*` call returns `403` — `{"error":"tier_readonly"}` when
the credential is `readonly`, `{"error":"tier_insufficient"}` otherwise.
`detail` names the tier you hold and the tier the route wants. Other tier-gated
routes may answer `tier_insufficient` for every rejected tier —
`POST /api/v1/sandbox/paper-account` does — so branch on both codes.

`liquidation` exists for risk systems that must be able to flatten a book they
are not allowed to add to. Issue the narrowest tier that does the job — a
read-only dashboard has no business holding `fullTrading`.

## Tenant binding

On top of both gates, every credential is bound to **one tenant**. The tenant
comes from the credential's own row, not from the request, so you can only ever
read and write your own tenant's data. Note this is separate from the
`X-Tenant-Slug` header your requests must carry to resolve at all — see
[Tenancy](https://docs.troncharts.xyz/docs/auth/tenancy/).

## Checking what you hold

`GET /api/v1/discovery` lists the tier required by each endpoint it catalogs.
Two limits to know before you lean on it: the catalog is partial, and it reports
tiers only — it never reports the `firm:operate` / `prop:manage` /
`tenant:config` scopes above, so it cannot verify the scope half of your
credential. For the full surface read the
[OpenAPI spec](https://docs.troncharts.xyz/docs/reference/specs/); to confirm a scope, call one of the
endpoints it gates and check for a `403`.