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

# Compose a voice engine

> Name the speech-to-text, language and text-to-speech models yourself, and what that costs.

An agent's `voice` takes one of two shapes: a **composed** pipeline of three
named models, or one **realtime** model that does the whole conversation. This
page is about the first. For the shapes themselves, see
[Voice engines](/voice-engines).

## The shape

```json theme={null}
"voice": {
  "stt": { "model": "deepgram/nova-3", "language": "en-US" },
  "llm": { "model": "openrouter/gpt-4o-mini", "temperature": 0.7 },
  "tts": { "model": "elevenlabs/eleven_turbo_v2_5", "voice": "21m00Tcm4TlvDq8ikWAM" }
}
```

Every model is a `provider/model` pair. All three stages are required:
a pipeline missing one cannot hold a conversation, and defaulting it would
silently bill you for a model you never chose.

## Which models you can name

Only models in the price book. The book is the meter's source of truth, so
"no price, no call" is enforced when the agent is created — not on the first
call, where the failure would land on your customer. Name something unpriced
and the answer is a `400` that lists what is available for that stage:

```json theme={null}
{
  "error": {
    "type": "invalid_request_error",
    "code": "unsupported_model",
    "message": "No pricing for acme/whisper-9. Available for stt: deepgram/nova-3, deepgram/nova-3-multilingual, sarvam/saaras-v3-realtime.",
    "param": "voice"
  }
}
```

The live list is [`GET /v1/engines`](/api-reference/engines): each engine
carries its `models`, with the unit each is billed in and the price per unit.
Prefer it to hardcoding ids — a model whose provider is degraded disappears
from that list before your calls start failing.

| Stage          | Model                               | Family   | Price                            | ≈ per minute |
| -------------- | ----------------------------------- | -------- | -------------------------------- | ------------ |
| Language model | `openrouter/gpt-4o-mini`            | classic  | \$0.0002 per 1k tokens in        | \$0.0005     |
| Language model | `openrouter/gpt-4o-mini`            | classic  | \$0.0008 per 1k tokens out       | \$0.0004     |
| Language model | `sarvam/sarvam-105b`                | sarvam   | \$0.0004 per 1k tokens in        | \$0.0011     |
| Language model | `sarvam/sarvam-105b`                | sarvam   | \$0.0011 per 1k tokens out       | \$0.0005     |
| Realtime       | `deepgram/agent`                    | realtime | \$0.0018 per second              | \$0.1050     |
| Realtime       | `google/gemini-live`                | realtime | \$0.0042 per 1k audio tokens in  | \$0.0063     |
| Realtime       | `google/gemini-live`                | realtime | \$0.0168 per 1k audio tokens out | \$0.0252     |
| Realtime       | `google/gemini-live`                | realtime | \$0.0007 per 1k tokens in        | \$0.0017     |
| Realtime       | `google/gemini-live`                | realtime | \$0.0028 per 1k tokens out       | \$0.0013     |
| Speech-to-text | `deepgram/nova-3`                   | classic  | \$0.0002 per second              | \$0.0108     |
| Speech-to-text | `deepgram/nova-3-multilingual`      | classic  | \$0.0002 per second              | \$0.0129     |
| Speech-to-text | `sarvam/saaras-v3-realtime`         | sarvam   | \$0.0001 per second              | \$0.0076     |
| Text-to-speech | `elevenlabs/eleven_flash_v2_5`      | classic  | \$0.0700 per 1k characters       | \$0.0630     |
| Text-to-speech | `elevenlabs/eleven_multilingual_v2` | classic  | \$0.1400 per 1k characters       | \$0.1260     |
| Text-to-speech | `elevenlabs/eleven_turbo_v2_5`      | classic  | \$0.0700 per 1k characters       | \$0.0630     |
| Text-to-speech | `sarvam/bulbul-v3`                  | sarvam   | \$0.0457 per 1k characters       | \$0.0411     |

Per-minute figures assume 15 synthesised characters, 40 input tokens and 8 output tokens per second, and exclude the flat \$0.012 per minute platform fee. A language model is billed in two units, so its line appears twice.

## One family per pipeline

The three stages must come from the same **family**, because each family runs
on its own pipeline:

| Family    | Speech-to-text | Language model | Text-to-speech |
| --------- | -------------- | -------------- | -------------- |
| `classic` | `deepgram/…`   | `openrouter/…` | `elevenlabs/…` |
| `sarvam`  | `sarvam/…`     | `sarvam/…`     | `sarvam/…`     |

The `stt` provider decides which pipeline runs: a Deepgram model selects the
classic pipeline, a Sarvam model selects the Sarvam one. That pipeline then
runs its own family end to end. A `tts` from another family passes pricing
validation but is not what that pipeline speaks with, so keep all three
together.

## Variants and language

Within a family the pipeline picks the exact variant for the agent's
`language`: the classic pipeline uses ElevenLabs Turbo for English and Flash
for everything else, and Nova-3 in the matching language mode. What you are
billed is the model that actually ran, at its own rate — the estimate at
admission reserves for the dearest variant in the family, and the settle
charges for the one used.

## What it costs

A composed minute is the sum of its stages plus the flat platform fee, at
typical speech rates: 15 characters of synthesised speech, 40 input tokens
and 8 output tokens per second. Each stage is metered in its own unit —
seconds of audio, tokens, characters — every few seconds while the call is
live, so a quiet call costs less than the estimate and a talkative one more.

The [pricing page](https://phone.wixzel.com/pricing#compose) has a builder
that prices any mix and writes the JSON for it.

Prices are frozen when a call is admitted, so a change to the book never
moves a running meter. See [Credits](/credits) for how the balance works.

## Or hand the whole turn to one model

```json theme={null}
"voice": {
  "realtime": { "model": "google/gemini-live", "voice": "Charon" }
}
```

A realtime model replaces all three stages and is billed per token or per
second, depending on the provider. It cannot be combined with `stt` or `llm`;
the API refuses a config that names both.
