> ## Documentation Index
> Fetch the complete documentation index at: https://docs.platform.aiplanet.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Admin API

> Private operator endpoints for models, keys, budgets, usage, and audit.

Base URL: private operator origin

Automation authentication: `Authorization: Bearer <admin-key>`

Browser authentication: named administrator session cookie plus the per-login CSRF token automatically supplied by the packaged console on mutations. The token is bound to that session and static or stale values are rejected. Admin bearer keys require both `role: admin` and matching endpoint scope and retain full automation access. Most data APIs require Postgres persistence.

| Console role      | Access                                                                                                     |
| ----------------- | ---------------------------------------------------------------------------------------------------------- |
| `system_admin`    | All APIs and tenants, including administrator creation and disable                                         |
| `system_operator` | Global configuration, catalog, keys, budgets, and usage; no administrator management                       |
| `org_admin`       | One organization; key lifecycle and its BYOK catalog, plus read-only budgets, usage, requests, and signals |
| `org_operator`    | One organization; key lifecycle plus read-only catalog, budgets, usage, requests, and signals              |
| `org_viewer`      | Read-only catalog, keys, budgets, usage, requests, and signals for one organization                        |

Organization scope is enforced by the API, not the browser. Organization roles must have exactly one `org_id`; omitted key ownership is bound to that organization, supplying another `org_id` returns `403 tenant_scope_violation`, and identifier lookups include the actor's organization predicate. System roles reject `org_id`.
Only a `system_admin` can create, update, rotate, or revoke `role: admin` bearer keys; organization and system operator key-management permission cannot be used for privilege escalation. The legacy values `admin`, `operator`, and `viewer` remain accepted as aliases for `system_admin`, `system_operator`, and `org_viewer`.

## Console administrators

| Method   | Path                               | Description                                                                                        |
| -------- | ---------------------------------- | -------------------------------------------------------------------------------------------------- |
| `POST`   | `/admin/session`                   | Exchange username/password for an eight-hour HttpOnly session                                      |
| `GET`    | `/admin/session`                   | Inspect the current session or bearer identity                                                     |
| `DELETE` | `/admin/session`                   | Revoke the current browser session                                                                 |
| `GET`    | `/admin/oidc/config`               | Console-safe OIDC availability and provider label                                                  |
| `GET`    | `/admin/oidc/login`                | Start throttled OIDC Authorization Code + PKCE; excessive attempts return `429` with `Retry-After` |
| `POST`   | `/admin/platform-handoff/exchange` | Exchange one signed, single-use Platform organization-membership token for a session               |
| `POST`   | `/admin/platform-handoff/browser`  | Browser form exchange followed by a `303` to `/admin/ui`                                           |
| `POST`   | `/admin/platform-handoff/logout`   | Signed, idempotent revocation for one membership or all subject sessions                           |
| `GET`    | `/admin/oidc/callback`             | Verify the provider callback and issue an eight-hour session                                       |
| `GET`    | `/admin/users`                     | List administrator metadata without password hashes                                                |
| `POST`   | `/admin/users`                     | Create a named console administrator                                                               |
| `POST`   | `/admin/users/{username}/disable`  | Block an administrator and revoke all their sessions                                               |

The first administrator is deployment-owned. A password must be 12-128 characters. Creation accepts `role`; every `org_*` role requires `org_id`, while every `system_*` role rejects it. The last active `system_admin` (including legacy `admin` records) cannot be disabled.

When OIDC is configured, the console offers the deployment provider label. Initiation is distributed-throttled before provider discovery or database state creation. The gateway verifies discovery issuer equality, HTTPS endpoints, PKCE S256, one-time state, signature and approved algorithm, issuer, audience, expiry, nonce, and authorized party. Provider subjects are mapped explicitly to gateway usernames/roles/tenant scopes; token group or role claims cannot grant access. Retain a restricted audited password identity for break-glass recovery.

When Platform handoff is configured, the Platform backend—not the browser—selects the current membership and signs its immutable subject, organization, current role, and high-resolution authority time. The token expires within five minutes at most, is consumed once through Postgres, and is submitted by body/form rather than a URL. Signed logout actions include the original logout cutoff, so delayed retries preserve sessions created by later logins without relying on clocks from different services. Persisted global and organization cutoffs also reject handoffs minted before logout but exchanged after delivery. One Platform subject may hold multiple independent organization principals. Platform `admin`, `editor`, and `viewer` map only to `org_admin`, `org_operator`, and `org_viewer`; a handoff can never create system authority.

## Audit events

| Method | Path                                   | Description                                                  |
| ------ | -------------------------------------- | ------------------------------------------------------------ |
| `GET`  | `/admin/audit-events`                  | Admin-only retention-bounded mutation and login events       |
| `GET`  | `/admin/data-governance`               | Retention policy, lease, completion counts, and worker error |
| `POST` | `/admin/data-governance/retention/run` | Admin-only leased metadata/auth-artifact cleanup             |

Each state-changing route records an `attempt` before mutation and an `outcome` with actor, authentication type, role, tenant scope, request/instance IDs, action, target, result, status, and allowlisted redacted metadata. Filters are `actor_subject`, `action`, `outcome`, `org_id`, and `limit=1..500`. Only system administrators can read this endpoint.

When Postgres audit preflight is unavailable, administrative mutations fail closed with `503 admin_audit_unavailable`. If only the post-action outcome write fails, the response includes `X-Gateway-Audit-Status: failed` and readiness remains failed until a later audit write succeeds; verify the target state before considering any retry.

## Runtime and configuration

| Method | Path            | Description                                                                                           |
| ------ | --------------- | ----------------------------------------------------------------------------------------------------- |
| `GET`  | `/ready`        | Serving decision plus engine, model-catalog, database, shared-state, audit, logger, and worker health |
| `GET`  | `/metrics`      | Prometheus exposition                                                                                 |
| `GET`  | `/admin/config` | Active configuration with credentials redacted                                                        |
| `POST` | `/admin/reload` | Validate and atomically reload supported configuration changes                                        |

Changes to persistence, shared state, alert worker, signals, reconciliation, or catalog-propagation configuration require restart. In a multi-process deployment, general configuration reload affects only the process receiving the request; catalog generations propagate separately.

## Signals and weekly digests

| Method | Path                     | Description                                                 |
| ------ | ------------------------ | ----------------------------------------------------------- |
| `GET`  | `/admin/signals/issues`  | List tenant-scoped open or resolved calibrated issues       |
| `GET`  | `/admin/signals/digests` | List tenant-scoped weekly digest records and delivery state |
| `POST` | `/admin/signals/run`     | Run one leased evaluation immediately; admin only           |

Signals require Postgres and use request metadata only. The initial rules cover sustained server-error rate, rate-limit rate, missing billable usage, and p95 latency with a previous-window regression guard. Minimum sample counts plus consecutive breach and recovery windows suppress one-off noise. Firing, reminder, resolved, and completed-week digest notifications use the configured durable Slack or Google Chat outbox. The API does not expose the webhook URL.

## Model catalog

| Method   | Path                                     | Description                                                                                                              |
| -------- | ---------------------------------------- | ------------------------------------------------------------------------------------------------------------------------ |
| `GET`    | `/admin/model-catalog`                   | Current providers, models, aliases, revision, stored/supported schema versions, generation, and replica acknowledgements |
| `POST`   | `/admin/models`                          | Add a concrete model                                                                                                     |
| `PUT`    | `/admin/models/{model_name}`             | Replace a concrete model definition                                                                                      |
| `DELETE` | `/admin/models/{model_name}?revision=N`  | Delete an unreferenced concrete model                                                                                    |
| `POST`   | `/admin/aliases`                         | Add a weighted application alias                                                                                         |
| `PUT`    | `/admin/aliases/{alias_name}`            | Replace an alias definition                                                                                              |
| `DELETE` | `/admin/aliases/{alias_name}?revision=N` | Delete an alias                                                                                                          |
| `POST`   | `/admin/model-catalog/reset`             | Remove the database override and restore deployment YAML models                                                          |

For system roles, every mutation includes the latest non-negative `revision`; stale updates return `409 model_catalog_conflict`. The gateway validates the entire routing graph, requires reviewed pricing for enabled API-managed models, builds and readiness-checks a new engine, persists the revision, and then atomically swaps the runtime. Deployment-owned global provider credentials cannot be created through these endpoints.

An `org_admin` sees and mutates only its organization's BYOK models and weighted aliases through the same routes. BYOK credential documents are encrypted at rest and returned only as masked previews. The deployment's `byok.custom_api_base_policy` can disable custom endpoints, require operator-approved hosts (the default), or accept public HTTPS hostnames. Every mode rejects IP-literal custom endpoints; configured endpoints must use HTTPS, contain no URL credentials/query/fragment, and resolve only to public addresses when created or updated. Production deployments also enforce outbound network policy against private and metadata destinations. Organization operators and viewers have read-only catalog access. An aliased model cannot be deleted until its aliases are changed or removed.

At startup, an unusable stored catalog is reported as `source: database_pending` with `activation_status: degraded`. The process keeps the deployment model baseline active for diagnosis; `/ready` reports component degradation but remains 200 while that safe runtime is serving. Use the returned pending revision to repair the graph or call the reset endpoint. If `schema_version` is newer than `supported_schema_version`, the replica returns `model_catalog_schema_unsupported` and rejects catalog mutations or reload with `409`; upgrade it or intentionally reset the pending revision.

With Postgres, each mutation and reset advances a monotonic generation. Replicas automatically poll and acknowledge it as `active`, `applying`, or `failed`; stale acknowledgements are marked separately. Every process needs a unique `LLM_GATEWAY_INSTANCE_ID`. A replica that is behind or cannot activate fails `model_catalog_ready` until it catches up or the catalog is repaired, without discarding its last safe runtime.

## API keys

| Method | Path                          | Description                                                      |
| ------ | ----------------------------- | ---------------------------------------------------------------- |
| `GET`  | `/admin/keys`                 | List metadata and status                                         |
| `POST` | `/admin/keys`                 | Create a key; raw token returned once                            |
| `POST` | `/admin/keys/{key_id}/rotate` | Replace the token atomically; optionally overlap the prior token |
| `POST` | `/admin/keys/{key_id}/revoke` | Block a key                                                      |

Creating a key with RPM or TPM limits requires Redis shared state unless the deployment explicitly acknowledges one-process memory enforcement with `shared_state.allow_process_local_throttling: true`. Otherwise `POST /admin/keys` returns `409 distributed_rate_limits_required` and does not persist the key.

Admin-created keys require `org_id`. Rotation accepts `{"overlap_seconds": 300}` with a range of 0-86,400 seconds and returns the new raw token once. A zero overlap invalidates the previous token immediately; revocation invalidates the current and overlapping token. See [API keys](/llm-gateway/administration/api-keys) for the full workflow.

## Usage

| Method | Path                           | Description                                                                                                       |
| ------ | ------------------------------ | ----------------------------------------------------------------------------------------------------------------- |
| `GET`  | `/admin/usage`                 | Aggregate requests/errors/tokens/cost/average latency                                                             |
| `GET`  | `/admin/usage/breakdown`       | Aggregate by model, provider, key, org, app, environment, or status                                               |
| `GET`  | `/admin/usage/timeseries`      | Hourly or daily request/token/cost buckets                                                                        |
| `GET`  | `/admin/requests`              | Paginated metadata rows and payload availability flags; server-side search/outcome filters; maximum page size 100 |
| `GET`  | `/admin/requests/{request_id}` | Tenant-scoped request details with retained input/output when payload storage is enabled                          |

Common filters are `start_at`, `end_at`, `api_key_id`, `org_id`, `app_id`, `environment`, `model`, `provider`, and `status_code`.

## Budgets

| Method | Path                                                    | Description                                                         |
| ------ | ------------------------------------------------------- | ------------------------------------------------------------------- |
| `GET`  | `/admin/budgets`                                        | Current period spend, reserved, available, utilization, and reset   |
| `GET`  | `/admin/budget-alerts`                                  | Threshold alert delivery status and retries                         |
| `GET`  | `/admin/budget-reservations`                            | Reservation lifecycle; supports `status`, `stale_only`, and `limit` |
| `POST` | `/admin/budget-reservations/{reservation_id}/reconcile` | Charge one stale reservation conservatively                         |

Manual reconciliation returns 409 while a reservation is still inside its active execution window.
Reservation rows include automatic reconciliation attempt, retry, error, and soft-quarantine fields. A manual reconcile remains available for a stale quarantined row after its underlying data is repaired; it does not wait for the automatic retry timestamp.

## Organization limits

Aggregate throttling ceilings apply across every key in an organization and are enforced before per-key limits. Only a `system_admin` can read or change these ceilings; tenant roles cannot raise their own limits.

| Method   | Path                                   | Description                                                                                     |
| -------- | -------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `GET`    | `/admin/organizations/{org_id}/limits` | Current per-organization `rpm_limit`, `tpm_limit`, and `max_concurrency` (null means unlimited) |
| `PUT`    | `/admin/organizations/{org_id}/limits` | Set the organization's limits; each field is a positive integer or null                         |
| `DELETE` | `/admin/organizations/{org_id}/limits` | Remove all limits for the organization                                                          |

Requests that exceed an organization's request or token rate return `429 org_rate_limit_exceeded` with a `Retry-After` header; requests over the organization's concurrent-request limit return `429 concurrency_limit_exceeded`. Organization rate and concurrency limits require Redis shared state unless the deployment explicitly acknowledges one-process memory enforcement.

## Operator UI

Self-managed builds include `/admin/ui` for models, aliases, application keys, console administrators, usage, cost, budgets, alerts, and reservations. Keep it on the private operator origin.
