Skip to main content

Read the unified cost-economics roll-up

GET /api/v1/insights/cost-economics answers one FinOps question across every channel at once: what does one unit actually cost us — per message, per minute, per 1,000 tokens? Until now each Insights slice answered a narrower version of that question (token spend, per-conversation P&L, per-agent margin). This surface is the roll-up a CX or operations leader opens first: five channels, one window, one per-unit ratio per channel, and the blended totals underneath. The behavior guide for the underlying per-channel numbers is Read the cost-intelligence dashboards. This guide covers the roll-up itself — what the endpoint returns, how to set the unit rates it prices with, and how to reconcile its volumes against your invoices.

1. What the surface answers

Channels bill on different units, which makes cross-channel cost comparisons hard to eyeball. The roll-up normalizes each channel onto its own billed unit:
  • Per message — SMS and WhatsApp. The volume is the sum of billed segments, not message rows: a 240-character SMS is two segments and prices as two units, the same basis a carrier invoice uses.
  • Per minute — voice and video. The volume is connected seconds rounded up to whole minutes — a 65-second call prices as two minutes, matching per-minute carrier increments. A call that never connected contributes zero.
  • Per 1,000 tokens — AI. The volume is raw tokens (input, output, and cached tokens), priced per thousand.
For each channel the response carries the volume in that unit, the cost in integer cents, and the per-unit ratio (cost ÷ volume) — so “is WhatsApp really five times SMS per message?” is one row read, not a spreadsheet. Cross-channel totals sit at the bottom. Access follows the standard Insights pattern: an authenticated session on your organization, org-scoped so no operator ever reads another workspace’s numbers. Two conventions to internalize before reading any number:
  • Money is integer cents end-to-end. cost_cents of 15234 is $152.34 in your org currency; the currency field on the response tells you which. Format with your org’s wallet currency.
  • The ratio is null, never 0, when the channel had no volume. A zero-traffic channel reports per_unit_cost_cents: null — render ”—”, not $0.00/unit. A null ratio means “nothing billed”, not “free”.

2. Reading GET /api/v1/insights/cost-economics

Both parameters are optional. Omit them and the window is the last 30 days ending now; pass only one side and the other backfills (30 days back from to, or up to now from from). A fromto is a 400, and the resolved window is capped at 365 days. The response arrives in the standard { data, meta } envelope. Under data: Per-channel rows — the unit semantics are the whole point: In totals, message_volume sums the two message channels (SMS + WhatsApp), voice_minutes sums the two minute channels (voice + video), and ai_tokens stands on its own. totals.cost_cents is the exact sum of the five channel cost_cents — sum the array and you must land on the total to the cent; that equality is the reconciliation check in §4. Because cost is volume × applied rate on each row, every row’s ratio reads back the applied rate for that channel (null on zero volume). The ratio column exists so you can sort five channels on one number without re-deriving the division.

3. Reading and setting rates — /cost-economics/config

The roll-up prices volumes with five per-unit rates, one per channel basis. Rates are tenant-owned: each workspace sets its own cost basis (what your carriers and model providers charge you), and unset dimensions fall back to platform reference rates. Nothing here changes what your wallet is billed; it changes the economics view you read. Read the current config:
The data block carries five nullable fields, all integer cents: Update any subset of them:
Update semantics — this is a read-merge-write, not a replace:
  • Omitted fields keep their current value. The example above touches WhatsApp and voice only; SMS, AI, and video are preserved.
  • An explicit null clears a field back to the platform reference rate, and the summary’s applied block drops back to it.
  • Values must be non-negative integer cents; a fractional or negative value is a 400.
  • The PUT response returns the merged, persisted config — read it back to confirm what your update actually resolved to.
The summary endpoint re-applies your config on every read, so retro-repricing a window is just a config change plus the same GET: set the rate your new carrier contract starts next month to, re-run the same 30-day window, and compare totals.cost_cents before and after.

Worked example — one WhatsApp campaign, one voice queue month

Price a WhatsApp campaign. Set the per-message cost your Meta billing runs at, then read the month the campaign sent:
If the campaign sent 120,000 messages, the WhatsApp row reads volume: 120000, cost_cents: 480000 ($4,800.00), per_unit_cost_cents: 4. Compare that 4¢ unit against the SMS row for the same window to decide the next campaign’s channel mix — that is the comparison this surface exists for. Price a voice queue month. Set your per-minute carriage cost, then read the queue’s month:
If the queue logged 41,200 connected seconds across 9,400 calls, the rounding rule makes the billed volume 41,200 seconds → per-call round-up → about 720 billed minutes beyond the raw division: volume is the per-call ceiling sum (say 735 minutes for a skewed call-length mix), cost_cents = volume × 2, and per_unit_cost_cents: 2. The round-up is deliberate — it matches the minute increments on your carrier invoice, so the volume here ties to the bill instead of to a wall-clock sum.

4. Mapping roll-ups to billed units — the reconciliation walkthrough

Finance’s question is always the same: does this view tie to the invoice? The roll-up is built to make that a two-minute check, because every volume convention above mirrors a billed-unit convention:
  1. Pick one window — say your billing month — and pull GET /api/v1/insights/cost-economics?from=<month start>&to=<month end>.
  2. Internal consistency: sum channels[].cost_cents; the result must equal totals.cost_cents to the cent. A mismatch means you compared different windows — re-check from/to in the response.
  3. SMS on the segment basis: SMS volume here is billed segments, so it matches the segment counters on the Billable usage records panel (GET /api/v1/messages/usage/records), not the billed-message headline on the Channel costs page. Do not “fix” the difference by filtering; Read the cost-intelligence dashboards explains the segments-versus-messages convention and the full dashboard-versus-API verification loop.
  4. Voice on the billed-minute basis: voice volume is per-call seconds rounded up — the same increments a carrier invoice lists. Compare against the voice records on the same usage-records export for the same window.
  5. Revenue side: the roll-up is a cost view, so map it against what you charged for the same traffic — your rate cards hold the sell-side unit prices, and Billing cost calculator walks the cost-versus-price margin arithmetic with your own volume mix.
When the applied rates in applied match your carrier and model-provider rates, totals.cost_cents is your expected cost line for the window before overheads.

5. Sample responses

GET /api/v1/insights/cost-economics?from=2026-08-01T00:00:00Z&to=2026-09-01T00:00:00Z — SMS, WhatsApp, voice, and AI carried traffic; video did not (note the null ratio):
Reading it: SMS priced 40,210 billed segments at the reference rate of 150¢ (60,315.00thedominantline,andtherowtointerrogate).WhatsAppusedtheconfigured4¢override.TheAIlineprices841,200tokensat10¢/1k(60,315.00 — the dominant line, and the row to interrogate). WhatsApp used the configured 4¢ override. The AI line prices 841,200 tokens at 10¢/1k (84.12); its per-unit ratio rounds to 0¢ per thousand tokens at cent granularity — read applied.ai_per_1000_tokens_cents for the actual rate when a ratio sits at zero on a low-rate channel. Video had no traffic, so its ratio is null. GET /api/v1/insights/cost-economics/config — one override set:
PUT /api/v1/insights/cost-economics/config — set WhatsApp, clear the SMS override, leave the rest untouched:
The response is the merged config — null on SMS means “reference rate applies”, and the three untouched fields kept their prior (unset) values.

See also