The insights rollup model
The Insights pages — LLM spend, call attribution, conversation P&L, containment and ROI, no-match mining, anomaly insights, language quality — look like ten different dashboards, but they share one design: every one of them is a read-time rollup over stores the platform already maintains. This page is the mental model behind the family: where the numbers come from, and why they come from public scope in one case and tenant scope in the rest.No new tables, ever
Each insights surface is only a query. The call-attribution header states the rule for the whole family: “no new table, no migration, and NO change to the write path.” The write paths stay exactly the write paths the product already has — the voice SIP webhook and call ledger, the message ledger, the LLM cost ledger, the agent runtime — and insights reads aggregate them after the fact. That design has three consequences worth knowing:- History is free. A new insights surface answers questions about events that happened before the surface existed, because it reads the same stores the product already wrote to.
- The write path never waits for analytics. Nothing on the insights side inserts, updates, or blocks a send, a call, or an agent turn — the read-replica separation invariant holds here exactly as it does for the Analytics API.
- Config is the only mutation. The few writable knobs (budget caps, ROI rubric values, labour rates) live in your organization’s settings, not in a new schema object.
The public-scope vs tenant-scope split
There is exactly one public-scope store in the family: the LLM cost ledger. LLM spend is vendor cost — what Devotel pays the model provider and what your organization is billed per call. That ledger records every call with its model, token counts, channel (“voice”, “sms”, “inbox”, “kb”, and so on), actual cost, and billed cost, and it records them indexed by organization, in public scope. The rationale is operational: the daily reconciler that compares the ledger against the provider’s billing can stay a single query instead of fanning out across every tenant schema. The ledger is org-scoped inside public scope — your reads still only ever return your own organization’s rows. Everything else in the family reads tenant-scoped stores: the per-tenant conversation, message, and call tables under tenant isolation. Containment, ROI, conversation P&L, call attribution, no-match mining, and language quality all aggregate the tenant schema — because those surfaces read your conversations and calls, and your conversations and calls live in your tenant schema, full stop.The surface map
Every monetary figure in the family is integer cents end to end, with
one rounding boundary at the render layer — the same convention the
wallets and credits model uses.
Worked example: one tracking-DID call rolling up to a campaign
You assign the tracking number+1-415-555-0132 to a pool labelled
“Paid search — Q3”, bound to source google, medium cpc, and
campaign q3-brand. A customer sees the ad, dials the number, talks
for 6 minutes, and hangs up answered.
At read time, call attribution:
- Loads your tracking pools and builds the map
+1-415-555-0132 → { source: "google", medium: "cpc", campaign: "q3-brand" }. - Aggregates inbound call logs whose dialled number is one of your tracking DIDs, per DID, over the window.
- Rolls the per-DID rows up by source + campaign.
Cost stays out of this surface on purpose: call attribution is a
volume-and-outcome view. Revenue attribution lives with the CDP
revenue-attribution analytics, so the two surfaces’ numbers line up
by window, not by ledger.
What integrators branch on
Read-time derivations versus stored rollups. The insights family derives at read time, as described above — there is no stored insights aggregate to drift out of sync and no backfill to run. When you compare an insights figure against an analytics pipeline figure, expect the pipeline’s number to be the same count served from a pre-aggregated bucket for the chart-friendly hour/day widths; a live-read insights surface may resolve the last minute slightly fresher at a narrow window. Reconciling against the billing ledger. The insights numbers are attribution and unit-economics numbers; the billing ledger is what you were charged. They deliberately disagree in two places:- LLM spend versus billing. The ledger records both actual cost (what the provider charges) and billed cost (what you’re charged) per call. Insights reads the ledger the same way billing does, but P&L and ROI blend that cost with telco and human handle-time — a P&L “cost to serve” is by design larger than the LLM line on your bill.
- Projections. The month-end projection on LLM spend is a forecast (last-7-day average × days left), not a stored ledger row — treat it as guidance, reconcile only the month-to-date.
null, not 0. Branch on null in your
integrations rather than coercing it.
Where to go next
- Analytics pipeline — the event spine and background roll-up producers behind the time-series analytics endpoints.
- Conversation intelligence — the per-conversation sentiment, topic, and quality signals several insights surfaces consume.
- Tenant isolation — why conversation rollups stay tenant-scoped.
- Insights API reference — endpoint shapes for every surface.
- Guides: LLM spend dashboard, Insights dashboards, Dashboard builder, Topic intelligence.