Skip to main content
VoiceGateway slots beside your agent framework, not between you and it. It hooks two seams: attach() is a passive observer that meters every STT, LLM, and TTS call; guard() is an active control wrapper that adds fallback chains, rate limits, and spend caps around a provider you choose. Metering the agent is where most people start. It is not the whole product. See What you can profile for the SFU and SIP layers.

The problem

A production voice agent juggles three provider categories at once: STT (Deepgram, AssemblyAI, Whisper), LLM (OpenAI, Anthropic, Groq, Ollama), and TTS (Cartesia, ElevenLabs, Kokoro, Piper). Each bills in a different unit. STT is audio-minutes, LLM is tokens, TTS is characters. No provider dashboard shows you what one conversation cost across all three. As a project grows the pain compounds:
  • No per-call cost visibility. You see monthly totals per provider, never the cost of one conversation.
  • No fallback story. When a provider goes down at 2 AM, your agent goes silent.
  • Per-project budgets are impossible. When several agents or customers share the same API keys, there is no way to cap spend per project.
  • Local and cloud paths diverge. Whisper in development and Deepgram in production means two wiring setups.

The two-seam model

VoiceGateway exposes exactly two integration points. attach() is the only source of metrics. guard() writes none of its own, so using both together never double-counts.

Modality-aware cost tracking

Voice calls mix three pricing units. VoiceGateway tracks each separately and converts them to a dollar cost per call: Rates come from voice-prices, a fork of pydantic/genai-prices extended for audio modalities. voicegw reconcile verifies the calculated totals against your provider invoice.

What gets priced

There is no list of supported providers. attach() meters whatever your framework emits, and the model id decides what happens next: The Costs page shows that source per row, so you can always tell which case you landed in. The distinction between the first and third rows is deliberate: free because you host it yourself is not the same as unpriced because nobody recognised the model.
Self-hosted models are matched on the local/ and ollama/ prefixes, not by name. An agent reporting whisper-large-v3 is unpriced; the same model reported as local/whisper-large-v3 prices at zero.

Where it fits

VoiceGateway does not sit in the audio or inference path. There is no proxy hop and no added latency on happy-path calls.

When something else is the better fit

Most tools VoiceGateway gets compared to are LLM proxies. They sit in the request path and route text completions, which is a different problem. Next: what you can profile, or go straight to the quickstart.