Insights API
Operator-facing analytics for your AI agents: how much they cost to run (LLM spend), the revenue they attribute and the margin they return (ROI), how often they resolve a conversation without a human (containment), and how each agent ranks against the rest of your org (comparison & benchmarks). These are read dashboards. They’re served from a database read-replica, so they’re cheap to call but lag the primary by 1-3 seconds. ThePUT endpoints (budget, ROI config, and cost-economics rates) write to the primary and are read-back consistent.
Base path: /api/v1/insights
Authentication: API key (X-API-Key) or session JWT. Every request is scoped to the caller’s organization; you only ever see your own tenant’s data.
Using the SDKs
ApiResponse envelope. See the SDK index at SDK quickstart.
Conventions
These apply to every endpoint below.- Money is always integer cents. Fields ending in
_centsare whole cents in the org’s wallet currency (returned ascurrency, e.g.USD). The API never converts to dollars or applies FX — format on the client. - Time ranges use
fromandtoas ISO 8601 timestamps with an offset (e.g.2026-06-01T00:00:00Z).frommust be earlier thanto, and the window may not exceed 365 days. Omit both to default to the last 30 days ending now; pass only one and the other is backfilled to a 30-day window. - Timezone-aware buckets. Day/month boundaries are computed in the org’s billing timezone (returned as
timezone), not UTC, so a cap or trend lines up with your local day. - Envelope. Responses are wrapped as
{ "data": { … }, "meta": { "request_id": "…", "timestamp": "…" } }. The shapes below show thedatapayload. - Invalid query parameters return
422with adetails.issuesarray naming the offendingfieldand amessage.
LLM spend
Track how much your AI agents are spending on model calls, where it’s going, and whether you’re on track against a budget.Overview
GET /api/v1/insights/llm-spend/overview takes no parameters. It’s the baseline header-stat call: today’s spend, month-to-date spend with a month-end projection and a vs-previous-period delta, the trailing 7-day spend, and how much of the configured daily cap is used.
Three fields intentionally turn null instead of zero — read them as “not computable here”, not “zero”:
today.cap_percentage—nullwhen nodaily_cap_centsis set in the budget config. Set a cap (see Budget) before you wire an alert on it, or the comparison is meaningless.month_to_date.projected_month_end_cents—nullwhen there’s no historic spend pace to project from (typically on day 1 of a brand-new org’s first month).month_to_date.vs_last_period_percent—nullwhen the previous comparable period had no recorded spend to compare against.
Summary
GET /api/v1/insights/llm-spend/summary groups spend over a window.
The response always carries
totals for the whole window plus a groups array ordered by cost descending. Row shape depends on groupBy:
Group by agent — the default. Which agent is driving spend.
model — which model tier is the cost driver; useful before you swap providers or negotiate routing.
conversation — the single most expensive threads; same leaderboard as top-conversations but over an explicit window.
Timeseries
GET /api/v1/insights/llm-spend/timeseries buckets spend over time.
Returns a
series array of { bucket, total_tokens, total_cost_cents } ordered ascending. Hour granularity is capped at a 14-day window — use granularity=day for longer ranges, or you’ll get a 422.
Daily buckets — the default dashboard trend.
bucket carries the full hourly timestamp instead of a date.
Top conversations
GET /api/v1/insights/llm-spend/top-conversations returns the most expensive threads in a window, for drill-down.
By feature
GET /api/v1/insights/llm-spend/by-feature accepts from and to. It aggregates spend by AI feature/channel (e.g. voice, sms, inbox, kb; events with no channel attributed appear as unknown) so you can see which feature is driving cost. It also returns the current budget config and any threshold_breaches — channels that have crossed their configured per-channel cap.
Budget
GET /api/v1/insights/llm-spend/budget returns the current AI budget config. PUT updates it. All body fields are optional — omitted fields keep their current value (read-merge-write), and the server re-validates on write, so out-of-range values are dropped rather than persisted.
PUT a settings body:
Agent ROI
Attributes outcome revenue to each agent and reports cost, attributed revenue, and margin.margin_cents means the agent runs at a loss for the window; margin_percent is null when attributed revenue is zero. totals.truncated is true when more agents than your limit had traffic — raise limit (max 200) or treat the page as a preview.
GET /agent-roi/timeseries accepts from, to, and an optional agentId to scope the trend to a single agent:
PUT /agent-roi/config is a read-merge-write with two optional fields:
Containment & resolution
Reports how often agents handle a conversation without a human handoff (containment), how often a conversation reaches a resolved status or passes a rubric outcome (resolution), and how often it escalates.GET /containment accepts from, to, and limit (default 50, max 200). GET /containment/timeseries accepts from, to, and an optional agentId.
Agent comparison & benchmarks
Ranks agents against each other and against the org baseline on the KPIs already computed above (cost, attributed revenue, margin, containment, resolution, escalation).agent-comparison needs at least two ids; the response adds the full-org org_average row, the KPI metric catalogue (key, label, unit, higherIsBetter), and population-safety flags (population_size, ranked_population_size, population_truncated). When population_truncated is true, the averages and badges reflect the top-by-traffic subset, not every agent.
agent_id, agent_name, model, conversation_count, cost_cents, attributed_revenue_cents, margin_cents, margin_percent, containment_rate, resolution_rate, and escalation_rate. Rate fields are 1-decimal percentages or null when the denominator is zero; unknown ids are silently dropped, so diff the returned rows against the ids you sent.
agent-benchmarks ranks every agent with traffic across percentile bands:
Cost economics
One cross-channel view of what usage costs and what each unit costs you. It prices per-message (SMS, WhatsApp), per-minute (voice, video), and per-1,000-token (AI) usage at configurable rates, then rolls everything into per-channel cost, a per-channel per-unit cost, and blended totals. Use it to compare unit economics across channels instead of reading each channel’s ledger on its own.GET /cost-economics accepts from and to (defaults to the last 30 days, capped at 365). The response carries the current config, the applied rates (your configured values, or the platform defaults where you haven’t set one), a channels array with one row per channel (channel, volume, cost_cents, per_unit_cost_cents), and totals (cost_cents, message_volume, voice_minutes, ai_tokens). per_unit_cost_cents is null when the channel had zero volume in the window — read it as “no usage”, not “free”.
volume), priced per 1,000 tokens (ai_per_1000_tokens_cents). totals.message_volume sums SMS + WhatsApp messages, totals.voice_minutes sums voice + video minutes, and totals.ai_tokens reports AI volume separately since its basis differs.
PUT /cost-economics/config is a read-merge-write: every field is optional and keeps its current value when omitted; an explicit null resets that rate back to the platform default. Values are integer cents, minimum 0, maximum 100,000,000,000.
Compute LLM margin
One line of math joins the ROI rollup to the LLM-spend tracker: revenue minus model spend. Three steps:GET /api/v1/insights/llm-spend/overview→ takemonth_to_date.spend_cents(your AI run-cost).GET /api/v1/insights/agent-roi→ sumtotals.attributed_revenue_centsover the same window.- Compute margin:
attributed_revenue_cents - spend_cents, and margin % as ratio of revenue.
Python
See also
- Analytics API — message-traffic analytics, deliverability, and scheduled reports
- Billing API — wallet, usage, and invoices