{ "components": { "schemas": { "AdminAuthPutView": { "description": "`PUT /admin-auth` — the resource post-state (`{configured, modules}`, the same shape\n`GET /admin-auth` returns) plus apply metadata, so a client uses the PUT response as post-state.", "properties": { "applied": { "type": "boolean" }, "config_version": { "format": "uint64", "minimum": 0, "type": "integer" }, "configured": { "type": "boolean" }, "modules": { "items": { "type": "string" }, "type": "array" }, "note": { "type": "string" } }, "required": [ "configured", "modules", "applied", "config_version", "note" ], "type": "object" }, "AdminAuthView": { "description": "The admin-plane auth read (`GET /api/v1/admin/admin-auth`) — which modules guard the ADMIN surface\n(distinct from the ingress `auth` chain). `modules` is the live `admin_auth` chain (the SAME\nresource `PUT /api/v1/admin/admin-auth` writes), so a read-after-write is coherent. An empty chain is\nthe open (anonymous, full-authority) dev posture — `configured: false`. Never a secret.", "properties": { "configured": { "description": "Whether an admin credential chain is configured. `false` = the empty chain = open dev posture.", "type": "boolean" }, "modules": { "description": "The active admin-plane guard module names — the `admin_auth` chain verbatim (e.g.\n`[\"admin-tokens\"]`), reported in order. Empty when the admin plane is open.", "items": { "type": "string" }, "type": "array" } }, "required": [ "configured", "modules" ], "type": "object" }, "AuditEntry": { "description": "One admin audit record. `outcome` is a stable token tooling can branch on. The record is\nHASH-CHAINED for tamper-EVIDENCE: `hash = sha256(prev_hash | seq | ts | action | resource |\noutcome | principal)`, and `prev_hash` is the preceding entry's `hash`. Recomputing the chain detects any\naltered/reordered/deleted entry (detection, not prevention — a compromised host can still rewrite\nthe whole chain; prevention is shipping the log off-box to a SIEM).", "properties": { "action": { "description": "The action, `noun.verb` (e.g. `hook.register`, `hook.delete`).", "type": "string" }, "hash": { "description": "`sha256(prev_hash | seq | ts | action | resource | outcome | principal)` — the tamper-evidence digest.", "type": "string" }, "outcome": { "description": "Stable outcome token: `applied` (mutation committed) | `rejected` (validation/conflict, nothing\nchanged).", "type": "string" }, "prev_hash": { "description": "The preceding entry's `hash` (empty for the first entry of the process, or the oldest retained\nentry whose predecessor was pruned).", "type": "string" }, "principal": { "description": "WHO — the authenticated principal id that attempted the mutation (`admin` for the operator\ntoken; a virtual-key id or an external module's principal id otherwise; `anonymous` for the\nexplicit open admin posture). Attribution, never a credential.", "type": "string" }, "resource": { "description": "The resource acted on (e.g. `hook:compress`). Never a secret.", "type": "string" }, "seq": { "description": "Monotonic sequence number (1-based), unique within a process lifetime.", "format": "uint64", "minimum": 0, "type": "integer" }, "ts": { "description": "Unix seconds when the mutation was attempted.", "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "seq", "ts", "action", "resource", "outcome", "principal", "prev_hash", "hash" ], "type": "object" }, "AuditPageView": { "description": "`GET /audit` — the cursor-paginated audit-log envelope (`{items, next_cursor}`, hand-rolled in the\naudit handler).", "properties": { "items": { "items": { "$ref": "#/components/schemas/AuditEntry" }, "type": "array" }, "next_cursor": { "type": [ "string", "null" ] } }, "required": [ "items", "next_cursor" ], "type": "object" }, "AuthView": { "description": "The ingress auth chain read (`GET /api/v1/admin/auth`): the ordered module names that authenticate\ncallers + the upstream-credential mode. Never a secret — module names and the mode are config\nidentifiers, not credentials. An empty `chain` is the open front door (admits every request).", "properties": { "chain": { "description": "Ordered auth-chain module names (`[]` = open front door).", "items": { "type": "string" }, "type": "array" }, "open": { "description": "Whether the front door is open (empty chain admits unconditionally).", "type": "boolean" }, "upstream_credentials": { "description": "`\"own\"` (busbar signs egress with its configured key) or `\"passthrough\"` (forward the caller's\ncredential upstream).", "type": "string" } }, "required": [ "chain", "upstream_credentials", "open" ], "type": "object" }, "BuildInfo": { "description": "The compiled-in feature proof (`InfoView.build`).", "properties": { "auth_modules": { "description": "Auth modules baked into this binary (e.g. `[\"tokens\"]`; empty under `--no-default-features`).", "items": { "type": "string" }, "type": "array" }, "hook_plugins": { "description": "Hook plugins baked into this binary (e.g. `[\"ranking\"]`).", "items": { "type": "string" }, "type": "array" }, "weighted_floor": { "description": "The inline SWRR floor — ALWAYS `true` (compiled in unconditionally, non-removable).", "type": "boolean" } }, "required": [ "auth_modules", "hook_plugins", "weighted_floor" ], "type": "object" }, "CacheFlushView": { "description": "`POST /auth/cache/flush` — number of cached credential-decision entries dropped.", "properties": { "flushed": { "format": "uint", "minimum": 0, "type": "integer" } }, "required": [ "flushed" ], "type": "object" }, "ConfigApplyView": { "description": "`POST /config/apply` — apply-a-full-config result. The change is live but not written to disk.", "properties": { "applied": { "type": "boolean" }, "config_version": { "format": "uint64", "minimum": 0, "type": "integer" }, "note": { "type": "string" } }, "required": [ "applied", "config_version", "note" ], "type": "object" }, "ConfigDiffGlobalHooks": { "description": "The `global_hooks` delta of a `GET /config/diff` — present only when the global wiring changed.", "properties": { "from": { "items": { "type": "string" }, "type": "array" }, "to": { "items": { "type": "string" }, "type": "array" } }, "required": [ "from", "to" ], "type": "object" }, "ConfigDiffHooks": { "description": "The `hooks` object of a `GET /config/diff` — hook names added / removed / changed between the two\nversions.", "properties": { "added": { "items": { "type": "string" }, "type": "array" }, "changed": { "items": { "type": "string" }, "type": "array" }, "removed": { "items": { "type": "string" }, "type": "array" } }, "required": [ "added", "removed", "changed" ], "type": "object" }, "ConfigDiffView": { "description": "`GET /config/diff` — structured hook-surface diff between two retained versions. `global_hooks` is\npresent only when the global wiring differed between the two sides.", "properties": { "from": { "format": "uint64", "minimum": 0, "type": "integer" }, "global_hooks": { "anyOf": [ { "$ref": "#/components/schemas/ConfigDiffGlobalHooks" }, { "type": "null" } ] }, "hooks": { "$ref": "#/components/schemas/ConfigDiffHooks" }, "to": { "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "from", "to", "hooks" ], "type": "object" }, "ConfigReloadView": { "description": "`POST /config/reload` — reload-from-disk result.", "properties": { "config_version": { "format": "uint64", "minimum": 0, "type": "integer" }, "reloaded": { "type": "boolean" } }, "required": [ "reloaded", "config_version" ], "type": "object" }, "ConfigRollbackView": { "description": "`POST /config/rollback` — restore-a-retained-version result (the restored version + the NEW\nconfig version the rollback produced).", "properties": { "config_version": { "format": "uint64", "minimum": 0, "type": "integer" }, "restored_version": { "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "restored_version", "config_version" ], "type": "object" }, "ConfigSettingsView": { "description": "`GET`/`PUT /config/settings` (1.5.0 full-config coverage) — the API-settable single-value config\noverlay (`root` section) and, on a PUT, the apply metadata. `settings` is the CURRENT effective\nroot override (the merge of prior overlay + this request). It is overlay-persisted so it survives\na restart WHEN a config overlay is configured (`BUSBAR_CONFIG_OVERLAY`) — a busbar with none\napplies the change live only, and `note` says so; `PUT` with `\"persist\": true` makes storage\nmandatory, refusing (`400`) rather than silently applying in memory when no overlay exists.\n`reload_to_apply` names the fields whose new value is DURABLY STORED but not yet LIVE: the\nprocess-level binds (`listen`/`admin_listen` socket, `tls`/`admin_tls` bind, `admin_insecure`) are\nread once at process start, and the durable `store` backend is reused across a hot reload — none\ncan hot-swap, so they take effect on the next RESTART (or a supervisor restart), NEVER on a\n`POST /config/reload` — a reload re-reads disk and rebuilds the `App` but does not rebind sockets,\nrebuild the TLS acceptor, or re-open the store. It is always EMPTY when nothing was durably stored\n(no overlay); `note` names the affected fields instead. Everything else\n(`rate_card`/`per_request_fee`/`security`/`advanced`/`metrics`/`health`/`routing`) is LIVE on the\nswap; `limits` is live EXCEPT four boot-scoped fields (see `reload_to_apply_fields`):\n`upstream_request_timeout_secs`/`pool_max_idle_per_host`/`pool_idle_timeout_secs`, which the\nreused `UpstreamClients` only reads once at boot, and `max_inbound_concurrent`, which is baked\nonce into the data router's `GlobalConcurrencyLimitLayer` at process start (a config apply swaps\nonly `Arc`, never the router) — two independent freezing mechanisms. `observability` is live\nEXCEPT three boot-scoped fields: `emit_server_timing` (baked into router middleware state at\nboot), `request_log_webhook_url` (seeds a process-global `OnceLock` that no-ops after the first\n`main()` call), and `otlp_url` (feeds a one-shot `tracing_subscriber` init) — none rebuilt by an\napply.", "properties": { "applied": { "description": "`true` on a PUT that stored + swapped; `false` on a GET (a pure read).", "type": "boolean" }, "config_version": { "format": "uint64", "minimum": 0, "type": "integer" }, "note": { "description": "A human note describing the live-vs-reload split (absent on a GET).", "type": [ "string", "null" ] }, "reload_to_apply": { "description": "Fields that were stored durably but are RESTART-TO-APPLY: a socket rebind, a TLS acceptor\nbuild and a store open all happen once at process start, so a `POST /config/reload` does NOT\nmake them live — `POST /restart` (or a supervisor restart) does. Empty when the PUT touched\nonly live-swappable fields (or on a GET). The field NAME is frozen wire; only this description\nchanged.", "items": { "type": "string" }, "type": "array" }, "settings": { "description": "The current effective root-section overlay (only the fields the operator has set; base\n`config.yaml` stands for the rest). An arbitrary JSON object (the `RootSettings` projection)." } }, "required": [ "applied", "config_version", "settings" ], "type": "object" }, "ConfigValidateView": { "description": "The result of `POST /api/v1/admin/config/validate` — a DRY-RUN: does a proposed config resolve +\nvalidate, WITHOUT applying anything. `ok` is the verdict; `errors` lists every structural/resolution\nfailure at once (empty when `ok`). A well-formed request always returns 200 with this view (a valid\nrequest that describes an INVALID config is `ok: false`, not an HTTP error); only a MALFORMED request\nbody is an `invalid_request`. Env-var interpolation is out of scope — this checks structure and\ncross-reference resolution, not runtime secret presence.", "properties": { "errors": { "items": { "type": "string" }, "type": "array" }, "ok": { "type": "boolean" } }, "required": [ "ok", "errors" ], "type": "object" }, "ConfigVersion": { "description": "One recorded config version: the metadata the versions LIST shows, plus the full hook-surface\nsnapshot rollback restores. Never contains a secret (hook definitions are operator config —\ntransports, grants, deadlines).", "properties": { "principal": { "description": "The acting principal (audit attribution, same handle as the audit log).", "type": "string" }, "summary": { "description": "Human summary of the mutation that produced this version (e.g. `hook.register hook:x`).", "type": "string" }, "ts": { "description": "Unix seconds when the mutation committed.", "format": "uint64", "minimum": 0, "type": "integer" }, "version": { "description": "The `App.config_version` this snapshot corresponds to (monotonic per process).", "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "version", "ts", "principal", "summary" ], "type": "object" }, "ConfigVersionDetailView": { "description": "`GET /config/versions/{v}` — one retained config version WITH its full hook-surface snapshot\n(projected through the wire `HookView`, keyed by hook name) and the global wiring at that version.", "properties": { "global_hooks": { "items": { "type": "string" }, "type": "array" }, "hooks": { "additionalProperties": { "$ref": "#/components/schemas/HookView" }, "type": "object" }, "principal": { "type": "string" }, "summary": { "type": "string" }, "ts": { "format": "uint64", "minimum": 0, "type": "integer" }, "version": { "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "version", "ts", "principal", "summary", "hooks", "global_hooks" ], "type": "object" }, "ConfigVersionPageView": { "description": "`GET /config/versions` — the cursor-paginated version-history envelope (`{items, next_cursor}`).", "properties": { "items": { "items": { "$ref": "#/components/schemas/ConfigVersion" }, "type": "array" }, "next_cursor": { "type": [ "string", "null" ] } }, "required": [ "items", "next_cursor" ], "type": "object" }, "CreateKeyReq": { "additionalProperties": false, "description": "`POST /keys` body (1.5.0 signed-token keys, S1): PURE AUTH + a signed expiring token. A minted\nkey is a busbar-signed `{sub, exp, kid}` token, returned ONCE. No rpm/tpm/budget on a key - all\nenforcement flows through the bound `group`. `#[serde(deny_unknown_fields)]` so the removed\n1.4.x fields (max_budget_cents/rpm_limit/tpm_limit/budget_period) fail loudly.", "properties": { "allowed_pools": { "default": null, "description": "Pools this key may target. OMITTED = ALL pools; an explicit `[]` = NO pools (C6).", "items": { "type": "string" }, "type": [ "array", "null" ] }, "expires_at": { "default": null, "description": "Token expiry as an absolute Unix-seconds timestamp. Mutually exclusive with `expires_in`.", "format": "uint64", "minimum": 0, "type": [ "integer", "null" ] }, "expires_in": { "default": null, "description": "Token lifetime as a duration string (`7d`, `24h`, `30m`, `3600s`) - the token's `exp` is\n`now + expires_in`. Mutually exclusive with `expires_at`. Absent (and no `expires_at`) => a\nsane long default (see `DEFAULT_KEY_TTL_SECS`).", "type": [ "string", "null" ] }, "group": { "default": null, "description": "The `groups:` bucket this key binds to (at most one). A key with NO group is authed +\nunlimited (access only). If the named group EXISTS, the key binds to it. If it does NOT\nexist, the mint 400s UNLESS `parent` is given — then it is AUTO-PROVISIONED as a leaf under\n`parent` (self-service D2; see `parent`).", "type": [ "string", "null" ] }, "issue_aws_credential": { "default": false, "description": "When true, ALSO issue an AWS-style access-key-id + secret access key (the MinIO/S3-compatible\nmodel) so a Bedrock-SDK client can authenticate via inbound SigV4. Both are returned ONCE.", "type": "boolean" }, "labels": { "additionalProperties": { "type": "string" }, "default": {}, "description": "Optional mint-time labels echoed onto this key's metric series; never interpreted by\nenforcement.", "type": "object" }, "name": { "type": "string" }, "parent": { "default": null, "description": "AUTO-PROVISION target: the EXISTING parent group under which to create\n`group` as a leaf when `group` does not yet exist — the first-self-mint materialization of a\n`user:` personal budget bucket. The new leaf's limits come from the nearest-ancestor\n`child_default` template (inherit-only when none up the chain), created through the same\nvalidate-at-the-door path as `POST /groups`. If `group` ALREADY exists, `parent` must equal\nits actual parent (else 409) — a mint never re-homes an existing group. Ignored when `group`\nis absent (a key with no group has nothing to provision).", "type": [ "string", "null" ] } }, "required": [ "name" ], "type": "object" }, "CreatedKeyView": { "description": "`POST /keys` (mint) — the key metadata plus the ONCE-shown signed token, and (when an AWS SigV4\ncredential was requested) the AccessKeyId + secret access key. The AWS fields are absent on a\nbearer-only mint.", "properties": { "allowed_pools": { "items": { "type": "string" }, "type": [ "array", "null" ] }, "aws_access_key_id": { "description": "AWS AccessKeyId (present only when `issue_aws_credential` was set). Not secret.", "type": [ "string", "null" ] }, "aws_secret_access_key": { "description": "AWS SigV4 secret access key — shown once (present only with an AWS credential).", "type": [ "string", "null" ] }, "created_at": { "format": "uint64", "minimum": 0, "type": "integer" }, "enabled": { "type": "boolean" }, "expires_at": { "description": "Unix-seconds expiry of the signed token.", "format": "uint64", "minimum": 0, "type": "integer" }, "group": { "type": [ "string", "null" ] }, "group_provisioned": { "description": "Whether this mint AUTO-PROVISIONED its bound group leaf (self-service D2) — lets a portal\ndistinguish \"bound to an existing bucket\" from \"created your personal bucket + bound\".", "type": "boolean" }, "id": { "type": "string" }, "labels": { "additionalProperties": { "type": "string" }, "type": "object" }, "name": { "type": "string" }, "state": { "description": "E-007: same field as `KeyView.state` — a fresh mint is always `\"active\"` (enabled, not\nrevoked, not deleted).", "type": "string" }, "token": { "description": "The busbar-SIGNED token — the key credential (1.5.0, S1), shown EXACTLY once and never\nreturned by any read. (This is the field a client must capture to authenticate.)", "type": "string" } }, "required": [ "id", "name", "allowed_pools", "group", "enabled", "created_at", "labels", "state", "token", "expires_at", "group_provisioned" ], "type": "object" }, "EffectiveConfigView": { "description": "The EFFECTIVE config snapshot (`GET /api/v1/admin/config`) — the running configuration as busbar\nresolved it, for drift detection (compare against your desired config) and one-shot inspection.\nComposed from the same REDACTED reads as the individual endpoints (auth chain names, pool/model/\nprovider topology, hook definitions, global-hook wiring) — so it carries NO secret: no client\ntokens, no provider keys, no hook payloads. Additive-only; the source-layer annotation (base vs\noverlay) lands with the config overlay substrate.", "properties": { "auth": { "$ref": "#/components/schemas/AuthView" }, "global_hooks": { "description": "Names fired on every request (`global_hooks:` + any inline `global: true`).", "items": { "type": "string" }, "type": "array" }, "hooks": { "items": { "$ref": "#/components/schemas/HookView" }, "type": "array" }, "models": { "items": { "$ref": "#/components/schemas/ModelView" }, "type": "array" }, "pools": { "items": { "$ref": "#/components/schemas/PoolView" }, "type": "array" }, "providers": { "items": { "$ref": "#/components/schemas/ProviderView" }, "type": "array" }, "version": { "description": "The monotonic config version at the time of this read (see `InfoView.config_version`) — so a\ndrift-detection read gets the config AND its version in one call.", "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "version", "auth", "pools", "models", "providers", "hooks", "global_hooks" ], "type": "object" }, "Error": { "properties": { "error": { "properties": { "code": { "enum": [ "not_found", "unauthorized", "method_not_allowed", "forbidden", "invalid_request", "version_conflict", "conflict", "rate_limited", "internal" ], "type": "string" }, "message": { "type": "string" } }, "required": [ "code", "message" ], "type": "object" } }, "required": [ "error" ], "type": "object" }, "FlushCacheReq": { "description": "The `POST /api/v1/admin/auth/cache/flush` body. An absent body (or an absent `module`) flushes\nevery partition. Deliberately NOT `deny_unknown_fields`: the endpoint has always ignored extra\nmembers, and tightening that would reject a call that works today.", "properties": { "module": { "default": null, "description": "The auth module whose cache partition to flush. Omitted = flush all.", "type": [ "string", "null" ] } }, "type": "object" }, "GroupBucketUsageView": { "description": "One `(window, pool?)` enforcement bucket's usage vs caps inside a [`GroupUsageView`].", "properties": { "budget_cap": { "format": "int64", "type": [ "integer", "null" ] }, "budget_remaining_cents": { "description": "Cents left under `budget_cap` (floored at 0); absent when no budget cap is set.", "format": "int64", "type": [ "integer", "null" ] }, "pool": { "description": "The pool scope for a pool-qualified bucket; absent for a group-wide bucket.", "type": [ "string", "null" ] }, "requests": { "description": "Requests admitted this window (the requests-limit truth: failures are not refunded).", "format": "uint64", "minimum": 0, "type": "integer" }, "requests_cap": { "description": "The bucket's caps, when configured (absent = uncapped on that metric).", "format": "uint64", "minimum": 0, "type": [ "integer", "null" ] }, "spend_cents": { "description": "Spend derived at read time (tokens x current rate card), abstract cents.", "format": "int64", "type": "integer" }, "tokens": { "description": "Total tokens ledgered this window (all tiers).", "format": "uint64", "minimum": 0, "type": "integer" }, "tokens_cap": { "format": "uint64", "minimum": 0, "type": [ "integer", "null" ] }, "window": { "description": "The accounting window: `minute` | `hour` | `day` | `month` | `total`.", "type": "string" } }, "required": [ "window", "requests", "tokens", "spend_cents" ], "type": "object" }, "GroupUsageView": { "description": "`GET /groups/{name}/usage` — one group's DERIVED current-window usage, one row per\nenforcement bucket (each `(window, pool?)` its limits materialise), against that bucket's\ncaps. The dashboard read: spend/tokens/requests per tier vs the budgets, straight off the\nledger x the CURRENT rate card (reprice-on-read, nothing stored). The customer's self-service\ntool consumes this per group (`user:` leaf = one person's view) and re-scopes it.", "properties": { "as_of": { "description": "Epoch seconds the read was taken at (the windows below are current AS OF this instant).", "format": "uint64", "minimum": 0, "type": "integer" }, "buckets": { "description": "One row per enforcement bucket, in the group's resolved bucket order. Empty for a group\nwith only a `concurrent` limit (or none) — there is no windowed ledger to read.", "items": { "$ref": "#/components/schemas/GroupBucketUsageView" }, "type": "array" }, "enabled": { "description": "`false` = the group is FROZEN (`enabled: false`): every request through it rejects.", "type": "boolean" }, "group": { "description": "The group name (echoed from the path).", "type": "string" } }, "required": [ "group", "enabled", "buckets", "as_of" ], "type": "object" }, "GroupView": { "description": "A group definition in the registry read (`GET /api/v1/admin/groups`,\n`GET /api/v1/admin/groups/{name}`) — the limit-tree read surface. Projects the `groups:` config\nentry faithfully (parent chain, enabled freeze flag, the ordered limits, the `child_default`\nbudget template for auto-provisioned children), never a secret. This is the READ shape; the\nWRITE verbs accept a `GroupCfg` verbatim (paste a config.yaml group block). Additive-only.", "properties": { "child_default": { "description": "The limit template stamped onto children auto-provisioned under this group (e.g. a\n`user:` leaf on first self-mint). Skipped from the body when the group sets none.", "items": { "$ref": "#/components/schemas/LimitView" }, "type": [ "array", "null" ] }, "enabled": { "description": "`false` FREEZES the group (every request charging through it is rejected; history kept).", "type": "boolean" }, "limits": { "description": "The group's own limits, enforced together (AND). Order preserved from config.", "items": { "$ref": "#/components/schemas/LimitView" }, "type": "array" }, "name": { "type": "string" }, "parent": { "description": "The parent group whose limits this one is ANDed under (the enforcement chain). `None` = a\nroot group. Skipped from the body when absent.", "type": [ "string", "null" ] } }, "required": [ "name", "enabled", "limits" ], "type": "object" }, "HookDesiredStatus": { "description": "The DESIRED settings side of `hooks/{name}/status`: busbar's registry copy of the hook's settings\nand their version.", "properties": { "settings": { "additionalProperties": true, "type": "object" }, "settings_version": { "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "settings", "settings_version" ], "type": "object" }, "HookHealthView": { "description": "The live health of one hook's transport (`GET /api/v1/admin/hooks/{name}/health`). Checks\nwhether the hook resolves to a LOADED `kind: hook` plugin in the process's plugin registry —\nthis is a plugin-LOAD status check, not a network reachability probe: it never opens a\nconnection, and it cannot tell you whether a `kind: hook` plugin's own configured external\nendpoint (e.g. `busbar-webrequest-hook`'s `settings.url`) is actually reachable, only that the\nplugin itself is loaded. Never fires the hook. Additive-only.", "properties": { "detail": { "description": "A short human note on the resolution (why `false`, or the resolved plugin's kind). Never a\nsecret.", "type": [ "string", "null" ] }, "name": { "type": "string" }, "reachable": { "description": "`Some(true)` = resolves to a loaded `kind: hook` plugin; `Some(false)` = it does not\n(wrong kind, or not installed/loaded) — always `Some`, never `None`, as of 1.5.0's\nin-process plugin model.", "type": [ "boolean", "null" ] }, "transport": { "$ref": "#/components/schemas/HookTransportView" } }, "required": [ "name", "transport", "reachable", "detail" ], "type": "object" }, "HookReportedStatus": { "description": "The REPORTED settings side of `hooks/{name}/status`: what the hook says it is actually running\n(present only when the hook answered `status`).", "properties": { "settings": { "additionalProperties": true, "type": [ "object", "null" ] }, "settings_version": { "format": "uint64", "minimum": 0, "type": [ "integer", "null" ] } }, "required": [ "settings", "settings_version" ], "type": "object" }, "HookSchemaView": { "description": "`GET /hooks/{name}/schema` — the hook's self-described settings JSON Schema (proxied over the\n`describe` wire message), or `null` when the hook/transport does not answer.", "properties": { "name": { "type": "string" }, "schema": { "description": "The hook's settings JSON Schema verbatim (an arbitrary JSON object), or `null`." } }, "required": [ "name", "schema" ], "type": "object" }, "HookStatusView": { "description": "`GET /hooks/{name}/status` — the hook's OBSERVED state: desired vs reported settings with a\n`drift` verdict, plus the hook's self-reported metrics. `reported`/`drift` are `null` and `note`\nis present when the hook did not answer (fail-open); `metrics` is invariantly an array.", "properties": { "as_of": { "format": "uint64", "minimum": 0, "type": "integer" }, "desired": { "$ref": "#/components/schemas/HookDesiredStatus" }, "drift": { "type": [ "boolean", "null" ] }, "metrics": { "description": "Validated + bounded self-reported metrics; each entry carries `{name, type, value}` and, when\nthe hook sent them, optional `labels`/`quantiles`/`estimated`/`ci_low`/`ci_high`/`help`/\n`label`/`unit`/`viz`/`max` members.\n\nE-004 (busbar-ui/docs/ENGINE-BUGS.md): schemars' blanket `JsonSchema` impl for\n`serde_json::Value` renders as the JSON-Schema-2020-12 boolean `true` (`schemars-1.2.1`'s\n`json_schema_impls/serdejson.rs`), which is legal 2020-12 but — nested here as this array's\n`items` — is a boolean SUB-schema, and `kin-openapi` (the parser under `oapi-codegen`, which\nevery published SDK generates through) cannot represent one at all: the parse aborts, taking\nout Python/TS/Go SDK regeneration simultaneously. `#[schemars(schema_with)]` overrides just\nthis field's schema to `{\"type\": \"array\", \"items\": {}}` — `{}` is the equivalent \"accepts\nanything\" schema every generator DOES understand, and is what busbar-ui's own\n`openapi-prep.py` already rewrites `items: true` into client-side. This is the only\n`items: true` in the document; every other `additionalProperties: true` schemars emits\nelsewhere is a boolean in a position `kin-openapi` handles fine and is deliberately untouched.", "items": {}, "type": "array" }, "name": { "type": "string" }, "note": { "description": "A short human note present only on the fail-open (no-answer) branch.", "type": [ "string", "null" ] }, "reported": { "anyOf": [ { "$ref": "#/components/schemas/HookReportedStatus" }, { "type": "null" } ] }, "source": { "description": "Always `\"live\"` (the read is a live transport query).", "type": "string" } }, "required": [ "name", "desired", "reported", "drift", "metrics", "as_of", "source" ], "type": "object" }, "HookTransportView": { "description": "The transport half of a `HookView`. As of 1.5.0 a hook is EITHER a compiled-in kind (no\ntransport at all) or a signed `kind: hook` dlopen'd plugin (`target` = the plugin NAME, not a\nsocket path or URL) — the retired 1.4.x socket/webhook sidecar transports are gone.", "properties": { "kind": { "description": "`\"plugin\"` for a signed dlopen'd hook plugin, or `\"none\"` for a hook with no plugin\ntransport (compiled-in kinds, or a misconfigured entry).", "type": "string" }, "target": { "description": "The plugin's NAME (not a path or URL). `None` when `kind` is `\"none\"`.", "type": [ "string", "null" ] } }, "required": [ "kind", "target" ], "type": "object" }, "HookView": { "description": "A hook definition in the registry read (`GET /api/v1/admin/hooks`, `GET /api/v1/admin/hooks/{name}`) — the\nplugin catalog read. Projects the DEFINITION (kind, transport, grants, ordering, stage), never a\nsecret. `global` reports whether the hook fires on every request (named in `global_hooks:` or\ndeclared `global: true`). Live connection status (`health`) is a separate endpoint. Additive-only.", "properties": { "at": { "description": "TAP observation stage (`\"request\"`/`\"route\"`/`\"attempt\"`/`\"completion\"`), or `None` for a gate.", "type": [ "string", "null" ] }, "global": { "description": "Whether this hook fires on every request (globally wired).", "type": "boolean" }, "kind": { "description": "`\"tap\"` (fire-and-forget) or `\"gate\"` (fire-and-wait).", "type": "string" }, "name": { "type": "string" }, "on_error": { "description": "Gate fallback on timeout/error — a CLOSED, unambiguous string union (audit #8): one of the\nreserved terminals (`\"weighted\"` | `\"reject\"` | `\"first\"` | `\"nothing\"`) or the NAME of the\nfallback hook the chain continues through. Unambiguous by construction: the terminal words\nare ILLEGAL hook names on every write path (`config::RESERVED_HOOK_NAMES`), so a value in\nthe terminal set is always a terminal and anything else is always a hook reference.", "type": "string" }, "priority": { "description": "Rewrite/reject ordering key (transform-chain order + reject tie-break).", "format": "uint16", "maximum": 65535, "minimum": 0, "type": "integer" }, "prompt": { "description": "Prompt access grant: `\"no\"` | `\"ro\"` | `\"rw\"`.", "type": "string" }, "settings": { "additionalProperties": true, "description": "The hook's opaque settings map (operator/API-owned; pushed via the configure wire). Never\ninterpreted by busbar; never a secret by contract (hook settings are operator config).", "type": "object" }, "timeout_ms": { "description": "Gate decision deadline in milliseconds.", "format": "uint64", "minimum": 0, "type": "integer" }, "transport": { "$ref": "#/components/schemas/HookTransportView" }, "user": { "description": "Caller-identity access grant: `\"no\"` | `\"ro\"`.", "type": "string" } }, "required": [ "name", "kind", "transport", "prompt", "user", "priority", "at", "on_error", "timeout_ms", "settings", "global" ], "type": "object" }, "InfoView": { "description": "The compiled-in plugin catalog + topology + uptime returned by `GET /api/v1/admin/info`. Powers\nversion negotiation for tooling AND the compliance-by-compilation proof: `auth_modules`/`hook_plugins` reflect\nthe ACTUAL binary (feature-gated at compile time), not config, so `--no-default-features` shows a\nprovably smaller surface. No LLM content, ever.", "properties": { "build": { "$ref": "#/components/schemas/BuildInfo" }, "config_persistence": { "description": "Whether config-overlay persistence is enabled (`BUSBAR_CONFIG_OVERLAY` set): `true` = API-applied\nconfig changes are durable across restarts; `false` = live-only (lost on restart). Lets tooling\ntell an operator whether their runtime changes will survive a restart.", "type": "boolean" }, "config_version": { "description": "Monotonic config version — `0` at boot, +1 per API config apply. Drift-detection: re-read and\ncompare to tell whether the running config changed. Process-local (resets on restart).", "format": "uint64", "minimum": 0, "type": "integer" }, "started_at": { "description": "Epoch seconds of process start — the BOOT EPOCH marker: `config_version` (and any\nprocess-local counter) resets on restart, so a consumer that sees `started_at` change knows\nto read a counter reset as \"new epoch\", never as \"reverted\" (audit minor #2 / #4).", "format": "uint64", "minimum": 0, "type": [ "integer", "null" ] }, "topology": { "$ref": "#/components/schemas/TopologyInfo" }, "uptime_seconds": { "description": "Seconds since process start, or `None` if the start instant was never stamped.", "format": "uint64", "minimum": 0, "type": [ "integer", "null" ] }, "version": { "description": "busbar semantic version (`CARGO_PKG_VERSION`).", "type": "string" } }, "required": [ "version", "build", "uptime_seconds", "started_at", "topology", "config_persistence", "config_version" ], "type": "object" }, "InspectPluginReq": { "description": "`POST /api/v1/admin/plugins/inspect` request body. SAME shape as [`InstallPluginReq`] (question\n#7 — \"same request body shape as `POST /plugins`\") — `file` is accepted for shape parity with\nthe install flow a UI composes around the same upload, but is otherwise UNUSED here: inspect\nnever writes anything to disk, so there is no filename to bind an install would need.", "properties": { "file": { "type": "string" }, "tarball_b64": { "type": "string" } }, "required": [ "file", "tarball_b64" ], "type": "object" }, "InstallPluginReq": { "description": "The `POST /api/v1/admin/plugins` request body: install a SIGNED plugin tarball. The tarball\nbytes ride as base64 (`tarball_b64`) — a plugin artifact is opaque binary, so base64 keeps it a\nclean JSON field. The engine RE-VERIFIES the contained signed manifest server-side against the\nrunning `plugins.*` trust posture (the client is never trusted). `file` is the bare `.tar.gz`\nfilename to store it under (storage only — identity comes from the signed manifest inside).", "properties": { "file": { "type": "string" }, "tarball_b64": { "type": "string" } }, "required": [ "file", "tarball_b64" ], "type": "object" }, "KeyMeteringView": { "description": "`GET /keys/{id}/usage`: the key's all-time attribution counters (a 1.5.0 key bucket accrues in\nthe `total` window; limits live on the bound group's own windows) plus the fraction of the\ntightest `requests`/`tokens` limit across the group chain remaining (`null` = no such limit).", "properties": { "as_of": { "format": "uint64", "minimum": 0, "type": "integer" }, "budget_period": { "description": "Always `\"total\"` (the key attribution window).", "type": "string" }, "group": { "description": "The bound `groups:` entry (`null` = unlimited key).", "type": [ "string", "null" ] }, "id": { "type": "string" }, "rate_headroom": { "format": "double", "type": [ "number", "null" ] }, "requests": { "format": "uint64", "minimum": 0, "type": "integer" }, "spend_cents": { "format": "int64", "type": "integer" }, "tokens": { "format": "uint64", "minimum": 0, "type": "integer" }, "window_start": { "description": "Always `0` (the all-time window start).", "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "id", "budget_period", "window_start", "as_of", "group", "spend_cents", "tokens", "requests", "rate_headroom" ], "type": "object" }, "KeyPageView": { "description": "`GET /keys` — the cursor-paginated key list envelope (`{items, next_cursor}`, hand-rolled in the\nkeys handler rather than via `Page`).", "properties": { "items": { "items": { "$ref": "#/components/schemas/KeyView" }, "type": "array" }, "next_cursor": { "type": [ "string", "null" ] } }, "required": [ "items", "next_cursor" ], "type": "object" }, "KeyUsageView": { "description": "One key's row of the per-key aggregation: the key id/name (never the secret) + its counts.", "properties": { "id": { "type": "string" }, "name": { "description": "The key's display name; `None` when the key was deleted after metering accumulated (history\noutlives the key — the id still attributes it).", "type": [ "string", "null" ] }, "requests": { "format": "uint64", "minimum": 0, "type": "integer" }, "spend_micros": { "description": "Busbar's derived cost estimate in MICRO-units of the ABSTRACT cost unit (1e-6 unit -\ninteger math, sub-cent precise, no float drift), recomputed at read time from the raw token\nsplit x the operator's CURRENT per-model rate card. Busbar attaches no currency - the rate\ncard's numbers are whatever unit the operator priced in; display/denomination is entirely\nthe consumer's concern. A consumer with its own per-model catalog recomputes from the raw\ntoken split instead.", "format": "int64", "type": "integer" }, "tokens_cache_creation": { "format": "uint64", "minimum": 0, "type": "integer" }, "tokens_cache_read": { "format": "uint64", "minimum": 0, "type": "integer" }, "tokens_input": { "description": "Uncached input tokens (normalized additive-cache convention).", "format": "uint64", "minimum": 0, "type": "integer" }, "tokens_output": { "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "id", "name", "tokens_input", "tokens_output", "tokens_cache_read", "tokens_cache_creation", "requests", "spend_micros" ], "type": "object" }, "KeyView": { "description": "Virtual-key metadata — the `key_meta()` shape returned by `GET /keys/{id}`, `PATCH /keys/{id}`,\nand as each item of `GET /keys`. Never the secret or its hash. 1.5.0: keys are PURE AUTH, no\ninline limits; `allowed_pools` is `null` = all pools, `[]` = no pools (C6); `group` names the\nbound `groups:` entry (`null` = unlimited).", "properties": { "allowed_pools": { "items": { "type": "string" }, "type": [ "array", "null" ] }, "created_at": { "format": "uint64", "minimum": 0, "type": "integer" }, "enabled": { "type": "boolean" }, "group": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "labels": { "additionalProperties": { "type": "string" }, "type": "object" }, "name": { "type": "string" }, "state": { "description": "E-007: `enabled` alone cannot distinguish a reversible pause from either of the two permanent\ndispositions — `PATCH {enabled:false}`, `POST /keys/{id}/revoke`, and `DELETE /keys/{id}` all\nused to leave `enabled: false` with nothing else to tell them apart. One of exactly four\nvalues, additive and derived (never independently settable):\n- `\"active\"` — enabled, not revoked, not deleted.\n- `\"disabled\"` — `PATCH {enabled:false}`. Reversible: `PATCH {enabled:true}` restores it.\n- `\"revoked\"` — `POST /keys/{id}/revoke`. Permanent: denylisted, but the binding row (and\n `GET /keys/{id}`) stays live for audit/usage attribution.\n- `\"tombstoned\"` — `DELETE /keys/{id}`. Permanent: denylisted AND hard-deleted; the row is\n kept only so id-attributed billing/audit history keeps resolving. Omitted from a plain\n `GET /keys` by default; visible there with `?include=tombstoned`.", "type": "string" } }, "required": [ "id", "name", "allowed_pools", "group", "enabled", "created_at", "labels", "state" ], "type": "object" }, "LimitView": { "description": "One limit inside a `GroupView`: an explicit `{ metric, amount, per, pool }` projection of a\nconfig `LimitCfg`. The config file's compact `{ budget: 3000, per: month }` form is\ndeserialize-only sugar; the read API projects it explicitly so a consumer never has to know\nthe metric is the map key. `per` is `None` only for `concurrent` (an instantaneous gauge, no\nwindow); `pool` is present only on a pool-scoped limit.", "properties": { "amount": { "description": "The cap amount (requests/tokens/cents, or the in-flight gauge for `concurrent`).", "format": "uint64", "minimum": 0, "type": "integer" }, "downgrade_to": { "description": "Where `on_exhaust: downgrade` sends exhausted traffic. Present iff downgrading.", "type": [ "string", "null" ] }, "metric": { "description": "One of `requests` | `tokens` | `budget` | `concurrent`.", "type": "string" }, "on_exhaust": { "description": "The budget-exhaustion behavior: `block` or `downgrade`. Absent = block (the default).", "type": [ "string", "null" ] }, "per": { "description": "The accounting window: `minute` | `hour` | `day` | `month` | `total`. Absent for `concurrent`.", "type": [ "string", "null" ] }, "pool": { "description": "The pool scope: present when the limit carries `pool: ` (it accounts and enforces\nonly that pool's traffic, per `(group, pool)`); absent for a group-wide limit.", "type": [ "string", "null" ] } }, "required": [ "metric", "amount" ], "type": "object" }, "ModelUsageView": { "description": "One (model, provider) row of the per-model aggregation.", "properties": { "model": { "type": "string" }, "provider": { "type": "string" }, "requests": { "format": "uint64", "minimum": 0, "type": "integer" }, "spend_micros": { "description": "Busbar's derived cost estimate in MICRO-units of the ABSTRACT cost unit (1e-6 unit -\ninteger math, sub-cent precise, no float drift), recomputed at read time from the raw token\nsplit x the operator's CURRENT per-model rate card. Busbar attaches no currency - the rate\ncard's numbers are whatever unit the operator priced in; display/denomination is entirely\nthe consumer's concern. A consumer with its own per-model catalog recomputes from the raw\ntoken split instead.", "format": "int64", "type": "integer" }, "tokens_cache_creation": { "format": "uint64", "minimum": 0, "type": "integer" }, "tokens_cache_read": { "format": "uint64", "minimum": 0, "type": "integer" }, "tokens_input": { "description": "Uncached input tokens (normalized additive-cache convention).", "format": "uint64", "minimum": 0, "type": "integer" }, "tokens_output": { "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "model", "provider", "tokens_input", "tokens_output", "tokens_cache_read", "tokens_cache_creation", "requests", "spend_micros" ], "type": "object" }, "ModelView": { "description": "A model lane in the topology read (`GET /api/v1/admin/models`): the config key + its upstream\nprovider. No credentials, ever.", "properties": { "model": { "type": "string" }, "provider": { "type": "string" } }, "required": [ "model", "provider" ], "type": "object" }, "OverlayResetView": { "description": "`DELETE /overlay/{section}` — per-section overlay reset result: the section reverted, the\nresulting config version, and whether anything changed (`false` = the section had no overlay state,\nan idempotent no-op).", "properties": { "changed": { "description": "`true` when the reset discarded overlay mutations; `false` for an already-empty section.", "type": "boolean" }, "config_version": { "format": "uint64", "minimum": 0, "type": "integer" }, "reset": { "description": "The section that was reset (`groups` | `hooks` | `root` | `plugin_versions`).", "type": "string" } }, "required": [ "reset", "config_version", "changed" ], "type": "object" }, "Page_GroupView": { "description": "A cursor-paginated list envelope. `items` is this page; `next_cursor` is `Some` when more remain.\nGeneric over the item view so every list endpoint shares one shape.", "properties": { "items": { "items": { "$ref": "#/components/schemas/GroupView" }, "type": "array" }, "next_cursor": { "type": [ "string", "null" ] } }, "required": [ "items", "next_cursor" ], "type": "object" }, "Page_HookView": { "description": "A cursor-paginated list envelope. `items` is this page; `next_cursor` is `Some` when more remain.\nGeneric over the item view so every list endpoint shares one shape.", "properties": { "items": { "items": { "$ref": "#/components/schemas/HookView" }, "type": "array" }, "next_cursor": { "type": [ "string", "null" ] } }, "required": [ "items", "next_cursor" ], "type": "object" }, "Page_ModelView": { "description": "A cursor-paginated list envelope. `items` is this page; `next_cursor` is `Some` when more remain.\nGeneric over the item view so every list endpoint shares one shape.", "properties": { "items": { "items": { "$ref": "#/components/schemas/ModelView" }, "type": "array" }, "next_cursor": { "type": [ "string", "null" ] } }, "required": [ "items", "next_cursor" ], "type": "object" }, "Page_PluginView": { "description": "A cursor-paginated list envelope. `items` is this page; `next_cursor` is `Some` when more remain.\nGeneric over the item view so every list endpoint shares one shape.", "properties": { "items": { "items": { "$ref": "#/components/schemas/PluginView" }, "type": "array" }, "next_cursor": { "type": [ "string", "null" ] } }, "required": [ "items", "next_cursor" ], "type": "object" }, "Page_PoolView": { "description": "A cursor-paginated list envelope. `items` is this page; `next_cursor` is `Some` when more remain.\nGeneric over the item view so every list endpoint shares one shape.", "properties": { "items": { "items": { "$ref": "#/components/schemas/PoolView" }, "type": "array" }, "next_cursor": { "type": [ "string", "null" ] } }, "required": [ "items", "next_cursor" ], "type": "object" }, "Page_ProviderView": { "description": "A cursor-paginated list envelope. `items` is this page; `next_cursor` is `Some` when more remain.\nGeneric over the item view so every list endpoint shares one shape.", "properties": { "items": { "items": { "$ref": "#/components/schemas/ProviderView" }, "type": "array" }, "next_cursor": { "type": [ "string", "null" ] } }, "required": [ "items", "next_cursor" ], "type": "object" }, "PatchSettingsReq": { "description": "The `PATCH /api/v1/admin/hooks/{name}/settings` body. Optimistic concurrency rides `If-Match` (H3).", "properties": { "settings": { "additionalProperties": true, "type": "object" } }, "required": [ "settings" ], "type": "object" }, "PluginInstallView": { "description": "The result of installing a dynamic-library store plugin (`POST /api/v1/admin/plugins`). The\nengine RE-VERIFIED the uploaded bytes against the running trust posture (the client is never\ntrusted), validated the ABI handshake, and atomically wrote the library (+ its manifest sidecar)\ninto the plugins directory. `active` takes effect on the next store (re)load — a store change\napplies on restart / `store.module` apply, not as a hot swap (design: store install is\nboot-time/config-apply). Additive-only; never a secret.", "properties": { "file": { "description": "The library FILENAME written into the plugins directory (the handle `DELETE` takes).", "type": "string" }, "interface_version": { "description": "The store C-ABI (`interface_version`) the engine validated the library against.", "format": "uint32", "minimum": 0, "type": "integer" }, "name": { "description": "The plugin name from its manifest (or the filename when unsigned).", "type": "string" }, "note": { "description": "A human note: this install is durable in the folder but takes effect on the next store (re)load.", "type": "string" }, "publisher": { "description": "The manifest publisher, when signed.", "type": [ "string", "null" ] }, "trust": { "description": "The server-side trust verdict from the RE-VERIFY: `\"trusted\"` | `\"unverified\"`. (A `\"rejected\"`\nverdict is an error, never a success body.)", "type": "string" }, "version": { "description": "The manifest version, when the upload carried a signed manifest.", "type": [ "string", "null" ] } }, "required": [ "file", "name", "interface_version", "trust", "note" ], "type": "object" }, "PluginReloadView": { "description": "The result of re-scanning the plugins directory (`POST /api/v1/admin/plugins/reload`): the\ncurrent dynamic-library inventory, each with its ABI-validity. Reconciles the reported set to the\nfolder (the folder is the source of truth), exactly as `config/reload` reconciles config to disk.\nA store change still applies on the next store (re)load, not as a hot swap.", "properties": { "note": { "description": "A human note on when a store change actually takes effect.", "type": "string" }, "plugins": { "description": "The dynamic-library plugins now present in the directory, sorted by filename.", "items": { "$ref": "#/components/schemas/PluginView" }, "type": "array" } }, "required": [ "plugins", "note" ], "type": "object" }, "PluginRollbackReq": { "description": "The `POST /api/v1/admin/plugins/rollback` body: the target library FILENAME to roll DOWN to.", "properties": { "file": { "description": "The plugin tarball FILENAME (in the plugins directory) carrying the prior version to pin to.", "type": "string" } }, "required": [ "file" ], "type": "object" }, "PluginRollbackView": { "description": "The result of an EXPLICIT plugin ROLLBACK (`POST /api/v1/admin/plugins/rollback`, 1.5.0\nrollback-friendly versioning): the operator deliberately pinned a plugin DOWN to a prior version and\nthe engine hot-swapped to that artifact. The pin is persisted (survives restart) and the trust\nfloor was lowered to EXACTLY the pinned version for THIS plugin — a lower artifact still cannot\nload, and an automatic/silent replay of an old artifact is still refused (only this explicit,\naudited action lowered the floor). Additive-only; never a secret.", "properties": { "config_version": { "description": "The now-live config version after the hot swap (the ETag the response also carries).", "format": "uint64", "minimum": 0, "type": "integer" }, "file": { "description": "The library FILENAME the rollback selected in the plugins directory.", "type": "string" }, "name": { "description": "The plugin's canonical manifest name that was pinned.", "type": "string" }, "note": { "description": "A human note on the rollback's semantics + durability.", "type": "string" }, "publisher": { "description": "The manifest publisher of the pinned artifact (`busbar` = first-party).", "type": "string" }, "version": { "description": "The version the plugin was pinned DOWN to (now serving), from the target artifact's manifest.", "type": "string" } }, "required": [ "name", "file", "version", "publisher", "config_version", "note" ], "type": "object" }, "PluginSchemaView": { "description": "`GET /plugins/{name}/schema` — the generalized, all-kinds sibling of [`HookSchemaView`]\n(plugin-settings-schema-SPEC.md). Carries `trust`/`source`/`schema_error` on top of\n`{name, schema}` so busbar-ui never has to infer trust state or the describe/manifest\nprecedence rule from context — the server always picks exactly one source and reports which.", "properties": { "kind": { "description": "The plugin's `kind` (`hook` | `secret` | …) from its manifest. Both `GET /plugins/{file}/schema`\nand `POST /plugins/inspect` emit it (`null` only when the plugin cannot be resolved to a\nmanifest). Declared so codegen'd clients keep it.", "type": [ "string", "null" ] }, "name": { "type": "string" }, "restart_required_default": { "description": "The kind-derived restart-scoping default (`busbar_plugin_sign::kind_restart_default`), so\nbusbar-ui need not hardcode the kind→default table. Emitted by both schema endpoints (`null`\nonly when the plugin has no resolvable manifest/kind). Declared so codegen'd clients keep it.", "type": [ "boolean", "null" ] }, "schema": { "description": "The plugin's settings JSON Schema verbatim, or `null` — either because the manifest never\nset `settings_schema`, or (distinctly, see `schema_error`) because it did but the value\nfailed to parse." }, "schema_error": { "description": "Set only when the manifest's `settings_schema` was present but failed to parse as JSON —\n`null` for a manifest that genuinely never set the field. Never collapsed into a bare\n`schema: null` (question #3, round-4 correction): a present-but-corrupt schema is a real\nauthoring/packaging bug, not \"this plugin simply has none.\"", "type": [ "string", "null" ] }, "source": { "description": "`\"describe\"` when a currently-loaded `kind: hook` answered its live `describe` wire\nmessage (the existing describe-proxy behavior, unchanged); `\"manifest\"` otherwise. Lets\nbusbar-ui explain \"why does this form look different from what I expected\" without\nimplementing the describe/manifest precedence rule itself (question #3, round-4\ncorrection).", "type": "string" }, "trust": { "description": "`\"trusted\" | \"unverified\" | \"rejected\"` — the same vocabulary the plugin catalog already\nuses (never `\"verified\"`; question #8, round-4 correction).", "type": "string" }, "version": { "description": "The plugin's semantic version from its manifest. Present on `POST /plugins/inspect` (which\npreviews an on-disk candidate's manifest); `null`/absent on `GET /plugins/{file}/schema`, which\ndoes not surface the version. Declared here so a codegen'd client keeps the field the inspect\nhandler always sends, rather than silently dropping it.", "type": [ "string", "null" ] } }, "required": [ "name", "schema", "schema_error", "trust", "source" ], "type": "object" }, "PluginView": { "description": "One plugin in the plugin catalog (`GET /api/v1/admin/plugins?type=`). A plugin is either\nCOMPILED-IN (baked into the binary, feature-gated — provably removable via `--no-default-features`)\nor a signed DYNAMIC-LIBRARY plugin (a loadable `.so`/`.dll`/`.dylib`, dlopen'd over the signed\nplugin ABI — this covers `auth`, `hooks`, and `store` plugin kinds alike as of 1.5.0; the\nretired 1.4.x socket/webhook \"external\" transport is gone). `active` is `Some(true/false)`\nwhere activation is tracked (auth modules: in the chain?; hook plugins: configured = true;\ndynamic store: the configured `store.module`) and `None` where it is a per-pool concern not\nsummarized here (compiled-in ranking policies). Additive-only.", "properties": { "active": { "description": "Whether the plugin is currently active, where tracked; `None` when activation is not summarized\nat this level.", "type": [ "boolean", "null" ] }, "error": { "description": "Why a dynamic-library plugin did not validate (`valid: false`) — a short, secret-free reason.", "type": [ "string", "null" ] }, "file": { "description": "The artifact FILENAME in `plugins.dir` — the `{file}` path segment `DELETE\n/plugins/{file}` and `GET /plugins/{file}/schema` key off (E-003: a list row previously\ncarried no field a client could feed straight back into either sibling endpoint; `target`\nis documented as the manifest NAME, not necessarily the on-disk filename, and is not a\nreliable substitute). `None` for compiled-in/external rows, which have no backing artifact\nto name. Additive; existing consumers reading only the pre-1.5.1 fields are unaffected.", "type": [ "string", "null" ] }, "has_schema": { "description": "`true` iff `GET /plugins/{file}/schema` would resolve this row's `file` to a manifest that\ndeclares `settings_schema` at all — i.e. iff `schema_url` below is non-null — so a plugin\ncatalog can render which rows are configurable in one list call instead of a fetch per row\n(E-003). Mirrors `schema_url.is_some()`; kept as its own boolean rather than requiring the\ncaller to null-check `schema_url` for the same fact. `false` for compiled-in/external rows\n(no manifest to carry a schema) and for a dynamic-library row whose manifest never set\n`settings_schema`. Additive.", "type": "boolean" }, "interface_version": { "description": "The store C-ABI (`interface_version`) the manifest declares (dynamic-library plugins with a\nmanifest). Operator-facing name for the \"ABI\" the engine speaks.", "format": "uint32", "minimum": 0, "type": [ "integer", "null" ] }, "loader": { "description": "`\"compiled-in\"` or `\"plugin\"` (a dlopen'd dynamic-library plugin — auth, hook, and store\nkinds alike as of 1.5.0's signed plugin ABI).", "type": "string" }, "name": { "type": "string" }, "publisher": { "description": "The manifest's declared publisher (dynamic-library plugins with a manifest).", "type": [ "string", "null" ] }, "schema_error": { "description": "A manifest that SET `settings_schema` but whose value fails to parse (question #3's round-4\ncorrection, carried onto the list row too) — distinct from a manifest that never set the\nfield at all (`schema_url: null`, this field also `None`). `schema_url` stays non-null in\nthis case; the operator sees the row is degraded from the list alone, before ever following\nthe URL.", "type": [ "string", "null" ] }, "schema_url": { "description": "Server-resolved path to this plugin's `GET /plugins/{name}/schema` endpoint (questions\n#10/#11 of plugin-settings-schema-SPEC.md) — ALWAYS a relative path under the admin origin\n(the client MUST reject an absolute/cross-origin value rather than fetch it; this endpoint\nonly ever emits the admin-prefixed relative form, never anything else). Non-null whenever the\nmanifest declared a `settings_schema` AT ALL, even if it's unparseable (following it then\nsurfaces `schema_error` — question #11, round-8 correction: a present-but-corrupt schema is a\nworse, distinct condition from \"no schema declared\", never folded into the same `null`).\n`null` for a compiled-in/external row (no manifest to carry a schema at all) and for any\ndynamic-library row whose manifest never set `settings_schema`.", "type": [ "string", "null" ] }, "target": { "description": "For a dynamic-library plugin, its NAME (not a socket path or URL — the retired 1.4.x\ntransport target). `None` for compiled-in.", "type": [ "string", "null" ] }, "trust": { "description": "The server-side trust verdict for a dynamic-library plugin, re-evaluated against the running\n`plugins.trust` posture: `\"trusted\"` (signed by an allowlisted publisher), `\"unverified\"`\n(loaded but not verified — the posture permits it), or `\"rejected\"` (the `halt` posture would\nrefuse it). `None` for compiled-in/external.", "type": [ "string", "null" ] }, "type": { "description": "`\"auth\"`, `\"hooks\"`, or `\"store\"` — the plugin TYPE (each a distinct engine contract).", "type": "string" }, "valid": { "description": "For a dynamic-library plugin: whether the library validated as a busbar store plugin the engine\ncan load (ABI handshake). `None` for compiled-in/external.", "type": [ "boolean", "null" ] }, "version": { "description": "The plugin's semantic version, from its signed sidecar manifest (dynamic-library plugins only).\n`None` for compiled-in/external, or a dynamic plugin with no/invalid manifest.", "type": [ "string", "null" ] } }, "required": [ "name", "type", "loader", "active", "target", "has_schema" ], "type": "object" }, "PoolDetailView": { "description": "The LIVE per-pool detail read (`GET /api/v1/admin/pools/{name}`) — the reliability/capacity dashboard\ndata: each member's breaker state, concurrency headroom, in-flight\ncount, latency EWMA, and success/error tallies, read from the SAME store signals the routing seam\nranks on. No LLM content, no credentials.", "properties": { "members": { "items": { "$ref": "#/components/schemas/PoolMemberStatusView" }, "type": "array" }, "name": { "type": "string" } }, "required": [ "name", "members" ], "type": "object" }, "PoolMemberStatusView": { "description": "One member's live status within a pool. The breaker signal is the release-exposed\n`usable`/`cooldown_remaining_seconds` pair (a lane in breaker cooldown reports `usable: false` with the\nseconds remaining) — the same summary `/stats` surfaces.", "properties": { "available_concurrency": { "description": "Free concurrency slots on this lane right now (lane-global; permits are shared across pools).", "format": "uint", "minimum": 0, "type": "integer" }, "cooldown_remaining_seconds": { "description": "Seconds until a tripped breaker's cooldown elapses; `0` when not cooling down. (`_seconds`\nsuffix — the one unit-suffix spelling across the surface, like `uptime_seconds`.)", "format": "uint64", "minimum": 0, "type": "integer" }, "dead": { "description": "Whether the lane is hard-down/dead (distinct from a transiently-tripped breaker).", "type": "boolean" }, "err": { "format": "uint64", "minimum": 0, "type": "integer" }, "inflight": { "description": "In-flight requests on this lane right now.", "format": "int64", "type": "integer" }, "last_trip_at": { "description": "Epoch seconds of the most recent trip; `None` = never tripped.", "format": "uint64", "minimum": 0, "type": [ "integer", "null" ] }, "latency_ms": { "description": "Latency EWMA in milliseconds, or `None` if no sample yet.", "format": "double", "type": [ "number", "null" ] }, "model": { "type": "string" }, "ok": { "description": "Successful and errored request tallies for this lane.", "format": "uint64", "minimum": 0, "type": "integer" }, "trip_count": { "description": "MONOTONIC count of Closed→Open breaker trips on this lane. Breaker episodes are transient\nand can open+close entirely between two polls — a consumer alerting on trips diffs this\ncount instead of trying to catch the live edge (audit #5). Carried across config apply and\nrestart with the rest of the learned health.", "format": "uint64", "minimum": 0, "type": "integer" }, "usable": { "description": "Whether the lane can currently take dispatch (breaker closed / recovered). `false` while a\ntripped breaker cools down or the lane is dead.", "type": "boolean" }, "weight": { "format": "uint32", "minimum": 0, "type": "integer" } }, "required": [ "model", "weight", "usable", "cooldown_remaining_seconds", "available_concurrency", "inflight", "latency_ms", "ok", "err", "dead", "trip_count", "last_trip_at" ], "type": "object" }, "PoolMemberView": { "description": "One member of a pool: the model it targets and its SWRR weight.", "properties": { "model": { "type": "string" }, "weight": { "format": "uint32", "minimum": 0, "type": "integer" } }, "required": [ "model", "weight" ], "type": "object" }, "PoolView": { "description": "A pool in the topology read (`GET /api/v1/admin/pools`). Summary shape today: name + the member\nmodels and their weights. LIVE per-member status (breaker state, available concurrency, latency\nEWMA, budget/rate headroom — design-admin-api-v1) is an additive follow-up; the field set\nonly grows.", "properties": { "members": { "items": { "$ref": "#/components/schemas/PoolMemberView" }, "type": "array" }, "name": { "type": "string" } }, "required": [ "name", "members" ], "type": "object" }, "ProviderView": { "description": "A provider in the topology read (`GET /api/v1/admin/providers`): the provider name + how many model\nlanes route through it.", "properties": { "model_count": { "format": "uint", "minimum": 0, "type": "integer" }, "provider": { "type": "string" } }, "required": [ "provider", "model_count" ], "type": "object" }, "PutAuthBody": { "additionalProperties": false, "description": "The `PUT /api/v1/admin/admin-auth` body: the replacement admin auth chain.", "properties": { "admin_auth": { "description": "The ordered admin auth module chain. Empty is the explicit open dev posture.", "items": { "type": "string" }, "type": "array" } }, "required": [ "admin_auth" ], "type": "object" }, "RestartReq": { "additionalProperties": false, "description": "The `POST /api/v1/admin/restart` body. Absent is the same as `{}`.", "properties": { "confirm": { "default": false, "description": "Proceed even though no supervisor was detected. Exiting only restarts busbar if something\nrestarts it; without this an undetected supervisor is refused rather than risking the\ngateway staying down.", "type": "boolean" } }, "type": "object" }, "RestartView": { "description": "`POST /restart` — accepted-and-draining result.", "properties": { "note": { "type": "string" }, "restarting": { "type": "boolean" }, "supervisor_detected": { "description": "Whether a process supervisor was detected. False means the caller confirmed explicitly.", "type": "boolean" } }, "required": [ "restarting", "supervisor_detected", "note" ], "type": "object" }, "RevokeView": { "description": "`POST /keys/{id}/revoke` — the revoked key's id (denylisted without deleting the binding). 1.5.0.", "properties": { "revoked": { "description": "The id that was revoked (durably denylisted; the binding record remains).", "type": "string" } }, "required": [ "revoked" ], "type": "object" }, "RollbackReq": { "description": "The `POST /api/v1/admin/config/rollback` request body. Optimistic concurrency rides `If-Match` (H3).", "properties": { "version": { "description": "The retained version to restore.", "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "version" ], "type": "object" }, "RotatedKeyView": { "description": "`POST /keys/{id}/rotate` — the key metadata plus the ONCE-shown fresh CREDENTIAL. Exactly one of\n`token`+`expires_at` (a 1.5.0 signed-token key: a new token at a new binding generation, every\nprior token now rejected) or `secret` (a legacy hashed-secret key) is present.", "properties": { "allowed_pools": { "items": { "type": "string" }, "type": [ "array", "null" ] }, "created_at": { "format": "uint64", "minimum": 0, "type": "integer" }, "enabled": { "type": "boolean" }, "expires_at": { "description": "Unix-seconds expiry of the re-minted signed token (present with `token`).", "format": "uint64", "minimum": 0, "type": [ "integer", "null" ] }, "group": { "type": [ "string", "null" ] }, "id": { "type": "string" }, "labels": { "additionalProperties": { "type": "string" }, "type": "object" }, "name": { "type": "string" }, "secret": { "description": "The fresh bearer secret — shown EXACTLY once (legacy hashed-secret keys only).", "type": [ "string", "null" ] }, "state": { "description": "E-007: same field as `KeyView.state` — rotate does not change `enabled`/revoked/tombstoned\nstatus, so this reflects whatever the key's disposition already was (rotating a `disabled` or\n`revoked` key is legal and leaves it exactly that; only a `tombstoned` key refuses to rotate,\nwhich surfaces as 404 instead of this response).", "type": "string" }, "token": { "description": "The fresh busbar-SIGNED token — shown EXACTLY once (signed-token keys).", "type": [ "string", "null" ] } }, "required": [ "id", "name", "allowed_pools", "group", "enabled", "created_at", "labels", "state" ], "type": "object" }, "SigningKeyRotateView": { "description": "`POST /signing-key/rotate` — the current key-signing key id plus the REVOKE-ALL warning. 1.5.0 is\nsingle-key: the actual swap is an operator action, so this reports intent, not an in-process swap.", "properties": { "current_kid": { "description": "The current signing-key id (`kid`) that tokens are minted under.", "type": "string" }, "message": { "description": "Human-readable guidance for the operator-driven lockstep rotation.", "type": "string" }, "revoke_all": { "description": "Always `true`: rotating the signing key revokes every outstanding key (all must be re-minted).", "type": "boolean" } }, "required": [ "current_kid", "revoke_all", "message" ], "type": "object" }, "TopologyInfo": { "description": "Pool/model/provider counts (`InfoView.topology`).", "properties": { "models": { "format": "uint", "minimum": 0, "type": "integer" }, "pools": { "format": "uint", "minimum": 0, "type": "integer" }, "providers": { "format": "uint", "minimum": 0, "type": "integer" } }, "required": [ "pools", "models", "providers" ], "type": "object" }, "UpdateKeyReq": { "additionalProperties": false, "description": "Partial update to an existing key. Keys are PURE AUTH (1.5.0, S1), so the mutable surface is\nauth-shaped only. Every field is optional; only the present ones change. The credential, name,\nallowed-pools, and labels are immutable here (rotate/recreate for those).\n\n`group` is THREE-STATE via serde double-option (`Option>`):\n- absent (`#[serde(default)]` -> outer `None`): leave the binding unchanged.\n- JSON `null` (`Some(None)`): UNBIND to no group (authed + unlimited).\n- a value (`Some(Some(name))`): REBIND to that group (must exist; mint-parity check).\n\nA single `Option` could not tell absent from present-null, so a binding could never be\ncleared once set. `enabled` is a plain `Option` (a bool has no clear state). The 1.4.x\ncap fields (`rpm_limit`/`tpm_limit`/`max_budget_cents`) are GONE: limits live on the group.", "properties": { "enabled": { "default": null, "type": [ "boolean", "null" ] }, "group": { "default": null, "description": "Rebind or UNBIND the key's group. Absent = unchanged; `null` = unbind. The double `Option`\nis what distinguishes those two, so the schema describes it as a nullable string.", "type": [ "string", "null" ] } }, "type": "object" }, "UsageBreakdown": { "description": "The raw consumption counts + the derived spend estimate — the one shape shared by `total`,\n`by_model` rows, and `by_key` rows, so a consumer writes ONE aggregation reader.", "properties": { "requests": { "format": "uint64", "minimum": 0, "type": "integer" }, "spend_micros": { "description": "Busbar's derived cost estimate in MICRO-units of the ABSTRACT cost unit (1e-6 unit -\ninteger math, sub-cent precise, no float drift), recomputed at read time from the raw token\nsplit x the operator's CURRENT per-model rate card. Busbar attaches no currency - the rate\ncard's numbers are whatever unit the operator priced in; display/denomination is entirely\nthe consumer's concern. A consumer with its own per-model catalog recomputes from the raw\ntoken split instead.", "format": "int64", "type": "integer" }, "tokens_cache_creation": { "format": "uint64", "minimum": 0, "type": "integer" }, "tokens_cache_read": { "format": "uint64", "minimum": 0, "type": "integer" }, "tokens_input": { "description": "Uncached input tokens (normalized additive-cache convention).", "format": "uint64", "minimum": 0, "type": "integer" }, "tokens_output": { "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "tokens_input", "tokens_output", "tokens_cache_read", "tokens_cache_creation", "requests", "spend_micros" ], "type": "object" }, "UsageView": { "properties": { "as_of": { "description": "Freshness marker: the epoch this read was computed at (counters accumulate live).", "format": "uint64", "minimum": 0, "type": "integer" }, "by_key": { "description": "Per-key aggregation (same raw-split shape). CAPPED at the top 1000 rows by spend (the\nFinOps-relevant ordering); `by_key_truncated` says the cap fired — never a silent cut.", "items": { "$ref": "#/components/schemas/KeyUsageView" }, "type": "array" }, "by_key_truncated": { "description": "True when `by_key` was truncated to the cap (a deployment with more active keys than the\ncap). `by_model` is never capped (bounded by the configured model fleet).", "type": "boolean" }, "by_model": { "description": "Per-(model, provider) aggregation — cost attribution by model (the FinOps unit).", "items": { "$ref": "#/components/schemas/ModelUsageView" }, "type": "array" }, "currency": { "description": "The denomination of every `spend_micros` in this response (`USAGE_CURRENCY`, currently\n`\"USD\"`). A single-const source of truth so removal is one line. Emitted only here.", "type": "string" }, "others": { "anyOf": [ { "$ref": "#/components/schemas/UsageBreakdown" }, { "type": "null" } ], "description": "The summed remainder BEYOND the `by_key` cap — present exactly when `by_key_truncated`, so\nevery unit of consumption is attributable at least to \"others\" (FinOps completeness:\n`total == sum(by_key) + others`)." }, "total": { "$ref": "#/components/schemas/UsageBreakdown" }, "window": { "$ref": "#/components/schemas/UsageWindow", "description": "The UTC-day metering bucket this response aggregates: `[start, end)` epoch seconds." } }, "required": [ "window", "as_of", "currency", "total", "by_model", "by_key", "by_key_truncated" ], "type": "object" }, "UsageWindow": { "description": "A metering window: `[start, end)` epoch seconds.", "properties": { "end": { "format": "uint64", "minimum": 0, "type": "integer" }, "start": { "format": "uint64", "minimum": 0, "type": "integer" } }, "required": [ "start", "end" ], "type": "object" } }, "securitySchemes": { "adminToken": { "in": "header", "name": "x-admin-token", "type": "apiKey" }, "bearerAuth": { "description": "The same operator credential via Authorization: Bearer", "scheme": "bearer", "type": "http" } } }, "info": { "description": "The frozen, additive-only /api/v1/admin surface. Errors use the stable envelope {\"error\":{\"code\",\"message\"}}; tooling branches on `code`.", "title": "Busbar Admin API", "version": "1.5.1" }, "openapi": "3.1.0", "paths": { "/api/v1/admin/admin-auth": { "get": { "operationId": "GetAdminAuth", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminAuthView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Admin-plane auth config (the admin surface guard)", "x-busbar-required-scope": "read-only" }, "put": { "operationId": "PutAdminAuth", "parameters": [ { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PutAuthBody" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AdminAuthPutView" } } }, "description": "The resource + apply metadata: `{configured, modules, applied, config_version, note}`" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: unknown module / malformed body, malformed body / unknown field, malformed `If-Match` header" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: the new chain would lock the caller out | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Replace the admin_auth chain at runtime — dry-run guarded (the calling credentials must hold full scope under the NEW chain, else 409). Live until the next reload/restart", "x-busbar-required-scope": "full" } }, "/api/v1/admin/audit": { "get": { "operationId": "GetAudit", "parameters": [ { "description": "Filter by exact action (e.g. `hook.register`)", "in": "query", "name": "action", "required": false, "schema": { "type": "string" } }, { "description": "Filter by exact resource (e.g. `hook:x`)", "in": "query", "name": "resource", "required": false, "schema": { "type": "string" } }, { "description": "Page size (default 200, max 1000)", "in": "query", "name": "limit", "required": false, "schema": { "type": "string" } }, { "description": "Opaque continuation cursor from `next_cursor`", "in": "query", "name": "cursor", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuditPageView" } } }, "description": "OK" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed or foreign pagination `cursor`" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Admin audit log — every mutation with its outcome (newest first). Page: ?limit=, ?cursor=; returns {items, next_cursor}", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/auth": { "get": { "operationId": "GetAuth", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AuthView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Ingress auth chain + upstream-credential mode", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/auth/cache/flush": { "post": { "operationId": "PostAuthCacheFlush", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/FlushCacheReq" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CacheFlushView" } } }, "description": "`{flushed}` — entries dropped" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed body / unknown field" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Flush the credential cache — one module's partition (`{module}`) or everything (empty body). Instant revocation of the cached-allow window", "x-busbar-required-scope": "full" } }, "/api/v1/admin/config": { "get": { "operationId": "GetConfig", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EffectiveConfigView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Effective running config snapshot (redacted)", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/config/apply": { "post": { "operationId": "PostConfigApply", "parameters": [ { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "additionalProperties": false, "description": "Replace the running configuration.", "properties": { "config": { "additionalProperties": true, "description": "A `config.yaml` deploy block, as JSON. The accepted shape is the config file's own, documented in the configuration reference; it is not restated here because several of its types parse a wire shape that does not match their field layout.", "type": "object" }, "providers": { "additionalProperties": true, "description": "A `providers.yaml` document, as JSON. The accepted shape is the config file's own, documented in the configuration reference; it is not restated here because several of its types parse a wire shape that does not match their field layout.", "type": "object" } }, "required": [ "config" ], "type": "object" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigApplyView" } } }, "description": "`{applied, config_version, note}`" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: invalid config; nothing changed, malformed body / unknown field, malformed `If-Match` header" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Apply a full config from the request body, atomically (live until next reload/restart; health preserved by lane identity)", "x-busbar-required-scope": "full" } }, "/api/v1/admin/config/diff": { "get": { "operationId": "GetConfigDiff", "parameters": [ { "in": "query", "name": "from", "required": true, "schema": { "type": "integer" } }, { "in": "query", "name": "to", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigDiffView" } } }, "description": "The diff (hooks added/removed/changed + global-wiring delta)" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: missing or unknown required query parameter" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Structured hook-surface diff between two retained versions", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/config/reload": { "post": { "operationId": "PostConfigReload", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigReloadView" } } }, "description": "`{reloaded, config_version}`" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: invalid config; nothing changed, ephemeral busbar: no disk config to read, merge onto, or revert to" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Re-read config.yaml/providers.yaml from disk and apply atomically (health state preserved by lane identity)", "x-busbar-required-scope": "full" } }, "/api/v1/admin/config/rollback": { "post": { "operationId": "PostConfigRollback", "parameters": [ { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RollbackReq" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigRollbackView" } } }, "description": "`{restored_version, config_version}`" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: invalid config; nothing changed, malformed body / unknown field, malformed `If-Match` header" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Restore a retained version's hook surface (re-validated; a NEW version)", "x-busbar-required-scope": "full" } }, "/api/v1/admin/config/settings": { "get": { "operationId": "GetConfigSettings", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigSettingsView" } } }, "description": "`{applied:false, config_version, settings}` (settings = the current root overrides)" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Read the API-set single-value config overlay (root section: listen/tls/rate_card/store/security/limits/…) — only the operator's overrides; base config.yaml stands for the rest", "x-busbar-required-scope": "read-only" }, "put": { "operationId": "PutConfigSettings", "parameters": [ { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "additionalProperties": true, "description": "The settings sections to replace, keyed by section name. The optional top-level boolean `persist` asserts the change MUST be stored in the config overlay: with `persist: true` a busbar that has no overlay refuses with `400 invalid_request` instead of applying the change in memory only. Omitted or `false` means the change is applied and stored where storage is available, and applied in memory only where it is not (the response `note` says which); `false` never suppresses storage. Every other top-level key must be a known settings section — an unknown key is a 400. The accepted shape is the config file's own, documented in the configuration reference; it is not restated here because several of its types parse a wire shape that does not match their field layout.", "type": "object" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigSettingsView" } } }, "description": "`{applied:true, config_version, settings, reload_to_apply, note}`" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: invalid config; nothing changed, malformed body / unknown field, malformed `If-Match` header, ephemeral busbar: no disk config to read, merge onto, or revert to" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "SET any single-value config section durably (1.5.0 full-config coverage): partial RootSettings merged onto the overlay, re-resolved + validated, swapped in. rate_card/per_request_fee/security/limits/… go live; listen/tls/admin_listen/admin_tls/admin_insecure/store are stored + flagged restart-to-apply (bound once at start / store reused across a hot reload). NEVER writes config.yaml", "x-busbar-required-scope": "full" } }, "/api/v1/admin/config/validate": { "post": { "operationId": "PostConfigValidate", "requestBody": { "content": { "application/json": { "schema": { "additionalProperties": false, "description": "Validate a configuration without applying it.", "properties": { "config": { "additionalProperties": true, "description": "A `config.yaml` deploy block, as JSON. The accepted shape is the config file's own, documented in the configuration reference; it is not restated here because several of its types parse a wire shape that does not match their field layout.", "type": "object" }, "providers": { "additionalProperties": true, "description": "A `providers.yaml` document, as JSON. The accepted shape is the config file's own, documented in the configuration reference; it is not restated here because several of its types parse a wire shape that does not match their field layout.", "type": "object" } }, "required": [ "config" ], "type": "object" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigValidateView" } } }, "description": "Verdict `{ok, errors}` (even for an invalid config)" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed body / unknown field" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Dry-run validate a proposed config", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/config/versions": { "get": { "operationId": "GetConfigVersions", "parameters": [ { "description": "Page size (default 100, max 1000)", "in": "query", "name": "limit", "required": false, "schema": { "type": "string" } }, { "description": "Opaque continuation cursor from `next_cursor`", "in": "query", "name": "cursor", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigVersionPageView" } } }, "description": "OK" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed or foreign pagination `cursor`" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Config version history (newest first; id/ts/principal/summary). Page: ?limit=, ?cursor=; returns {items, next_cursor}", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/config/versions/{v}": { "get": { "operationId": "GetConfigVersionsV", "parameters": [ { "in": "path", "name": "v", "required": true, "schema": { "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigVersionDetailView" } } }, "description": "The version (metadata + hooks + global_hooks)" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: non-numeric path segment" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "One retained config version, with its hook-surface snapshot", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/groups": { "get": { "operationId": "GetGroups", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page_GroupView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Group registry — the limit tree (parent chain, limits, child_default budget template)", "x-busbar-required-scope": "read-only" }, "post": { "operationId": "PostGroups", "parameters": [ { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "additionalProperties": false, "properties": { "config": { "additionalProperties": true, "description": "A `groups:` entry, as JSON. The accepted shape is the config file's own, documented in the configuration reference; it is not restated here because several of its types parse a wire shape that does not match their field layout.", "type": "object" }, "name": { "description": "The group name.", "type": "string" } }, "required": [ "name", "config" ], "type": "object" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GroupView" } } }, "description": "Replaced — the name existed (body is the group definition)" }, "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GroupView" } } }, "description": "Created — the name is NEW (body is the group definition)" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: invalid tree — dangling/cyclic parent or depth, malformed body / unknown field, malformed `If-Match` header" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: base-defined (edit config.yaml) | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Create (or replace) a group at runtime — live immediately (upsert)", "x-busbar-required-scope": "full" } }, "/api/v1/admin/groups/{name}": { "delete": { "operationId": "DeleteGroupsName", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } }, { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Removed" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed `If-Match` header" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: base-defined (edit config.yaml), another group still names it as parent, one or more keys are still bound (rebind/delete them first) | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Remove an overlay group at runtime — live immediately", "x-busbar-required-scope": "full" }, "get": { "operationId": "GetGroupsName", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GroupView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "One group definition (parent, enabled, limits, child_default)", "x-busbar-required-scope": "read-only" }, "patch": { "operationId": "PatchGroupsName", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } }, { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "additionalProperties": false, "description": "A partial update: only the fields present are changed. `limits` and `child_default` REPLACE their whole value when present.", "properties": { "child_default": { "additionalProperties": true, "description": "A `child_default:` template. The accepted shape is the config file's own, documented in the configuration reference; it is not restated here because several of its types parse a wire shape that does not match their field layout.", "type": "object" }, "enabled": { "type": [ "boolean", "null" ] }, "limits": { "items": { "additionalProperties": true, "description": "A `limits:` entry. The accepted shape is the config file's own, documented in the configuration reference; it is not restated here because several of its types parse a wire shape that does not match their field layout.", "type": "object" }, "type": [ "array", "null" ] }, "parent": { "type": [ "string", "null" ] } }, "type": "object" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GroupView" } } }, "description": "The updated group" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: invalid tree — dangling/cyclic parent or depth, malformed body / unknown field, malformed `If-Match` header" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: base-defined (edit config.yaml) | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Partial update — change only the fields present (e.g. raise a budget, freeze a group)", "x-busbar-required-scope": "full" }, "put": { "operationId": "PutGroupsName", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } }, { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "additionalProperties": false, "properties": { "config": { "additionalProperties": true, "description": "A `groups:` entry, as JSON. The accepted shape is the config file's own, documented in the configuration reference; it is not restated here because several of its types parse a wire shape that does not match their field layout.", "type": "object" } }, "required": [ "config" ], "type": "object" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GroupView" } } }, "description": "The replaced group" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: invalid tree — dangling/cyclic parent or depth, malformed body / unknown field, malformed `If-Match` header" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: base-defined (edit config.yaml) | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Replace an overlay group definition — live immediately (limits rebuilt)", "x-busbar-required-scope": "full" } }, "/api/v1/admin/groups/{name}/usage": { "get": { "operationId": "GetGroupsNameUsage", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GroupUsageView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "The group's derived current-window usage per (window, pool) enforcement bucket vs its caps — the self-service dashboard read (spend derives from the token ledger x the CURRENT rate card at read time)", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/hooks": { "get": { "operationId": "GetHooks", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page_HookView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Hook registry (definitions)", "x-busbar-required-scope": "read-only" }, "post": { "operationId": "PostHooks", "parameters": [ { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "additionalProperties": false, "properties": { "config": { "additionalProperties": true, "description": "A `hooks:` entry, as JSON. The accepted shape is the config file's own, documented in the configuration reference; it is not restated here because several of its types parse a wire shape that does not match their field layout.", "type": "object" }, "name": { "description": "The hook name.", "type": "string" } }, "required": [ "name", "config" ], "type": "object" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HookView" } } }, "description": "Replaced — the name existed (same-grant re-register; body is the hook definition)" }, "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HookView" } } }, "description": "Registered — the name is NEW (body is the hook definition)" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed body / unknown field, malformed `If-Match` header" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`forbidden`: a `hooks-register` principal may not touch a content-seeing (`prompt`/`user`) or `global` hook" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: base-defined (edit config.yaml), grant change on an existing definition | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Register (or replace) a hook at runtime — live immediately", "x-busbar-required-scope": "hooks-register" } }, "/api/v1/admin/hooks/{name}": { "delete": { "operationId": "DeleteHooksName", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } }, { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Removed" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed `If-Match` header" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`forbidden`: a `hooks-register` principal may not touch a content-seeing (`prompt`/`user`) or `global` hook" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: base-defined (edit config.yaml) | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Remove a hook at runtime — live immediately", "x-busbar-required-scope": "hooks-register" }, "get": { "operationId": "GetHooksName", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HookView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "One hook definition", "x-busbar-required-scope": "read-only" }, "put": { "operationId": "PutHooksName", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } }, { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "additionalProperties": false, "properties": { "config": { "additionalProperties": true, "description": "A `hooks:` entry, as JSON. The accepted shape is the config file's own, documented in the configuration reference; it is not restated here because several of its types parse a wire shape that does not match their field layout.", "type": "object" } }, "required": [ "config" ], "type": "object" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HookView" } } }, "description": "The replaced hook" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed body / unknown field, malformed `If-Match` header" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`forbidden`: a `hooks-register` principal may not touch a content-seeing (`prompt`/`user`) or `global` hook" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: base-defined (edit config.yaml), grant change on an existing definition | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Replace an overlay hook definition — live immediately (grants immutable)", "x-busbar-required-scope": "hooks-register" } }, "/api/v1/admin/hooks/{name}/health": { "get": { "operationId": "GetHooksNameHealth", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HookHealthView" } } }, "description": "OK (`reachable` may be null for webhook/non-unix)" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Best-effort hook transport reachability", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/hooks/{name}/schema": { "get": { "operationId": "GetHooksNameSchema", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HookSchemaView" } } }, "description": "`{name, schema}` (`schema` null when the hook doesn't answer describe)" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "The hook's self-described settings JSON Schema (describe proxy)", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/hooks/{name}/settings": { "patch": { "operationId": "PatchHooksNameSettings", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } }, { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PatchSettingsReq" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HookView" } } }, "description": "Acked + committed (the updated hook)" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed body / unknown field, malformed `If-Match` header, the hook did not acknowledge; nothing committed" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`forbidden`: a `hooks-register` principal may not touch a content-seeing (`prompt`/`user`) or `global` hook" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: base-defined (edit config.yaml), a config change landed during the settings push — retry | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Push an opaque settings map to the running hook; COMMIT ON ACK", "x-busbar-required-scope": "hooks-register" } }, "/api/v1/admin/hooks/{name}/status": { "get": { "operationId": "GetHooksNameStatus", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HookStatusView" } } }, "description": "`{name, desired, reported, drift, metrics, as_of, source}`" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "The hook's OBSERVED state, live-queried: running settings + version (vs busbar's desired copy, with a drift verdict) and self-reported metrics. reported=null when the hook doesn't answer (fail-open)", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/info": { "get": { "operationId": "GetInfo", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InfoView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Version, compiled-in plugin proof, uptime, topology", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/keys": { "get": { "operationId": "GetKeys", "parameters": [ { "description": "Filter by enabled state (`true`|`false`)", "in": "query", "name": "enabled", "required": false, "schema": { "type": "string" } }, { "description": "Filter by key-id prefix", "in": "query", "name": "prefix", "required": false, "schema": { "type": "string" } }, { "description": "Filter by bound group (a `user:` leaf's keys are one person's)", "in": "query", "name": "group", "required": false, "schema": { "type": "string" } }, { "description": "Page size (default 200, max 1000)", "in": "query", "name": "limit", "required": false, "schema": { "type": "string" } }, { "description": "Opaque continuation cursor from `next_cursor`", "in": "query", "name": "cursor", "required": false, "schema": { "type": "string" } }, { "description": "E-007: set to `tombstoned` to include hard-deleted keys, which are otherwise omitted (each row's `state` reads `\"tombstoned\"`)", "in": "query", "name": "include", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KeyPageView" } } }, "description": "`{items, next_cursor}` — the cursor page envelope (next_cursor null at end)" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed or foreign pagination `cursor`, invalid query-parameter value" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "List virtual keys (metadata only; never secrets). Filters: ?enabled=, ?prefix=, ?group= (keys bound to a group — a `user:` leaf's keys are one person's). Paginate: ?limit=, ?cursor= (opaque)", "x-busbar-required-scope": "read-only" }, "post": { "operationId": "PostKeys", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateKeyReq" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreatedKeyView" } } }, "description": "Created (body includes the once-shown secret)" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed body / unknown field, an id or name exceeds its length cap, invalid mint-time `labels` — a reserved or non-Prometheus label name, or too many/too long, bad `expires_in` / `expires_at`, `parent` was given without `group`, a delegated `mint` credential may only issue keys BOUND to a group (`group` is required), invalid tree — dangling/cyclic parent or depth" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `mint` (error code `forbidden`)" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: governance is not enabled on this server, no signing key is configured for signed-token minting, an `Idempotency-Key` request is already in flight, the group is at the `limits.max_keys_per_principal` cap, base-defined (edit config.yaml)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Mint a virtual key. The secret is returned EXACTLY once. Honors an `Idempotency-Key` header (per-principal ~10min replay)", "x-busbar-required-scope": "mint" } }, "/api/v1/admin/keys/{id}": { "delete": { "operationId": "DeleteKeysId", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" } }, { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Revoked — No Content" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed `If-Match` header, an id or name exceeds its length cap" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: governance is not enabled on this server | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Revoke a key — it stops resolving immediately. Optional `If-Match` (the key's ETag)", "x-busbar-required-scope": "full" }, "get": { "operationId": "GetKeysId", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KeyView" } } }, "description": "Key metadata (+ `ETag` header)" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: an id or name exceeds its length cap" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource, governance is not enabled on this server" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "One key's metadata + `ETag` (never the secret/hash)", "x-busbar-required-scope": "read-only" }, "patch": { "operationId": "PatchKeysId", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" } }, { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateKeyReq" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KeyView" } } }, "description": "Updated metadata" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed body / unknown field, malformed `If-Match` header, an id or name exceeds its length cap, the rebind target group does not exist" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: governance is not enabled on this server, the group is at the `limits.max_keys_per_principal` cap | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Enable/disable a key or rebind its group. Optional `If-Match` for optimistic concurrency", "x-busbar-required-scope": "full" } }, "/api/v1/admin/keys/{id}/revoke": { "post": { "operationId": "PostKeysIdRevoke", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RevokeView" } } }, "description": "`{revoked}` — the id, now denylisted" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: an id or name exceeds its length cap" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: governance is not enabled on this server" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "REVOKE a signed-token key: denylist it durably WITHOUT deleting the binding (GET /keys/{id} still shows the record; verify now fails). Idempotent — revoking an already-revoked key is 200. DELETE /keys/{id} is the revoke-AND-forget variant (1.5.0)", "x-busbar-required-scope": "full" } }, "/api/v1/admin/keys/{id}/rotate": { "post": { "operationId": "PostKeysIdRotate", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RotatedKeyView" } } }, "description": "Rotated (body includes the once-shown new secret; an Idempotency-Key retry replays it verbatim)" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: governance is not enabled on this server, an `Idempotency-Key` request is already in flight" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Mint a fresh secret in place (same id, budgets, usage). The new secret is shown once; the old stops resolving. Honors an `Idempotency-Key` header (per-principal, op+id-scoped, ~10min replay)", "x-busbar-required-scope": "full" } }, "/api/v1/admin/keys/{id}/usage": { "get": { "operationId": "GetKeysIdUsage", "parameters": [ { "in": "path", "name": "id", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KeyMeteringView" } } }, "description": "Budget-window counters + `rate_headroom` (fraction of the tightest RPM/TPM cap left; null = uncapped)" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: an id or name exceeds its length cap" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource, governance is not enabled on this server" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Current-window usage for one key (spend / tokens / requests)", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/models": { "get": { "operationId": "GetModels", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page_ModelView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Model lanes + upstream providers", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/openapi.json": { "get": { "operationId": "GetOpenapiJson", "responses": { "200": { "content": { "application/json": { "schema": { "description": "An OpenAPI 3.1 document (this document's shape)", "type": "object" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "This OpenAPI 3.1 document", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/overlay/{section}": { "delete": { "operationId": "DeleteOverlaySection", "parameters": [ { "in": "path", "name": "section", "required": true, "schema": { "enum": [ "groups", "hooks", "root", "plugin_versions" ], "type": "string" } }, { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OverlayResetView" } } }, "description": "`{reset, config_version, changed}` — changed:false when the section had no overlay state" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: unknown overlay section (expected `groups`|`hooks`|`root`|`plugin_versions`), malformed `If-Match` header, ephemeral busbar: no disk config to read, merge onto, or revert to, invalid config; nothing changed" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "DISCARD a section's overlay mutations and revert it to base config.yaml (section ∈ groups|hooks|root|plugin_versions). Per-section reset — the OTHER sections' overlay survives. A NEW config version; an already-empty section is an idempotent no-op (changed:false)", "x-busbar-required-scope": "full" } }, "/api/v1/admin/plugins": { "get": { "operationId": "GetPlugins", "parameters": [ { "description": "Plugin type: `auth` | `hooks` | `store` (required)", "in": "query", "name": "type", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page_PluginView" } } }, "description": "OK" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: missing or unknown required query parameter" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Plugin catalog by type (compiled-in + external + dynamic-library)", "x-busbar-required-scope": "read-only" }, "post": { "operationId": "PostPlugins", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InstallPluginReq" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PluginInstallView" } } }, "description": "Installed — `{file, name, interface_version, trust, version?, publisher?, note}`" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed body / unknown field, invalid plugin filename, the artifact is not loadable — bad archive/manifest, or it fails structure/trust validation" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: the upload is untrusted and not opted-in, the plugin name/alias collides with an already-installed plugin under a different filename" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Install a dynamic-library store plugin: upload the library (base64) + optional signed manifest; the engine RE-VERIFIES against the running trust posture, validates the store ABI, and writes it atomically into the plugins directory. Takes effect on the next store (re)load", "x-busbar-required-scope": "full" } }, "/api/v1/admin/plugins/inspect": { "post": { "operationId": "PostPluginsInspect", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/InspectPluginReq" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PluginSchemaView" } } }, "description": "`{name, version, kind, schema, schema_error, trust, source, restart_required_default}` — the same shape `GET /plugins/{file}/schema` carries, plus `name`/`version`/`kind`; an untrusted/rejected candidate is reported (`trust`), never refused" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed body / unknown field" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Stateless read-only preview of a candidate plugin tarball — verify its signature, parse its manifest, and report its settings schema WITHOUT installing anything", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/plugins/reload": { "post": { "operationId": "PostPluginsReload", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PluginReloadView" } } }, "description": "`{plugins, note}` — the current dynamic-library inventory" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: invalid config; nothing changed" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Re-scan the plugins directory and report the reconciled dynamic-library inventory (the sibling of config/reload). A store change takes effect on the next store (re)load", "x-busbar-required-scope": "full" } }, "/api/v1/admin/plugins/rollback": { "post": { "operationId": "PostPluginsRollback", "parameters": [ { "description": "Optimistic concurrency: the resource's ETag from a prior read (or the ETag returned by the previous mutation). Stale = 409 `version_conflict` (re-read and retry), nothing changes; absent or `*` = unconditional.", "in": "header", "name": "If-Match", "required": false, "schema": { "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PluginRollbackReq" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PluginRollbackView" } } }, "description": "`{plugin, version, config_version, plugins}` — rolled back and hot-swapped" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed body / unknown field, malformed `If-Match` header, invalid plugin filename, ephemeral busbar: no disk config to read, merge onto, or revert to" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: the artifact is not loadable — bad archive/manifest, or it fails structure/trust validation | `version_conflict`: stale `If-Match` (re-read and retry)" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "EXPLICIT, authenticated, audited rollback of a plugin to a PRIOR version (1.5.0). Validates the target artifact (structure + trust) with the anti-downgrade floor lowered to EXACTLY the target's own version — a lower or untrusted artifact still fails (a rollback authenticates the OPERATOR, never the bytes). Persists the version pin to the overlay (survives restart) and hot-swaps via the same rebuild-and-swap path as plugins/reload", "x-busbar-required-scope": "full" } }, "/api/v1/admin/plugins/{file}": { "delete": { "operationId": "DeletePluginsFile", "parameters": [ { "in": "path", "name": "file", "required": true, "schema": { "type": "string" } } ], "responses": { "204": { "description": "Removed" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: invalid plugin filename" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Remove a dynamic-library plugin (library + manifest sidecar) from the plugins directory. A loaded store keeps running until the next store (re)load", "x-busbar-required-scope": "full" } }, "/api/v1/admin/plugins/{file}/schema": { "get": { "operationId": "GetPluginsFileSchema", "parameters": [ { "in": "path", "name": "file", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PluginSchemaView" } } }, "description": "`{name, schema, schema_error, trust, source}` — `schema` null (with `schema_error` null) when the manifest carries none; a manifest that SET `settings_schema` but failed to parse instead reports `schema_error` (never collapsed into the same null as \"no schema\"). `trust` is `trusted|unverified|rejected` (the catalog vocabulary). `source` is `describe` (a loaded hook answered live) or `manifest`" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "The plugin's self-described settings JSON Schema, read from the SIGNED manifest's `settings_schema` field — works for every plugin kind (store/secret/auth/hook), not just hooks. `hook` plugins keep the live describe-proxy behavior when describe answers (source: describe); a loaded hook whose describe answers null falls back server-side to the manifest baseline (source: manifest)", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/pools": { "get": { "operationId": "GetPools", "parameters": [ { "description": "`true` inlines each member's live status (same row shape as /pools/{name})", "in": "query", "name": "detail", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page_PoolView" } } }, "description": "OK" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: invalid query-parameter value" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Pool topology (members + weights). ?detail=true inlines live member status (one call, no N+1)", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/pools/{name}": { "get": { "operationId": "GetPoolsName", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PoolDetailView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "404": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`not_found`: unknown resource" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Live per-member status of one pool (breaker/concurrency/latency)", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/providers": { "get": { "operationId": "GetProviders", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Page_ProviderView" } } }, "description": "OK" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Distinct providers + lane counts", "x-busbar-required-scope": "read-only" } }, "/api/v1/admin/restart": { "post": { "operationId": "PostRestart", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestartReq" } } }, "required": false }, "responses": { "202": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RestartView" } } }, "description": "`{restarting, supervisor_detected, note}` — draining; in-flight requests finish first" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: malformed body / unknown field" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: no process supervisor was detected, so exiting would leave busbar down; re-send with `confirm: true` if a supervisor will restart it, this process has no shutdown channel, so it cannot restart itself" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Restart busbar to apply the restart-scoped settings (listen, admin_listen, tls, admin_tls, admin_insecure, store). Drains first; the supervisor brings it back", "x-busbar-required-scope": "full" } }, "/api/v1/admin/signing-key/rotate": { "post": { "operationId": "PostSigningKeyRotate", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SigningKeyRotateView" } } }, "description": "`{current_kid, revoke_all, message}` — the rotation intent + revoke-all warning" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `full` (error code `forbidden`)" }, "409": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`conflict`: governance is not enabled on this server, no signing key is configured; nothing to rotate" }, "429": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Per-principal mutation budget exhausted (error code `rate_limited`; `Retry-After` header)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "ROTATE the busbar key-signing key (S2). Rotation is REVOKE-ALL by design: a new signing key means every token minted under the OLD key stops verifying, so every outstanding key must be re-minted. 1.5.0 is single-key, so this reports the intent + current kid; the actual swap is an operator action (replace auth.signing_key / the persisted key file and restart/reload every node in lockstep) (1.5.0)", "x-busbar-required-scope": "full" } }, "/api/v1/admin/usage": { "get": { "operationId": "GetUsage", "parameters": [ { "description": "A PAST UTC-day bucket start epoch (default: current bucket). The response is always ONE bucket; spend_micros is a read-time estimate — bill from the raw token split, never store spend_micros as a ledger charge", "in": "query", "name": "window", "required": false, "schema": { "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UsageView" } } }, "description": "OK" }, "400": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "`invalid_request`: invalid query-parameter value" }, "401": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Missing/invalid admin credential (error code `unauthorized`)" }, "403": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Authenticated but under-scoped: requires `read-only` (error code `forbidden`)" }, "500": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }, "description": "Internal failure (error code `internal`); the detail is logged server-side, never returned" } }, "security": [ { "adminToken": [] }, { "bearerAuth": [] } ], "summary": "Metering: current UTC-day bucket — {window, as_of, currency, total, by_model, by_key}, raw token split + derived spend_micros", "x-busbar-required-scope": "read-only" } } } }