Skip to main content
Ultravox Realtime integrates with major telephony providers to enable AI-powered voice applications that work with regular phone numbers. Your AI agents can make outbound calls and answer inbound calls through traditional phone networks.
SIP is separateThis page describes integrations with telephony providers like Twilio, Telnyx, Plivo, and Exotel. If you want to connect Ultravox to your existing phone system using SIP, see our SIP Guide.

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 APIImport Credentials?HD audioOut of Band DTMF?Cold transfer?*
Twilio"twilio": {}Media Streams
Telnyx"telnyx": {}Media Streaming
Plivo"plivo": {}AudioStream
Exotel"exotel": {}Voice Streaming
* Transfers are possible with any integration, but the built-in tool is limited to particular providers. See the transfers page for details.

Providing Telephony Credentials

If you are using Twilio, Telnyx, or Plivo, you can import your credentials to unlock new capabilities:
  • Simplified Incoming Call Handling → Configure your provider to send webhooks directly to Ultravox for incoming calls. No need to run your own server.
  • Simplified Outbound Calling → Allow Ultravox to directly create and connect outbound calls.
  • Outbound Call SchedulerSchedule batches of outbound calls and let us manage the call concurrency and retry logic.
  • Out of Band DTMF → Importing credentials allows Ultravox to use out-of-band DTMF.
You can import your credentials in the Ultravox console or via API. For the APIs, see Twilio, Telnyx, or Plivo.

Incoming Calls

Simplified Incoming Call Handling

Once you’ve added your credentials, just set your telephony provider’s webhook callback to https://app.ultravox.ai/api/agents/{agent_id}/telephony_xml to have incoming phone calls automatically create and connect to Ultravox calls. Note that agents need to be allowlisted to receive incoming calls. If you did not add your agent when importing your credentials, you can add it afterward in the Ultravox console or using the PATCH verb: Twilio, Telnyx, or Plivo. You can also allow all agents to receive calls by setting allowAllAgents to true when importing your credentials or updating them afterward. If there are fields in your provider’s webhook that you want to use as template variables in your agent, you can set up a mapping from the webhook fields to template context fields. For example, for Twilio you could add an entry like {"From": "user.phone_number"} to add {"user": {"phone_number": "+15551234567"}} to the template context.

Custom Incoming Call Handling

Alternatively, you can use these steps when routing calls through your own application.
1

User Dials You

User dials your phone number purchased from your telephony provider.
2

Incoming Webhook

Provider routes the call to your configured webhook/application.
3

Create Ultravox Call

Your server creates an Ultravox call using the medium for your provider and gets a joinUrl.
4

Connect & Answer

Connect the call to your provider using the joinUrl. The AI agent answers and begins the conversation.

Outbound Calls

firstSpeakerSettingsBy default, Ultravox calls assume the agent begins conversations. This is typically what you want for inbound calls, but for outbound calls consider changing your firstSpeakerSettings so the agent waits for the user to answer.

Simplified Outbound Calling

Once you’ve added your credentials, you can add an outgoing field to your medium to have Ultravox create and connect outbound calls for you.
Outgoing Example
{
  "systemPrompt": "You are calling to remind John Doe about their appointment.",
  "firstSpeakerSettings": {
    "user": {  // We expect the user to speak first since this is outgoing
      "fallback": { // But we add a fallback in case the user waits for the agent to speak
        "delay": "10s",
        "text": "Hello, is John available to confirm an appointment?"
      }
    }
  },
  "medium": {
    "twilio": { // or "telnyx": {} or "plivo": {}
      "outgoing": {
        "to": "+15551234567",
        "from": "+15559876543",
        "additionalParams": { // Optional.
          // See your provider's docs for all options. These will be added to the call creation request to your provider.
          "statusCallback": "https://your-server.com/status"
        }
      }
    }
  }
}
We recommend configuring your systemPrompt and firstSpeakerSettings in an agent so you only need to specify medium when creating calls with the agent.

Custom Outbound Calling

You can also integrate Ultravox with your existing telephony workflows by creating calls manually through your provider’s API.
1

Call Trigger

Your application triggers an outbound call (user action, scheduled event, etc.).
2

Create Ultravox Call

Create an Ultravox call with the medium corresponding to your provider.
3

Initiate Phone Call

Initiate the phone call using your telephony provider’s API and connect it to Ultravox using the joinUrl. User answers and the agent engages in the conversation.

Batch Outbound Calling

For scheduling large volumes of outbound calls, use the Outbound Call Scheduler which provides:
  • Automatic Concurrency Management - No more 429 errors from hitting rate limits
  • Flexible Scheduling - Define time windows for when calls should be made
  • Automatic capacity reservation - Save room for high priority or incoming calls while your campaign is running
  • Batch Management - Track progress and control execution

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
});
Full example code in Outbound Quickstart →

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>
Full example code in Inbound Quickstart →

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: "inbound_track",
  stream_bidirectional_mode: "rtp"
  stream_codec: "L16",
  stream_bidirectional_codec: "L16",
  stream_bidirectional_sampling_rate: 16000,
  stream_bidirectional_target_legs: "opposite",
});
Or using TeXML:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Connect>
    <Stream url="${joinUrl}" bidirectionalMode="rtp"  codec="L16" bidirectionalCodec="L16" bidirectionalSamplingRate="16000"/>
  </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="L16" bidirectionalCodec="L16" bidirectionalSamplingRate="16000"/>
  </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! Now that Telnyx supports HD Audio, you most likely want “L16” for both.
For more details, see the Telnyx documentation.

Plivo

Full example code for outbound and inbound calls with Plivo on GitHub here →

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.

Learn More