> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Read the unified cost-economics roll-up

> Operator guide to GET /api/v1/insights/cost-economics and its rate-config endpoints: per-message (SMS/WhatsApp), per-minute (voice/video), and per-1k-token (AI) unit economics rolled into one view, with per-channel breakdowns mapped to billed units for invoice reconciliation.

# 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](/guides/cost-intelligence). 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

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/insights/cost-economics?from=2026-08-01T00:00:00Z&to=2026-08-25T00:00:00Z" \
  -H "Authorization: Bearer $ORBIT_SESSION_TOKEN"
```

| Query parameter | Type              | Notes                                                               |
| --------------- | ----------------- | ------------------------------------------------------------------- |
| `from`          | ISO-8601 datetime | Inclusive window start. Optional — defaults to 30 days before `to`. |
| `to`            | ISO-8601 datetime | Exclusive window end. Optional — defaults to now.                   |

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 `from` ≥ `to` is a 400, and the resolved window is capped at 365 days.

The response arrives in the standard `{ data, meta }` envelope. Under `data`:

| Field        | Type              | Meaning                                                                                                                                                  |
| ------------ | ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `from`, `to` | ISO-8601 datetime | The resolved window, echoed back.                                                                                                                        |
| `currency`   | string            | Your org's billing currency (e.g. `USD`). Applied to every `_cents` field.                                                                               |
| `timezone`   | string            | Your org's timezone, echoed for alignment with other Insights surfaces.                                                                                  |
| `config`     | object            | The persisted rate overrides — five nullable fields (see §3).                                                                                            |
| `applied`    | object            | The five rates actually used: your override where set, else the platform reference rate. Cost figures come from `applied`, never from `config` directly. |
| `channels[]` | array             | One row per channel: `channel`, `volume`, `cost_cents`, `per_unit_cost_cents`.                                                                           |
| `totals`     | object            | Blended totals: `cost_cents`, `message_volume`, `voice_minutes`, `ai_tokens`.                                                                            |

Per-channel rows — the unit semantics are the whole point:

| `channel`  | `volume` unit                                | `cost_cents` =                             | `per_unit_cost_cents`  |
| ---------- | -------------------------------------------- | ------------------------------------------ | ---------------------- |
| `sms`      | billed segments                              | volume × applied SMS per-message rate      | cents per segment      |
| `whatsapp` | messages                                     | volume × applied WhatsApp per-message rate | cents per message      |
| `voice`    | billed minutes (per-call seconds rounded up) | minutes × applied per-minute rate          | cents per minute       |
| `video`    | room minutes (seconds rounded up)            | minutes × applied per-minute rate          | cents per minute       |
| `ai`       | raw tokens                                   | tokens ÷ 1,000 × applied per-1k-token rate | cents per 1,000 tokens |

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:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/insights/cost-economics/config" \
  -H "Authorization: Bearer $ORBIT_SESSION_TOKEN"
```

The `data` block carries five nullable fields, all integer cents:

| Field                        | Unit                    | `null` means                    |
| ---------------------------- | ----------------------- | ------------------------------- |
| `sms_per_message_cents`      | per billed SMS segment  | use the platform reference rate |
| `whatsapp_per_message_cents` | per WhatsApp message    | use the platform reference rate |
| `voice_per_minute_cents`     | per billed voice minute | use the platform reference rate |
| `ai_per_1000_tokens_cents`   | per 1,000 AI tokens     | use the platform reference rate |
| `video_per_minute_cents`     | per billed video minute | use the platform reference rate |

Update any subset of them:

```bash theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/insights/cost-economics/config" \
  -H "Authorization: Bearer $ORBIT_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"whatsapp_per_message_cents": 4, "voice_per_minute_cents": 3}'
```

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:

```bash theme={null}
curl -X PUT ".../api/v1/insights/cost-economics/config" \
  -H "Authorization: Bearer $ORBIT_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"whatsapp_per_message_cents": 4}'

curl ".../api/v1/insights/cost-economics?from=2026-08-01T00:00:00Z&to=2026-09-01T00:00:00Z" \
  -H "Authorization: Bearer $ORBIT_SESSION_TOKEN"
```

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:

```bash theme={null}
curl -X PUT ".../api/v1/insights/cost-economics/config" \
  -H "Authorization: Bearer $ORBIT_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"voice_per_minute_cents": 2}'
```

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](/guides/cost-intelligence) 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](/billing/rate-cards) hold the sell-side unit prices, and [Billing cost calculator](/guides/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):

```json theme={null}
{
  "data": {
    "from": "2026-08-01T00:00:00.000Z",
    "to": "2026-09-01T00:00:00.000Z",
    "currency": "USD",
    "timezone": "America/New_York",
    "config": {
      "sms_per_message_cents": null,
      "whatsapp_per_message_cents": 4,
      "voice_per_minute_cents": null,
      "ai_per_1000_tokens_cents": null,
      "video_per_minute_cents": null
    },
    "applied": {
      "sms_per_message_cents": 150,
      "whatsapp_per_message_cents": 4,
      "voice_per_minute_cents": 2,
      "ai_per_1000_tokens_cents": 10,
      "video_per_minute_cents": 9
    },
    "channels": [
      {
        "channel": "sms",
        "volume": 40210,
        "cost_cents": 6031500,
        "per_unit_cost_cents": 150
      },
      {
        "channel": "whatsapp",
        "volume": 120000,
        "cost_cents": 480000,
        "per_unit_cost_cents": 4
      },
      {
        "channel": "voice",
        "volume": 735,
        "cost_cents": 1470,
        "per_unit_cost_cents": 2
      },
      {
        "channel": "ai",
        "volume": 841200,
        "cost_cents": 8412,
        "per_unit_cost_cents": 0
      },
      {
        "channel": "video",
        "volume": 0,
        "cost_cents": 0,
        "per_unit_cost_cents": null
      }
    ],
    "totals": {
      "cost_cents": 6521382,
      "message_volume": 160210,
      "voice_minutes": 735,
      "ai_tokens": 841200
    }
  }
}
```

Reading it: SMS priced 40,210 billed segments at the reference rate of 150¢ ($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:

```json theme={null}
{
  "data": {
    "sms_per_message_cents": null,
    "whatsapp_per_message_cents": 4,
    "voice_per_minute_cents": null,
    "ai_per_1000_tokens_cents": null,
    "video_per_minute_cents": null
  }
}
```

**PUT /api/v1/insights/cost-economics/config** — set WhatsApp, clear the SMS override, leave the rest untouched:

```bash theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/insights/cost-economics/config" \
  -H "Authorization: Bearer $ORBIT_SESSION_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"whatsapp_per_message_cents": 5, "sms_per_message_cents": null}'
```

```json theme={null}
{
  "data": {
    "sms_per_message_cents": null,
    "whatsapp_per_message_cents": 5,
    "voice_per_minute_cents": null,
    "ai_per_1000_tokens_cents": null,
    "video_per_minute_cents": null
  }
}
```

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

* [Read the cost-intelligence dashboards](/guides/cost-intelligence) — the per-channel cost surfaces behind the roll-up, and the dashboard-versus-API verification loop
* [Insights API reference](/api-reference/insights) — endpoint shapes for the Insights surfaces
* [Rate cards](/billing/rate-cards) — the sell-side unit prices to map these costs against
* [Billing cost calculator](/guides/billing-cost-calculator) — cost-versus-price margin arithmetic on your own volume mix
* [Read the Channel costs page](/guides/insights-costs) — the console counterpart for per-channel spend
* [AI agent cost controls](/agents/cost-controls) — budgets and hard caps for the AI token leg
