Skip to content

Latency tiers

Every request names a tier. The tier decides how much audio the encoder is allowed to look ahead before it commits to text, which is both the latency knob and the rate you are charged at. There is one model. The tier is a serving setting, not a different model.

Tier att_context_size Latency $/sec
ultra [70, 0] 80 ms 0.000139
turbo [70, 1] 160 ms 0.000100
standard [70, 6] 560 ms 0.000061
economy [70, 13] 1.12 s 0.000042

att_context_size is [left, right], in encoder frames. The left context is the same everywhere. The right context is the lookahead, and it is what you are paying for: less lookahead means the encoder does more work per second of audio to reach a decision sooner.

The latency column is the lookahead the tier imposes. It is a property of the context setting, not an end to end measurement of your request, which also includes network time and however long your own audio frames are.

Start from what is waiting on the text.

A person is waiting mid sentence. Live captions, a voice agent that has to respond in the gap after someone stops talking, an interpreter view. ultra or turbo.

A person is waiting for a whole utterance. Voice search, dictation into a field, a form filled by speaking. standard is usually indistinguishable from turbo here, and costs about 60% as much.

Nothing is waiting. Recorded calls, meeting archives, subtitle generation, anything you process in a queue. economy, always. Compared to ultra, it costs under a third.

If you are unsure, standard is the default for a reason.

Because the tier is per request, you do not have to pick once. A product can stream turbo for the live view and re-run the recording on economy overnight for the searchable archive.

Not every tier is servable on every deployment. Availability is reported by GET /v1/tiers, and that endpoint is the source of truth. Do not hardcode the list above as an assumption about what will work.

Terminal window
curl https://api.utter.cc/v1/tiers \
-H "Authorization: Bearer $UTTER_API_KEY"
{
"tiers": [
{
"tier": "ultra",
"att_context_size": [70, 0],
"latency_ms": 80,
"usd_per_second": "0.000139",
"available": true
},
{
"tier": "turbo",
"att_context_size": [70, 1],
"latency_ms": 160,
"usd_per_second": "0.000100",
"available": true
},
{
"tier": "standard",
"att_context_size": [70, 6],
"latency_ms": 560,
"usd_per_second": "0.000061",
"available": true
},
{
"tier": "economy",
"att_context_size": [70, 13],
"latency_ms": 1120,
"usd_per_second": "0.000042",
"available": true
}
]
}

A tier that is priced is not necessarily servable. available can be false for a tier that appears in the table above, because the serving layer declares at startup which context settings it can actually run, and the API reflects that rather than guessing.

Asking for an unavailable tier fails cleanly. It is never silently downgraded to a neighbouring tier, because a silent downgrade would change both your latency and your rate without telling you.

{
"error": {
"code": "tier_unavailable",
"message": "Tier 'ultra' is not available on this deployment.",
"request_id": "req_01JD4Z2Q8W6M"
}
}

The practical advice: read GET /v1/tiers at startup, cache it for the life of the process, and have a fallback tier chosen in advance. If you want a fallback, choose it yourself and handle tier_unavailable, rather than relying on the API to pick one for you.

The per second rate in the table is the rate for every second of audio you send on that tier, before the volume rebate. Usage debits a prepaid credit balance. The full formula, the rebate bands and a worked example are on Pricing and credits.