> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# The stats surface map: dashboard workbench vs the analytics pipeline

> Where each dashboard number comes from: the /stats workbench (raw-event, per-widget reads), the /stats/analytics advanced block, and the pre-aggregated /api/v1/analytics pipeline — and which route family answers which question.

# The stats surface map: dashboard workbench vs the analytics pipeline

Devotel Orbit exposes two distinct read surfaces for "numbers on
screens," and they are built differently on purpose. The
**stats workbench** (`/api/v1/stats/…`) is a family of small,
per-widget reads that power the dashboard's overview cards, channel
health tiles, and workspace headers — computed from raw rows at request
time. The **analytics pipeline** (\`/api/v1/analytics/…) serves
pre-aggregated hourly series from the read replica, as described on
[the analytics pipeline concept](/concepts/analytics-pipeline). The
sibling [operator observability map](/concepts/operator-observability-map)
frames WHEN to open each surface; this page owns WHERE each number a
widget shows actually comes from, so you can predict which route family
answers your question before you write any code.

## 1. Where the dashboard workbench fits

Every number on the dashboard's home overview, workspace headers, and
channel tiles resolves to one route under `/api/v1/stats`:

* **`GET /stats/summary`** — the six home-overview cards (24-hour
  message volume, active agents, total contacts, 24-hour API calls,
  today's spend, success rate).
* **`GET /stats/channel-health`** — per-message-channel health tiles
  (SMS, WhatsApp, email, voice delivery quality).
* **`GET /stats/usage`** — the daily usage timeline chart across
  channels.
* **`GET /stats/activity`** — the recent-activity feed (messages,
  agent events, webhook deliveries, newest first).
* **`GET /stats/dashboard`** — all four above in one parallel-fetched
  payload; the home-overview page prefers this to four separate polls,
  and each leg shares cache keys with its individual sibling.
* **Workspace header cards** — `GET /stats/sms`, `/stats/whatsapp`,
  `/stats/voice`, `/stats/numbers`, `/stats/agents`,
  `/stats/contacts`, `/stats/flows` each power one workspace's
  aggregate counters.
* **Operational health** — `GET /stats/gateway/sms` renders the SMS
  workspace's gateway availability card (status verdict, latency,
  rolling-24h counts); `GET /stats/request-logs` backs the
  Developer → Request Logs viewer (request-level drill-down, not an
  aggregate at all).
* **Conversation intelligence** — `GET /stats/conversation-intelligence`
  powers the Conversation Intelligence page (sentiment, leaderboard,
  volume over a trailing window).

Two nested blocks sit under the same prefix:

* **`/stats/analytics/*`** — the advanced-analytics block (full payload,
  summary, channels, volume, delivery funnel) plus the carbon endpoints
  (`/stats/analytics/carbon`, `/stats/analytics/carbon/export`). The
  whole block is feature-flagged per tenant; without the
  advanced-analytics flag it returns 403.
* **The "always-on" subset** — `/summary`, `/channel-health`, `/usage`,
  `/activity`, `/dashboard`, `/request-logs` that degrade to a graceful
  zeroed or empty 200 when a transient dependency fails, so the polled
  home widgets render a fresh-tenant zero state instead of an error.
  The remaining reads pass through the standard tenant-schema gate.

## 2. Read-surface semantics: stats vs analytics

The two surfaces differ on three axes, and the difference decides which
one to call.

**Granularity of the question.** The stats controller computes raw-event
answers at request time — counts over the tenant's message, contact,
call, flow, and number tables for a short window (24 hours for the
summary cards, a bounded day range for the usage timeline). It is a
console over current rows: the right reach for "what is the dashboard
showing right now" and "how many agents do I have." The analytics
surface answers trend questions over pre-aggregated hourly buckets —
"how did delivery rate move over the last quarter" — and deliberately
accepts a 1–3 second replica lag in exchange for cheap, index-friendly
reads. Never answer a trend question by polling `/stats/usage` from your
own system; use `/api/v1/analytics` (or its scheduled reports).

**Consistency guarantees.** Stats reads run against the primary's
tenant schema and degrade to zeroed empties on transient failure —
a widget that must render something. Analytics reads hold the
read-replica invariant (reporting never competes with live traffic) and
are served from roll-ups when they exist. One aggregate can legitimately
disagree with the other for the lag window; the [operator
map](/concepts/operator-observability-map) covers which surface to trust
for which question class.

**Access and quotas.** API-key callers reach the stats workbench with
the `analytics:read` scope — the same scope the `/api/v1/analytics`
family enforces. Analytics endpoints run under a per-tenant analytics
rate limit (60 requests per minute); the stats family runs under the
general authenticated-read limit the dashboard's foreground polling
uses. The heavy `/stats/analytics/*` advanced block additionally
requires the per-tenant advanced-analytics flag.

## 3. The pipeline underneath both

Neither surface invents its numbers. The
[usage metering pipeline](/concepts/usage-metering-pipeline) is the
event source: every message, call, and billable action writes an
append-only usage record, and both the stats workbench's counters and
the analytics pipeline's hourly roll-ups are projections over the same
tenant schema. The
[analytics pipeline concept](/concepts/analytics-pipeline) covers the
read-replica invariant, the per-tenant scope and rate limit, and the
background producers that pre-aggregate the `/api/v1/analytics` series.
Because both surfaces share the source, a figure the dashboard
home-overview shows (stats) and the figure an Insights chart shows
(analytics roll-ups) count the same billed events — they differ only in
aggregation window and freshness.

## 4. Which route family answers which question

| Your question                                                     | Route family                                        | Primitive                                                                                                                                                       |
| ----------------------------------------------------------------- | --------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| "What do my dashboard's home cards say right now?"                | `/api/v1/stats` — `/summary`, `/dashboard`          | Raw-event counters over the last 24 hours, computed at request time, degrade-on-failure.                                                                        |
| "Is my SMS fleet delivering, or is the gateway degraded?"         | `/api/v1/stats` — `/channel-health`, `/gateway/sms` | Per-channel availability and delivery-quality verdicts.                                                                                                         |
| "What just happened in my workspace?"                             | `/api/v1/stats` — `/activity`                       | Newest-first raw events (messages, agent events, webhook deliveries).                                                                                           |
| "How is my traffic trending over days/weeks?"                     | `/api/v1/analytics`                                 | Pre-aggregated hourly/day buckets from the read replica; group\_by hour/day/week/month.                                                                         |
| "What are my AI agents costing and returning?"                    | `/api/v1/insights`                                  | LLM spend, ROI, containment, benchmarks — same replica discipline.                                                                                              |
| "Show me the full analytics workbench (funnel, geo, peak hours)." | `/api/v1/stats/analytics` (flagged)                 | Advanced payload: delivery funnel, channel/geo breakdown, peak hours — tenant flag required.                                                                    |
| "Hand me a durable record/chat archive."                          | Export + webhooks                                   | Signed [vCon export](/guides/conversation-export-vcon), [conversation archive](/guides/conversation-archive), [exports model](/concepts/export-families-model). |
| "Push events to my system as they happen."                        | [Webhooks](/webhooks/overview)                      | Durable, retried, signed delivery; drill into failures via `/webhooks/dlq`.                                                                                     |

The rule of thumb: **widget and workspace-header questions go to
`/stats`; trend and reporting questions go to `/analytics` or
`/insights`; durability goes to exports and webhooks.** When you cannot
tell which family a question belongs to, return to the [operator
observability map](/concepts/operator-observability-map) — it covers
the WHEN; this page is the WHERE.

## See also

* [Operator observability map](/concepts/operator-observability-map) —
  which surface to open for which question class
* [Analytics pipeline](/concepts/analytics-pipeline) — the read-replica
  invariant, scope and rate limit, and roll-up producers
* [Usage metering pipeline](/concepts/usage-metering-pipeline) — the
  event source both surfaces project from
* [Insights rollup model](/concepts/insights-rollup-model) — the AI-cost
  and benchmark aggregates the Insights family serves
* [Export families model](/concepts/export-families-model) — the
  durable-record alternatives to polling
