Skip to main content

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.js
  • sable-agents-demo/web/api/environment.js, _environment.js
  • sable-agents-demo/web/api/admin-costs.js
  • sable-agents-demo/web/api/_usage.js, _pricing.js — the ai_usage ledger this route reads