Repository navigation
[Admin][API] Usage & Spending — ledger, platform-paid vs BYOK, cost + AI kill switch #32
Copy link
Copy link
Closed
Labels
admin-portalPAGS admin/operator portalPAGS admin/operator portalenhancementNew feature or requestNew feature or request
Description
[Admin][API] Usage & Spending — aggregate ledger, platform-paid vs BYOK split, cost + AI kill switch
Why
The core operator concern. The platform currently pays for internal AI (PLATFORM_AI_ENABLED="true": embeddings + summaries + translation fallback) and that spend is invisible in-app. We need cross-user usage + a clear platform-paid vs BYOK cost split, and an operator control to cap/kill platform spend.
Scope
GET /v1/admin/usage(behindrequireAdmin): aggregate theai_usageledger across ALL users — group by provider, model,kind, user, agent/instance, and day. Return token totals andcost_microstotals with a time window (?days=).- Platform-paid vs BYOK split: classify each
ai_usagerow as platform-paid (internalkinds run onenv.AIwhenPLATFORM_AI_ENABLED— embeddings/summary/translation) vs BYOK (user's Anthropic/CF key). Since CF platform calls currently ledger atcost_micros≈0, add estimated cost via a neuron/token price table so platform spend is a real number, not zero. Document the estimate. GET /v1/admin/spending— top-line: total platform-paid $ (30d), total BYOK tokens (informational), top spenders, top models, trend series.- AI kill switch:
GET/PUT /v1/admin/settings/platform-aito read and toggle the effectivePLATFORM_AI_ENABLEDbehavior at runtime (e.g. aplatform_settingsrow overriding the env default), so the operator can turn platform-paid AI off without a redeploy. Off → embeddings/summaries/translation no-op (BYOK-only); note the known side effect that RAG goes dark until a BYOK-embedding path exists (track separately).
Acceptance criteria
-
/v1/admin/usageaggregates across all users with provider/model/kind/user/day breakdowns and correct totals. - Platform-paid vs BYOK split is correct and platform-paid rows carry a non-zero estimated cost.
-
/v1/admin/spendingreturns 30-day platform spend, top spenders/models, trend. - Toggling the AI kill switch changes runtime behavior (verified: with it off, an embed call no-ops) and writes an audit-log row.
- Non-admin → 403; tests for aggregation + gate + toggle.
Relevant code
- Ledger:
workers/api/src/lib/usage.ts(recordUsage→ai_usage, hascost_micros), migration0048_ai_usage.sql - Platform-AI gate:
agent-do.ts:72,routes/instances-translation.ts,wrangler.tomlPLATFORM_AI_ENABLED - Existing per-user view to reuse shapes:
routes/usage.ts
References
- PAS platform analytics endpoint pattern (
/v1/analytics/admin/platform). PAS has no usage/cost admin — this closes that gap for PAGS.
Part of the PAGS Admin Portal epic. Depends on Foundation. Directly addresses the "platform should not pay for AI" concern.
Best-practice hardening (2026-08-01)
- Authoritative spend = Cloudflare billing actuals, not only a token estimate. Platform-paid Workers AI is billed per neuron; our
ai_usage.cost_microsis ~0 for CF and the token→price table is a derived guess. Pull the real platform AI cost from Cloudflare's GraphQL Analytics / billing API (Workers AI usage) as the authoritative number for the "platform spend" headline. Keep the token estimate only for BYOK (where we genuinely can't see the provider bill) and label estimates as estimates in the API + UI so the two are never conflated. - Cache the CF billing pull (it's rate-limited + slow); expose
source: "cf-actuals" | "estimate"per figure.
Metadata
Metadata
Assignees
Labels
admin-portalPAGS admin/operator portalPAGS admin/operator portalenhancementNew feature or requestNew feature or request
Activity
feat(admin): cross-user usage + spending API (#32)
serge-ivo commentedon Aug 1, 2026
Done — landed on
mainas 0492b0b.feat(admin): admin SPA served at /admin (#29, #35)