Skip to main content

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. The PUT 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

Returns the typed ApiResponse envelope. See the SDK index at SDK quickstart.

Conventions

These apply to every endpoint below.
  • Money is always integer cents. Fields ending in _cents are whole cents in the org’s wallet currency (returned as currency, e.g. USD). The API never converts to dollars or applies FX — format on the client.
  • Time ranges use from and to as ISO 8601 timestamps with an offset (e.g. 2026-06-01T00:00:00Z). from must be earlier than to, 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 the data payload.
  • Invalid query parameters return 422 with a details.issues array naming the offending field and a message.

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_percentagenull when no daily_cap_cents is 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_centsnull when 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_percentnull when 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.
Group by model — which model tier is the cost driver; useful before you swap providers or negotiate routing.
Group by 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.
Hourly buckets — spot an intra-day spike (a runaway agent loop, a launch). 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:
Then GET to echo the saved state:

Agent ROI

Attributes outcome revenue to each agent and reports cost, attributed revenue, and margin.
A negative 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:
Attribution is driven by a value-per-outcome config. 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.
Containment asks “did this conversation stay with the agent?”; resolution asks “did it reach a resolved status or pass a rubric outcome?”. Promote on both, not just the first.

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.
Each agent row carries 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”.
AI volume is raw tokens (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:
  1. GET /api/v1/insights/llm-spend/overview → take month_to_date.spend_cents (your AI run-cost).
  2. GET /api/v1/insights/agent-roi → sum totals.attributed_revenue_cents over the same window.
  3. Compute margin: attributed_revenue_cents - spend_cents, and margin % as ratio of revenue.
Python
Cost and containment settings are tenant-owned: they apply only inside your organization and are never shared across customers.

See also

  • Analytics API — message-traffic analytics, deliverability, and scheduled reports
  • Billing API — wallet, usage, and invoices