Inbound calls with Twilio Voice

How to use LiveKit SIP with TwiML and Twilio conferencing.

Inbound calls with Twilio programmable voice

You can use LiveKit SIP to accept calls to a Twilio phone number without setting up Twilio Elastic SIP Trunking. All you need is an inbound trunk and dispatch rule created using the LiveKit CLI (or SDK) to accept calls and route callers to LiveKit rooms. The following steps guide you through the process.

The example in this section uses Node and the Twilio Node SDK.

Step 1. Purchase a phone number from Twilio

If you don't already have a phone number, see How to Search for and Buy a Twilio Phone Number From Console.

Step 2. Create an inbound trunk

Use the LiveKit CLI to create an inbound trunk for the purchased phone number.

  1. Create an inbound-trunk.json file with the following contents. Replace the phone number and add a username and password of your choosing:

    {
    "trunk": {
    "name": "My inbound trunk",
    "numbers": ["+16505550100"],
    "auth_username": "<username>",
    "auth_password": "<password>"
    }
    }
  2. Use the CLI to create an inbound trunk:

    lk sip inbound create inbound-trunk.json
  3. Note the trunk ID in the output for the next step:

    SIPTrunkID: <trunk_id>

Step 3. Create a dispatch rule to place each caller into their own room.

Use the LiveKit CLI to create a dispatch rule that places each caller into individual rooms named with the prefix call.

  1. Create a dispatch-rule.json file. Replace the <trunk_id> and add the following contents:

    {
    "trunk_ids": ["<trunk_id>"],
    "rule": {
    "dispatchRuleIndividual": {
    "roomPrefix": "call"
    }
    }
    }
  2. Use the CLI to create the dispatch rule:

    lk sip dispatch create dispatch-rule.json

Step 4: Use TwiML to handle incoming calls

These instructions pass along incoming calls to your LiveKit SIP endpoint. They include the username and password credentials you created previously for the inbound trunk:

note

If you're signed in to LiveKit Cloud, your sip host is filled in below.

import twilio from 'twilio';
const VoiceResponse = twilio.twiml.VoiceResponse;
/**
* Phone number purchased from Twilio.
* For example: +15105550100
*/
const twilioPhoneNumber = '<phone_number>';
/**
* SIP host is available in your LiveKit Cloud project settings.
* This is your project domain without the leading "sip:".
*/
const sipHost = '<your SIP host>';
const response = new VoiceResponse();
const dial = response.dial();
dial.sip({
username: '<username>',
password: '<password>',
}, `sip:${twilioPhoneNumber}@${sipHost}`);
console.log(response.toString());

When a caller dials your Twilio phone number, the request is passed on to LiveKit SIP and the caller is placed in a LiveKit room per the dispatch rule.

Testing with an agent

You can test your setup by creating a MultimodalAgent to respond to incoming calls.

  1. Use the CLI to create an Node.js multimodal agent:

    lk app create --template=multimodal-agent-node

    Follow the instructions in the command output to start the agent:

    cd /path/to/your_app
    pnpm install
    pnpm build
    node dist/agent.js dev
  2. Call the phone number and an agent picks up the call.

Connecting to a Twilio phone conference

You can bridge Twilio conferencing to LiveKit via SIP, allowing you to add agents and other LiveKit clients to an existing Twilio conference. This requires the following setup:

The example in this section uses Node and the Twilio Node SDK.

Step 1. Set Twilio environment variables

You can find these values in your Twilio Console:

export TWILIO_ACCOUNT_SID=<twilio_account_sid>
export TWILIO_AUTH_TOKEN=<twilio_auth_token>

Step 2. Bridge a Twilio conference and LiveKit SIP

Create a bridge.js file and update the twilioPhoneNumber, conferenceSid, sipHost, and from field for the API call in the following code:

note

If you're signed in to LiveKit Cloud, your sip host is filled in below.

import twilio from 'twilio';
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const twilioClient = twilio(accountSid, authToken);
/**
* Phone number bought from Twilio that is associated with a LiveKit trunk.
* For example, +14155550100.
* See https://docs.livekit.io/sip/quickstarts/configuring-sip-trunk/
*/
const twilioPhoneNumber = '<sip_trunk_phone_number>';
/**
* SIP host is available in your LiveKit Cloud project settings.
* This is your project domain without the leading "sip:".
*/
const sipHost = '<your SIP host>';
/**
* The conference SID from Twilio that you want to add the agent to. You
* likely want to obtain this from your conference status callback webhook handler.
* The from field must contain the phone number, client identifier, or username
* portion of the SIP address that made this call.
* See https://www.twilio.com/docs/voice/api/conference-participant-resource#request-body-parameters
*/
const conferenceSid = '<twilio_conference_sid>';
await twilioClient.conferences(conferenceSid).participants.create({
from: '<valid_from_value>',
to: `sip:${twilioPhoneNumber}@${sipHost};transport=tcp`,
});

Step 3. Execute the file

When you run the file, it bridges the Twilio conference to a new LiveKit session using the previously configured dispatch rule. This allows you to automatically dispatch an agent to the Twilio conference.

node bridge.js