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. The
sibling 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/flowseach power one workspace’s aggregate counters. - Operational health —
GET /stats/gateway/smsrenders the SMS workspace’s gateway availability card (status verdict, latency, rolling-24h counts);GET /stats/request-logsbacks the Developer → Request Logs viewer (request-level drill-down, not an aggregate at all). - Conversation intelligence —
GET /stats/conversation-intelligencepowers the Conversation Intelligence page (sentiment, leaderboard, volume over a trailing window).
/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-logsthat 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 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 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 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
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 — it covers
the WHEN; this page is the WHERE.
See also
- Operator observability map — which surface to open for which question class
- Analytics pipeline — the read-replica invariant, scope and rate limit, and roll-up producers
- Usage metering pipeline — the event source both surfaces project from
- Insights rollup model — the AI-cost and benchmark aggregates the Insights family serves
- Export families model — the durable-record alternatives to polling