Admin, Environment, and Costs API
Three admin-only routes, grouped because none of them touch the spine directly.
/api/users — user and role management
Admin-only. Lists the org's people and lets an admin change a person's role, from
admin | lead | consultant | client. Guards against removing the org's last admin — a
lockout an admin route must never be able to cause by accident.
/api/environment — the Environment tool's metadata bridge
Admin-only. Reads and writes the env-control-plane tables (env_apps, env_repos,
env_platform_targets, env_var_requirements, env_manifest_ingests, and friends) — names and
metadata only, never values, mirroring the same discipline the env-manifests/*.json files
follow.
GET ?action=summary -> KPI strip + per-app rows (default)
GET ?action=app&slug=... -> one app: platforms + variable requirements + deployment status
GET ?action=providers -> provider registry with variable counts
GET ?action=audit&limit=... -> recent audit events
POST ?action=ingest-manifest -> { manifest } (one env-manifest.json) -> upsert the tables
ingest-manifest is how a manifest file's structure becomes queryable — see
Env Manager Guide for the manifest format this ingests.
/api/admin-costs — AI and API spend
Admin/lead only (cost data is treated as sensitive, not just internal). Reads the ai_usage
ledger scoped to the viewer's org via the service-role client and aggregates in JavaScript
(org-wide, by provider/model/feature/user/day).
GET /api/admin-costs?range=7d|30d|90d|mtd
GET /api/admin-costs?range=30d&format=csv
format=csv streams raw rows for finance rather than the aggregated view — a different shape for
a different audience, not a superset/subset of the same data.
Pagination is capped: PAGE = 1000 rows per page, MAX_PAGES = 200 — a hard 200,000-row safety
ceiling so a huge range parameter can't run away and exhaust the function's own runtime.
What's captured vs. pending
captured: chat, weekly_update, vision_ocr, embed, rerank, meeting_extract,
interview_synth, kickoff_intake, drive_sync, agent_session
pending: (none currently)
This COVERAGE constant is the route's own honesty check on itself — it spans web routes, Edge
Functions, and the CMA/Opus agent, and agent_session is explicitly noted as best-effort,
reconstructed from session events rather than a first-class logged call.
Where the code lives
sable-agents-demo/web/api/users.jssable-agents-demo/web/api/environment.js,_environment.jssable-agents-demo/web/api/admin-costs.jssable-agents-demo/web/api/_usage.js,_pricing.js— theai_usageledger this route reads