Ultravox integrates with multiple telephony providers and voice platforms.

Native Integrations

Ultravox provides native integrations for the following. Each has their own unique call medium that must be used when creating calls.

ProviderCall MediumStreaming API
Twilio"twilio": {}Media Streams
Telnyx"telnyx": {}Media Streaming
Plivo"plivo": {}AudioStream
Exotel"exotel": {}Voice Streaming

SIP

Ultravox Realtime has native support for SIP. See the SIP Guide for more.

Partner Integrations

Our voice platform partners have native integrations for Ultravox:

Voximplant

Voximplant provides a hosted voice platform. Check out the Integration Guide →

jambonz

jambonz provides a voice platform that runs in a fully managed cloud or can be self-hosted. Details on how to make and receive calls using jambonz appear below.

Provider-Specific Integration Examples

Twilio

Outbound Calls with Twilio

1

Create an Ultravox Call

Create a new call as shown above with medium: { "twilio": {} }, firstSpeakerSettings: { user: {} }, and get a joinUrl.

2

Connect Ultravox to the Twilio Phone Call

Use the joinUrl with a Twilio <Stream>:

// Example using the twilio node library
const call = await client.calls.create({
    twiml: `<Response>
                <Connect>
                    <Stream url="${joinUrl}"/>
                </Connect>
            </Response>`,
    to: phoneNumber,
    from: twilioPhoneNumber
});

Incoming Calls with Twilio

1

Create an Ultravox Call

Create a new call with medium: { "twilio": {} } and firstSpeakerSettings set to { agent: {} }.

2

Connect the Inbound Twilio Call to Ultravox

Use the joinUrl with a Twilio <Stream>:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Connect>
        <Stream url="your_ultravox_join_url" />
    </Connect>
</Response>

For more details, see the Twilio documentation.

Telnyx

Outbound Calls with Telnyx

1

Create an Ultravox Call

Create a new call as shown above with medium: { "telnyx": {} }, firstSpeakerSettings: { user: {} }, and get a joinUrl.

2

Connect Ultravox to the Telnyx Phone Call

Use the joinUrl with a TeXML <Stream>:

// Example using the telnyx node library
const call = await telnyx.calls.create({
  connection_id: "uuid",
  to: phoneNumber,
  from: telnyxPhoneNumber,
  stream_url: joinUrl,
  stream_track: "both_tracks",
  stream_bidirectional_mode: "rtp"
});

Or using TeXML:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Connect>
    <Stream url="${joinUrl}" bidirectionalMode="rtp"  codec="PCMU" bidirectionalCodec="PCMU"/>
  </Connect>
</Response>

Incoming Calls with Telnyx

1

Create an Ultravox Call

Create a new call with medium: { "telnyx": {} } and firstSpeakerSettings set to { agent: {} }.

2

Connect the Inbound Telnyx Call to Ultravox

Use the joinUrl with a TeXML <Stream>:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Connect>
    <Stream url="${joinUrl}" bidirectionalMode="rtp" codec="PCMU" bidirectionalCodec="PCMU"/>
  </Connect>
</Response>
Telnyx codec

Telnyx allows setting both codec and bidirectionalCodec. The former controls user audio while the latter controls agent audio. When using with Ultravox, these must have the same value because Telnyx only tells us about one of them! If your users are mostly in Europe, you’ll likely want to set both to PCMA. Otherwise setting both to PCMU is preferred but leaving them both unset is fine to get started.

For more details, see the Telnyx documentation.

Plivo

Outbound Calls with Plivo

1

Create an Ultravox Call

Create a new call as shown above with medium: { "plivo": {} }, firstSpeakerSettings: { user: {} }, and get a joinUrl.

2

Connect Ultravox to the Plivo Phone Call

Use the joinUrl with AudioStream:

// Example using the plivo node library
// This assumes our server exposes an endpoint at `answerUrl`
const call = await plivo.calls.create({
  to: phoneNumber,
  from: plivoPhoneNumber,
  answer_url: answerUrl, // URL that returns the XML below
  answer_method: "GET"
});

The answer URL should return:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Stream keepCallAlive="true" 
            contentType="audio/x-l16;rate=16000"
            bidirectional="true">
        ${joinUrl}
    </Stream>
</Response>

Note: For best audio quality, we recommend audio/x-l16;rate=16000. However, any contentType supported by Plivo will work with Ultravox.

Incoming Calls with Plivo

1

Create an Ultravox Call

Create a new call with medium: { "plivo": {} } and firstSpeakerSettings set to { agent: {} }.

2

Connect the Inbound Twilio Call to Ultravox

Use the joinUrl with AudioStream:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Stream keepCallAlive="true"
            contentType="audio/x-l16;rate=16000" 
            bidirectional="true">
        ${joinUrl}
    </Stream>
</Response>

For more details, see the Plivo documentation.

jambonz

jambonz Portal Setup

jambonz is a “bring your own everything” open-source telephony platform that integrates Ultravox directly via their llm verb. This gives you the flexibility to choose your carrier of choice, you’ll just need to add it in your jambonz dashboard.

1

Add Your Carrier in jambonz

In jambonz, we use the terms “carrier” and “SIP trunk” interchangeably. jambonz is a “Bring your own carrier” platform, which means that you can connect any sip network provider or device. Add your carrier of choice in your jambonz dashboard to get started.

2

Add a Speech Provider in jambonz

Next, you need to add speech credentials for your chosen vendor.

3

Create a New jambonz Application

​A jambonz application configured via the jambonz portal defines how calls are handled by linking them to your custom logic through webhooks or WebSocket endpoints. When you create an application, you specify:​

  • Call webhook URL: Where jambonz sends call events.​
  • Call status webhook URL: For receiving call status updates.​
  • Speech vendors: Your chosen TTS/STT providers.​

Once saved, you can associate phone numbers or SIP trunks with this application, ensuring that incoming calls are routed to your specified logic. This setup allows you to implement features like speech recognition, text-to-speech, call routing, and integration with AI services.

4

Add a Phone Number in jambonz

Finally, you need to add a phone number provisioned from your carrier of choice. At the bottom of the page select the jambonz application you just created to link your new virtual number to that application.

Incoming Calls with jambonz

// Example using the @jambonz/node-client-ws library
session
.pause({length: 1.5})
.llm({
  vendor: 'ultravox',
  model: 'fixie-ai/ultravox',
  auth: {
    apiKey
  },
  actionHook: '/final',
  eventHook: '/event',
  llmOptions: {
    systemPrompt: 'You are an agent named Karen. Greet the user and ask how you can help.',
    firstSpeakerSettings: { agent: {} },
    initialMessages: [{
      medium: 'MESSAGE_MEDIUM_VOICE',
      role: 'MESSAGE_ROLE_USER'
    }],
    model: 'fixie-ai/ultravox',
    voice: 'Tanya-English',
    transcriptOptional: true,
  }
})
.hangup()
.send();

For more details see the llm verb in the jambonz docs.

Outbound Calls with jambonz

In addition to the inbound scenario, you’ll have to create a call that connects to the destination number (phoneNumber) and points to the jambonz application that defines how the call should be handled. Find the APPLICATION_SID in the jambonz portal by clicking on the application you created during the setup process.

  const JambonzClient = require('@jambonz/node-client');

  const client = JambonzClient(
    process.env.JAMBONZ_ACCOUNT_SID,
    process.env.JAMBONZ_API_KEY,
    {baseUrl: process.env.JAMBONZ_REST_API_BASE_URL || 'https://api.jambonz.cloud/v1'}
  );

  const call = await client.calls.create({
      from: process.env.FROM_NUMBER,  
        to: {
          type : 'phone',
          number: phoneNumber,
          trunk: process.env.CARRIER
          },
      application_sid: process.env.APPLICATION_SID
  });

For more details, see the jambonz documentation and example code.