---
title: "Get Admin Stats"
method: GET
path: "/admin/stats"
tags: ["admin-stats"]
---

# Get Admin Stats

`GET /admin/stats`

## Request

- Base URL: `https://app.zeno-works.ch` (the document declares no server; this is the origin it was published from)
- URL: `https://app.zeno-works.ch/admin/stats`
- Auth: none declared

Platform-wide counters for the admin bar (admin).

Gated by ``AdminUserInSession`` rather than ``AdminUser``: the bar is chrome that polls
this every 60 seconds on every admin page, and ``require_admin`` refuses support
sessions — so under the ordinary gate an operator inside a customer's tenant got a 403
and an error toast every minute for the whole visit, from the surface meant to orient
them. These are platform-wide aggregates with no tenant detail, which is why widening
the gate here costs nothing an operator could not already see.

Users, companies, held AI decisions and token spend — the four numbers the bar shows,
plus untriaged client errors and whether the published FX feed is still landing
(ZET-203; the bar renders that one only when it is behind, because a healthy feed is
not news). Every count is bounded, and all but one are indexed — the FX freshness check
filters `fx_rate.valid_from` alone, which no index on that table serves because every
one of them leads with `currency`, so it is a scan. Deliberate: the table holds ~72 rows
a month, and the index that exists is shaped for the hot path instead (the coder's
per-document `(currency, date)` lookup). The result is
cached per worker process for 90 seconds — longer than the bar's 60s poll, so
consecutive polls landing on the same worker coalesce. The api runs ten workers, so
counters can differ by up to that TTL between requests; they are advisory, and a shared
cache was judged new infrastructure for a number nobody acts on inside a minute.

Three numbers carry a correction worth knowing when you read them: admins are counted
separately from users (the platform creates its own admin rows on boot), demo tenants
are separated from real ones (nothing else distinguishes the e2e seed from a customer),
and held decisions are split from rows the coder could not run at all — the second is an
outage detector, not a review queue, and summing them reports an LLM outage as customer
work.

## Headers

- `authorization` string, nullable

## Cookies

- `access_token` string, nullable

## Response `200`

Successful Response

- AdminStatsOut
  - `as_of` string, date-time, required
  - `window_start` string, date-time, required
  - `users` UserCounts, required
    - `active` integer, required
    - `admins` integer, required
    - `inactive` integer, required
  - `companies` CompanyCounts, required
    - `active` integer, required
    - `demo` integer, required
    - `inactive` integer, required
  - `held_decisions` HeldCounts, required
    - `awaiting_review` integer, required
    - `could_not_code` integer, required
  - `tokens` TokenCounts, required
    - `window` integer, required
    - `onboarding` integer, required
    - `platform` integer, required
  - `new_client_errors` integer, required
  - `fx_rates` FxRateFreshness, required: Is the published FX feed still landing? (ZET-203) The only question an operator has about ``fx_rate``. It is on the admin bar rather than on a page because the failure it reports is **silent and sticky**: nothing fetches a rate on the coding path, so if the orchestrator's daily job dies or the feed reshapes, the sole evidence is a log line while every foreign-currency document holds — and a held decision does not heal when the rate finally lands, it costs an LLM coding to release. A surface nobody opens would not have caught that; chrome on every admin page does.
    - `latest_month` string, date, nullable, required
    - `behind` boolean, required
    - `spot_latest_date` string, date, nullable
    - `spot_behind` boolean

## Other responses

- `422`: Validation Error

---

[API](https://skmtc.dev/zeno-works/apis/zeno-api.md) · [All operations](https://skmtc.dev/zeno-works/apis/zeno-api/llms.txt) · [OpenAPI document](https://skmtc.dev/zeno-works/apis/zeno-api/revisions/1eb93dde146c?raw)
