# What a call costs

A live call is billed on audio tokens, which cost about four times the same model's text rate on input and roughly 2.7 times on output. Metering is therefore split by modality rather than totalled: `usage_summary` reads the audio and text counts the SDK actually reports. A call that reports no tokens is charged from its own duration at the per-minute rate, never at zero.

- **Status:** Available
- **Audience:** both
- **Channels:** phone
- **In the app:** #/usage, #/calls
- **Last verified:** 2026-09-10
- **Canonical:** https://connectbyjbrh.com/docs/phone/voice-cost/

## Why modality is the unit

On a text channel, a token is a token and a total is enough. On a voice call it is not: the same model charges very differently for audio than for text, and a call carries both — the caller's speech and the model's reply as audio, the brief and the mid-call notes as text.

| Stream | Relative cost | What produces it |
|---|---|---|
| Audio in | About four times the model's text input rate | Everything the caller says |
| Audio out | Roughly 2.7 times the model's text output rate | Everything the voice says |
| Text in | The model's text input rate | The brief, knowledge, memory, notes, supervisor guidance |
| Text out | The model's text output rate | Reasoning and tool arguments |

Multiply a total by any single rate and the answer is wrong by a factor that depends on how talkative the caller was. `brief.usage_summary` therefore reads the breakdown the SDK reports — `input_audio_tokens`, `input_text_tokens`, `output_reasoning_tokens`, `session_duration` — and prices each stream at its own rate.

## The field that did not exist

There is no `input_audio_duration` in that breakdown. An earlier version of the metering looked for one, found nothing, and recorded **0.0 seconds** of audio for every call it ever metered — a number that is wrong in a way nothing complains about, because zero is a perfectly valid duration and every dashboard drew it happily.

> **Careful** A metering bug does not announce itself. The only reliable check is to read what the provider's own report actually contains rather than what a plausible field name suggests it should, and to treat an impossible figure — every call costing exactly nothing — as a fault rather than as good news.

## Every session a call held

A call is not always one model session. A session that refuses to start is opened again on the same model and once on the fallback; a session the server ends with a `go_away` is resumed carrying the conversation. Each of those is a separate usage report.

`merge_usage` adds them all. Before it did, a restarted call billed only the surviving session — so precisely the calls that had gone wrong, and therefore cost the most, were the calls that were under-charged. The record shows `model_session_restarted` when this happened, which is also the fastest way to see whether a line is quietly restarting sessions.

## The context you pay for again every turn

A Live session is re-billed for its entire context on every turn. That single sentence explains most of a voice bill: measured across production calls, **92% of input tokens are carried context** rather than anything new the caller just said.

It also explains why the prompt budgets are as tight as they are. A thousand extra characters in a behaviour block is not a thousand characters once — it is a thousand characters on every turn of every call for as long as that profile is in use, and it slows first tokens as well.

Context compression is *sized* rather than switched on by default: `COMPRESSION_TRIGGER_TOKENS` and `_TARGET_TOKENS` decide when a sliding-window compression happens and what it compresses to. The default trigger is the model's whole context window, which means a call that never gets near it is never compressed — set the numbers deliberately if you run long calls.

## A call that reports nothing

Some calls end with no usage report at all — a session that died, a provider that answered nothing useful, a browser call with no worker behind it. Those calls are charged from their own duration at the published per-minute rate.

Charging them at zero would be the easy behaviour and the wrong one: the calls that fail to report are disproportionately the calls that went wrong, and a cost model that quietly forgives them tells a business its worst calls are free. The stale-call sweep works the same way — it charges what it closes.

## Where to read the numbers

`GET /api/usage/voice` is the per-call profiler. Like the rest of the ledger it is available to the platform operator rather than to a customer workspace, and it reports what was measured and states what was **not** measured instead of filling the gap with an estimate. A blank beside a figure means nobody knows, which is more useful than a confident number that came from arithmetic rather than from the wire.

On the call record itself, cost is stored in minor units alongside the provider's status, the ring and answer times and the quality snapshot, so a call's price sits next to the evidence for how it went.

## Questions

### Why is a short call sometimes more expensive than a longer one?

Because context, not duration, drives most of the input cost. A short call on a line with a large brief and a full knowledge block re-bills all of it on every turn, while a longer call on a lean profile carries less each time. Shrinking the brief is usually the biggest single lever.

### Does a silent call cost anything?

Yes. A call that connected and reported no tokens is charged from its duration, and a row left active is charged by the sweep when it closes. The only calls that cost nothing are the ones that were refused before anything was opened.

### Can a customer workspace see its own per-call cost profile?

The detailed profiler is operator-only. A customer workspace sees its usage through the ordinary usage surfaces rather than the per-call ledger — the same split that applies to every other cost in the platform.

## Related

- [The budget that stops a call](https://connectbyjbrh.com/docs/phone/voice-budget/)
- [Stuck calls and the sweep](https://connectbyjbrh.com/docs/phone/stuck-calls/)
- [Session limits and long calls](https://connectbyjbrh.com/docs/phone/session-limits/)
- [The call record](https://connectbyjbrh.com/docs/phone/call-record/)
- [Telling the voice how to speak](https://connectbyjbrh.com/docs/phone/speaking-guide/)
- [What every character of a prompt costs on a live call](https://connectbyjbrh.com/research/prompt-size-and-first-token/)

## What this page is based on

- Connect phone source pack — `docs-source/sources/PHONE.md` §4, cost and what stops a call
- Connect phone source pack — `docs-source/sources/PHONE.md` §9, session restarts and compression
- Connect capability registry — `docs-source/facts.py` (`voice_cost_metering`, `MEASURED`)
