---
title: "Get Workspace Metrics"
method: GET
path: "/analytics/workspace-metrics"
tags: ["analytics"]
---

# Get Workspace Metrics

`GET /analytics/workspace-metrics`

Return KPI metrics for the monitoring page.

Aggregates inference rows over the selected ``window`` and the immediately
preceding window of equal length (for trend deltas), plus an all-time count
for the caption. ``scope`` selects per-user vs active-team aggregation; the
service explicitly filters ``inferences``/``requests`` by ``user_id`` or
``team_id`` — the ``service_role`` async engine bypasses Postgres RLS, so
RLS cannot be relied on for tenant isolation.

Args:
    window: Rolling window key driven by the monitoring page picker.
    scope: ``personal`` (per-user) or ``team`` (active team) aggregation.
    auth: Authentication result carrying the user id used to scope
        every aggregate.

Returns:
    ``WorkspaceMetrics`` populated with current / previous / all-time
    counts, p99 / median latency, spend, and the open-issue tally. For
    ``window='all'`` the previous-window aggregates run against the same
    unbounded all-time range, so each ``*_previous`` field equals its
    current counterpart.

## Query parameters

- `window` '24h' | '7d' | '30d' | '90d' | 'all' — Rolling window for the KPI rollup, used only when ``since`` is omitted. ``24h``/``7d``/``30d``/``90d`` produce a current window of that length plus a previous window of equal length for trend deltas. ``all`` runs both the current and previous aggregates against the unbounded all-time window.
- `scope` 'personal' | 'team' — ``personal`` aggregates the requesting user's inferences; ``team`` aggregates the user's active team (every member sees the same totals). A ``team`` request from a user with no team degrades to personal scope rather than erroring.
- `since` string, date-time, nullable — Inclusive start of an explicit custom window (UTC). When provided it overrides ``window``; the previous window is the immediately preceding window of equal length.
- `until` string, date-time, nullable — Exclusive end of the explicit window (UTC). Defaults to now.

## Response `200`

Successful Response

- WorkspaceMetrics — Workspace-wide metrics for the monitoring page KPI grid. Aggregates inference rows over a rolling window selected by the caller (``window``), scoped by ``scope``: ``personal`` filters by the requesting user, ``team`` filters by the user's active team (every member sees the same totals). The previous-window fields are computed against the immediately preceding window of equal length so the UI can render trend deltas; for ``window="all"`` both windows are unbounded so each ``*_previous`` field equals its current counterpart and the UI hides the resulting zero deltas. ``inference_count_all_time`` is independent of the window. Scoping is applied as an explicit ``user_id`` / ``team_id`` predicate, not via RLS — the ``service_role`` async engine bypasses Postgres RLS.
  - `scope` 'personal' | 'team' — Echo of the scope used to compute the rollup. ``personal`` aggregates the requesting user's inferences; ``team`` aggregates the user's active team.
  - `window` '24h' | '7d' | '30d' | '90d' | 'all' — Echo of the rolling window used to compute the rollup. One of ``24h``, ``7d``, ``30d``, ``90d``, ``all``.
  - `inference_count` integer — Number of inference rows in the selected window for the team.
  - `inference_count_previous` integer, nullable — Inference count for the window immediately preceding the current one (equal length). For ``window='all'`` both windows are unbounded, so this equals ``inference_count``. Drives the trend arrow.
  - `inference_count_all_time` integer, nullable — All-time inference count for the team with no time window.
  - `error_count` integer — Inferences in the selected window with status = 'failed'.
  - `avg_latency_ms` number, nullable — Average end-to-end latency over the selected window, or null when no latency was recorded.
  - `avg_ttft_ms` number, nullable — Average streaming time to first visible output chunk over the selected window, or null when no TTFT was recorded.
  - `p99_latency_ms` number, nullable — p99 E2E latency in milliseconds over the selected window, computed via ``percentile_cont(0.99) WITHIN GROUP (ORDER BY latency_ms)``.
  - `median_latency_ms` number, nullable — Median (p50) E2E latency in milliseconds over the selected window.
  - `p99_ttft_ms` number, nullable — p99 streaming TTFT in milliseconds over the selected window.
  - `median_ttft_ms` number, nullable — Median (p50) streaming TTFT in milliseconds over the selected window.
  - `p99_ttft_ms_previous` number, nullable — p99 streaming TTFT for the preceding window of equal length.
  - `p99_latency_ms_previous` number, nullable — p99 E2E latency for the preceding window of equal length. For ``window='all'`` both windows are unbounded, so this equals ``p99_latency_ms``. Drives the E2E latency trend arrow on the KPI grid.
  - `spend_usd` number, nullable — Workspace spend in USD over the selected window, summed across all models the team called. Null when pricing is unavailable for every called model.
  - `spend_previous_usd` number, nullable — Workspace spend for the preceding window of equal length. For ``window='all'`` both windows are unbounded, so this equals ``spend_usd``.
  - `spend_per_1k_calls_usd` number, nullable — Average cost per 1,000 inferences over the selected window.
  - `open_issue_count` integer, nullable — Count of inferences in the selected window where ``llmaj_verdict = 'incorrect'`` OR ``human_verdict = 'incorrect'``.
  - `last_inference_at` string, date-time, nullable — Most recent inference ``created_at`` observed in the selected window, or null.

## Other responses

- `422` — Validation Error
- `503` — Workspace metrics dependency is temporarily unavailable.

---

[API](https://skmtc.net/pioneer/apis/brain-api.md) · [All operations](https://skmtc.net/pioneer/apis/brain-api/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/pioneer/brain-api/versions/31dfe831e079/schema)
