Ultravox AI: Putting It on a Phone Line

Putting Ultravox AI on a live phone line requires bridging a real-time voice model to PSTN infrastructure that was never designed for it. This guide covers the audio path, WebSocket...
ultravox ai phone line barge in interruption handling teler feature
In this article

AI Summary: This article is for backend and API integration engineers evaluating how to put Ultravox AI on a live phone line in 2026. Ultravox uses a WebSocket transport designed for server-to-server communication, and the Ultravox docs explicitly warn against using that path from a browser or mobile client. The reader must decide where to terminate PSTN audio, how to handle the format conversion between carrier audio and the model, and how to manage barge-in and buffer clearing. Teler provides the telephony layer, including real-time media streaming over WebSocket, number provisioning, and call control, so developers work at the application layer rather than building carrier connectivity from scratch.

Scope: This walkthrough covers connecting Ultravox AI to a live PSTN call using a WebSocket media bridge, verified against Ultravox documentation and the fixie-ai/ultravox-examples repository as of September 2026. It does not cover self-hosted Ultravox model deployment or WebRTC client paths.

Quick Answer: Putting Ultravox AI on a phone line in 2026 requires a server-side WebSocket bridge between a PSTN telephony layer and the Ultravox Realtime API. The telephony layer terminates the carrier audio, and your server forwards it to Ultravox over a plain WebSocket connection. Barge-in requires explicit PlaybackClearBuffer handling on your side.

Connecting Ultravox AI to a phone line means bridging a real-time voice model to carrier infrastructure over a server-side WebSocket, with your application responsible for audio forwarding, buffer management, and interruption handling throughout the call.

What is Ultravox AI?

Ultravox AI is a fast multimodal large language model built by Fixie.ai for real-time voice conversations, available both as open weights and as a managed service called Ultravox Realtime. It occupies the inference layer: it receives audio input, reasons over it, and returns audio output, but it does not own a phone number, a SIP trunk, or any carrier connectivity. The model does not provision DTMF (dual-tone multi-frequency) handling, call recording, or PSTN (public switched telephone network) routing on its own. A developer who wants Ultravox AI on a phone line must supply the telephony transport, the media bridge, the audio format conversion if required, and the call control logic independently.

Why is putting Ultravox AI on a phone line harder than it looks?

The core problem is that PSTN infrastructure and a real-time voice model operate on different assumptions about who owns the media path. A phone call delivers audio continuously from a carrier; the model expects a server to feed it that audio in a controlled stream. Nothing in the carrier network knows about WebSocket framing, and nothing in Ultravox knows about SIP (Session Initiation Protocol) signaling or RTP (Real-time Transport Protocol) packet delivery.

The Ultravox documentation is explicit on one constraint that catches teams early: WebSocket connections are designed for server-to-server communication. For browser or mobile applications, the docs say to use client SDKs with WebRTC for optimal performance, because WebSocket connections over TCP can experience buffering and ordering issues that degrade audio quality on client devices. That means the media bridge must live on your server, not in the caller’s browser.

A second constraint is pacing. The Ultravox API reference describes a call medium that expects continuous audio at roughly one second of audio per second, typically in small chunks such as 20 milliseconds. Sending too little audio produces underflow; sending too much produces overflow. Either condition can drop audio or de-synchronize any recording you have attached to the call.

ultravox websocket server to server transport no browser client

What does the audio path look like from carrier to model?

The end-to-end path has four hops. The carrier delivers audio to a telephony layer, the telephony layer streams it to your server over WebSocket, your server forwards it to Ultravox over a second WebSocket connection, and Ultravox returns synthesized audio that travels back through the same chain. Each hop has a different owner and potentially a different audio format.

HopTransportTypical formatOwner
Carrier to telephony layerPSTN / SIP + RTPG.711 PCM, 8 kHz, mu-law or A-lawCarrier and telephony provider
Telephony layer to your serverWebSocket16-bit PCM, 8 kHzTelephony provider and your server
Your server to UltravoxWebSocket (server-to-server)Audio format per Ultravox session configYour server and Ultravox Realtime
Ultravox to your server and backWebSocketSynthesized audio returned by the modelUltravox Realtime and your server

The format at hop one is almost always ITU-T G.711 narrowband PCM at 8 kHz, which is the standard for PSTN voice. Ultravox lets you set the input and output sample rate per call, so you can set both to 8 kHz and skip the resampling step.

Prerequisites before you write a line of code

  • An Ultravox Realtime account and API key from ultravox.ai
  • A telephony provider that exposes raw media over WebSocket, such as Teler, with a provisioned phone number in E.164 format
  • A server reachable from the public internet for WebSocket connections from both the telephony layer and Ultravox
  • Python 3.10 or later, or Node.js 18 or later, depending on your bridge implementation
  • The websockets library for Python (pip install websockets) or the ws package for Node.js (npm install ws)
  • An audio resampling library if your telephony provider delivers 8 kHz and Ultravox requires a different rate for your session; librosa or ffmpeg work for Python
  • Network reachability: your server must be able to open outbound WebSocket connections to the Ultravox API endpoint and receive inbound connections from the telephony provider
  • Review the fixie-ai/ultravox-examples repository (last commit August 2026) for the Plivo telephony reference implementation before writing your own bridge
ultravox ai phone call media path carrier teler app server chain

How do you implement the Ultravox AI phone bridge?

The implementation has four steps: create an Ultravox session, accept the inbound call on the telephony layer, open the server-side WebSocket bridge, and handle interruptions. Each step is a distinct failure surface.

Step 1: Create an Ultravox session via REST

Before the call arrives, create an Ultravox session. The API returns a WebSocket URL your server uses to connect to the inference instance. Do this before bridging media, not after.

import httpx

response = httpx.post(
    "https://api.ultravox.ai/api/calls",
    headers={"X-API-Key": ULTRAVOX_API_KEY},
    json={
        "systemPrompt": "You are a helpful phone assistant.",
                "medium": {
            "serverWebSocket": {
                "inputSampleRate": 8000,
                "outputSampleRate": 8000,
            }
        },
    },
)
session = response.json()
ultravox_ws_url = session["joinUrl"]  # connect your server here

The joinUrl is time-limited; connect to it promptly after the call answers, not at session creation time. Ultravox takes the sample rate for each call as a parameter, so both directions can be set to 8000. That matches the 16-bit PCM at 8 kHz that Teler streams and plays back, so the audio passes through your bridge without resampling.

Step 2: Accept the inbound call and start the telephony WebSocket

When the telephony provider signals an inbound call, your server answers it and opens a WebSocket connection to receive the caller’s audio stream. With Teler, the telephony layer streams audio to your server as 16-bit PCM at 8 kHz, in chunks you specify. The Teler documentation covers the exact WebSocket handshake and stream configuration parameters.

Teler targets sub-100ms packet delivery as a design specification, which matters here because any delay in the telephony-to-server hop adds directly to the caller’s perceived latency before the model even starts processing.

Step 3: Bridge audio between the two WebSocket connections

Your server now holds two open WebSocket connections: one to the telephony layer and one to Ultravox. The bridge reads audio chunks from the telephony connection and forwards them to Ultravox, then reads synthesized audio from Ultravox and injects it back into the call. Both directions run concurrently.

import asyncio
import base64
import json
import websockets

async def bridge(teler_ws, ultravox_ws_url):
    async with websockets.connect(ultravox_ws_url) as uv_ws:

        async def caller_to_model():
            # Teler sends JSON frames with base64 PCM; Ultravox wants raw PCM bytes
            async for message in teler_ws:
                event = json.loads(message)
                if event.get("type") == "audio":
                    pcm = base64.b64decode(event["data"]["audio_b64"])
                    await uv_ws.send(pcm)

        async def model_to_caller():
            chunk_id = 1
            async for message in uv_ws:
                if isinstance(message, bytes):
                    # Raw PCM from Ultravox -> JSON frame with base64 for Teler
                    await teler_ws.send(json.dumps({
                        "type": "audio",
                        "audio_b64": base64.b64encode(message).decode(),
                        "chunk_id": chunk_id,
                    }))
                    chunk_id += 1
                else:
                    event = json.loads(message)
                    if event.get("type") == "playback_clear_buffer":
                        await teler_ws.send(json.dumps({"type": "clear"}))

        await asyncio.gather(caller_to_model(), model_to_caller())

Watch the chunk size: Teler accepts chunks from 20 to 2000 milliseconds in multiples of 20, with a default of 400 ms, and requires you to send back at least 500 ms of audio to avoid choppy playback.

Step 4: Handle barge-in and buffer clearing

Barge-in, where the caller speaks while the agent is still talking, requires explicit buffer clearing on both sides. When Ultravox signals a playbackClearBuffer event, your server must flush any queued audio on the telephony side immediately. If you skip this step, the caller hears the agent finish its queued response even after interrupting. The Voximplant integration example for Ultravox also recommends clearing the buffer when a user transcript event arrives, as a belt-and-suspenders approach.

For outbound calls, create the Ultravox session and open the bridge only after the callee answers. Bridging before answer sends agent audio into ringback, which is audible to the callee and breaks the conversation flow from the first word.

Most teams discover their latency problem is not the model, it is the resampling hop they added between the carrier and the model. If your telephony layer delivers 8 kHz PCM and you transcode it to a different rate before forwarding, that conversion runs on every chunk for the entire call duration. Profile it before you ship.

– Subhash Kalluri, Founder & CEO, FreJun

What breaks in production when running Ultravox AI on a phone line?

The failure modes below come from the Ultravox GitHub issue tracker, the Ultravox documentation, and the Voximplant integration reference. Frequency is noted honestly: most of these are single reported incidents, not widespread patterns.

SymptomRoot causeFixFrequency
Choppy audio or stalled turn-taking on client devicesWebSocket path used from browser or mobile instead of serverMove the bridge to your server; use WebRTC SDKs for client pathsReported once, documented in Ultravox docs
Agent keeps talking after caller interruptsNo PlaybackClearBuffer handler; queued audio keeps playingListen for playbackClearBuffer, call clear on the telephony side immediatelyReported once, Voximplant integration docs
Agent talks into ringback on outbound callsBridge created before callee answersOpen the Ultravox bridge only after the PSTN leg answersReported once, Voximplant outbound docs
Audio underflow or overflow, dropped audioChunk pacing mismatch; too little or too much audio per secondSend 20 ms chunks continuously; tune clientBufferSizeMsReported once, Ultravox API reference
recordingEnabled flag ignoredUnresolved; behavior does not match expectedNo fix reported as of August 2026Reported once, GitHub issues

The barge-in failure is the one that catches most teams in user testing rather than load testing. A caller says something mid-sentence, the agent finishes its queued response anyway, and the conversation feels broken. The fix is straightforward once you know to look for the playbackClearBuffer event, but the Ultravox docs do not surface it prominently in the quickstart path. Read the Ultravox data messages reference before you write the bridge loop.

Which integration approach is right for your stack?

There are four practical ways to get Ultravox AI onto a phone line. Each trades operational complexity against control and vendor coupling.

ApproachWhere media terminatesLatency costOperational burdenVendor coupling
Raw media streaming bridge (this article)Your serverLow, one resampling hop if neededMedium; you own pacing and buffer logicLow; swap telephony provider independently
SIP trunk into a media serverSIP/media server (e.g., Asterisk, FreeSWITCH)Medium; extra RTP hopHigh; SBC and media server opsMedium; SIP is standard but config is complex
Provider-native telephony bridgeTelephony vendor’s infrastructureLow to medium depending on vendorLow; vendor handles the bridgeHigh; locked to vendor’s supported model list
WebRTC gatewayWebRTC edge or browserLow for web-to-phone hybridMedium; TURN/STUN infrastructure neededLow to medium

The raw media streaming bridge is the right choice when you need to swap models, change telephony providers, or instrument the audio path for debugging. Use a provider-native bridge when you want the fastest path to production and the vendor officially supports Ultravox. Use a SIP media server approach only if you already operate one and the team has the expertise to maintain it. The WebRTC gateway path makes sense for web-to-phone hybrid applications where the caller is in a browser and the agent is on a PSTN number.

Frequently asked questions

Does Ultravox AI support SIP directly?

The Ultravox telephony overview page lists SIP as a supported connection method alongside other telephony partners. The retrieved documentation does not detail the SIP configuration parameters, so check the Ultravox telephony overview directly for current SIP setup instructions. The WebSocket server-to-server path described in this article is the approach with the most publicly available reference implementations as of 2026.

What audio format does Ultravox expect on the WebSocket connection?

Raw binary WebSocket frames of 16-bit little-endian PCM. The sample rate is whatever you set when creating the call: inputSampleRate (required) for caller audio and outputSampleRate for agent audio, which defaults to the input rate. Set both to 8000 to match Teler. Data messages such as transcripts arrive as separate JSON text frames.

Can I use Ultravox AI from a browser WebSocket directly?

No. The Ultravox documentation explicitly states that WebSocket connections are designed for server-to-server communication. TCP buffering and ordering constraints make the plain WebSocket path unsuitable for browser or mobile clients. For browser or mobile applications, use the Ultravox client SDKs with WebRTC. The server-side bridge described in this article is the correct architecture for a phone line integration.

What happens to audio pacing under load?

Under load, the pacing constraint becomes a bottleneck. The Ultravox API reference describes a call medium that expects continuous audio at roughly one second of audio per second. If your server is processing many concurrent calls and falls behind on forwarding chunks, you will see underflow on some sessions. Profile your bridge under realistic concurrency before going to production, and consider whether your server’s event loop can sustain the chunk rate across all active sessions simultaneously.

Does Teler handle the resampling between 8 kHz carrier audio and Ultravox?

You don’t need resampling here. Teler uses 16-bit PCM at 8 kHz, and Ultravox lets you set the same rate when you create the call, so the audio passes straight through. Resampling only comes into play if you choose a different rate on the Ultravox side, in which case your server owns the conversion

How do I provision a phone number for an Ultravox AI agent?

Ultravox does not provision phone numbers. You provision a DID (direct inward dialing) number through a telephony provider such as Teler, which supports number provisioning in 50 or more countries via API. The number routes inbound calls to your server, which then bridges audio to Ultravox. Check current Teler pricing for number provisioning costs, as rates vary by country and number type.

Is the fixie-ai/ultravox-examples repository actively maintained?

The last commit to the fixie-ai/ultravox-examples repository was August 11, 2025, which is over 12 months before the verification date of this article. The Plivo telephony example is present, but treat it as a starting reference rather than a production-ready implementation. Verify that the session creation parameters and WebSocket message types match the current Ultravox API before using the example code directly.

What do I need to build myself that Ultravox and Teler do not provide?

You are responsible for the bridge server itself, audio pacing logic, resampling if the sample rates differ, PlaybackClearBuffer handling for barge-in, and any call recording logic beyond what the telephony provider offers. The recordingEnabled flag in Ultravox has an open unresolved issue as of August 2026, so do not rely on it for production recording without testing it against your specific session configuration. Teler provides call control primitives including hangup, mute, DTMF, and transfer, but your server must invoke them at the right moment in the call flow.

What can you do now with Ultravox AI on a phone line?

With the bridge in place, you can run Ultravox AI on a live PSTN call, handle barge-in correctly, and swap the telephony provider without touching the model integration. The one decision that matters most is where your server sits relative to both the telephony layer and the Ultravox API endpoint: latency compounds at every hop, and a server that is geographically distant from either endpoint will produce a conversation that feels slow regardless of how fast the model is. If your use case requires a provider-native path with less bridge code to maintain, evaluate whether your telephony vendor officially supports Ultravox AI before committing to the custom bridge approach described here.

About the Author: Subhash Kalluri is the Founder & CEO of FreJun, which he has been building since 2019. With over 8 years in voice communication and SaaS, he works on the problem of getting real-time AI onto live phone calls: raw media streaming, interruption handling, and carrier connectivity. That work became FreJun Teler, FreJun’s programmable voice API for developers building AI phone agents. Connect with him on LinkedIn.

Get started with FreJun today

In this article

Make every voice interaction count

FreJun is a real-time voice platform for automating calls and connecting AI bots.

Popular Articles
Edge-native voice agents built with AgentKit, Teler and the OpenAI Realtime API connected in one chain

Quick Answer: To build an edge-native voice agent, combine an orchestration layer (AgentKit), a realtime audio API, and a telephony...

Media streaming in an AI voice call: caller audio streamed as a live waveform to an AI agent

Quick Answer: Media streaming for AI calls is the continuous, two-way flow of audio between a caller and an AI...

Advantages of using Superbryn.com on a radar chart of speed, simplicity, latency, control and scale versus FreJun Teler

Quick Answer: Superbryn.com is an end-to-end managed platform for AI phone agents, bundling telephony, speech-to-text, LLM orchestration, and text-to-speech behind...