Build the future of communications.
Start building for free

Registering a SIP Phone Directly to Twilio (and so much more...)

Sl2wfrJ5aA9RwXwPmthRlZdT9FnZmsiEAYFdlVUQ5C8KQfEWVaHhxkipFOx_DwRAwEBVlcKcLvmUOrJrzO8aZW5WsjOfKvBh54q7Oh50m2cLpIxYRbxXoFsULFNNCP3b5nWxrnW2

Twilio Programmable Voice SIP Domains, sometimes referred to as SIP Interfaces, allow you to place and receive voice calls using a standards based SIP endpoint by registering directly with Twilio.

Along with the ability to register directly with Twilio, you have the flexibility to choose the termination transport. This may include the traditional public switched telephone network (PSTN), another registered SIP device (often referred to as a SIP user agent [UA]), or even a Twilio Programmable Voice SDK endpoint. Connect all the things, indeed!

In this blog post we will:

  • Register a SIP phone directly to Twilio
  • Place and receive calls from a registered SIP phone
  • Cover recommended design approaches
  • Provide two different methods for delivering SIP Domain phone calls
  • Discuss the benefits and current limitations using Twilio SIP Domains

Prerequisites to working with SIP Domains and Twilio

To accomplish the tasks in this blog post you will need the following:

  • Twilio Account (Sign up for a free account.)
  • A SIP client such as X-Lite.

SIP You Say?

Programmable Voice SIP Domains leverages the Internet Engineering Task Force (IETF) standard RFC 3261 to set-up, modify, and tear down communication sessions. SIP has many similarities with other IETF protocols such as HTTP, which can be quite helpful to gain an initial understanding of the protocol.

Twilio uses webhooks to let your application know when events happen, such as receiving a voice call or an incoming SMS.

When such an event occurs, Twilio makes an HTTP request (usually a POST or a GET) to a webhook URL you configure. Twilio's request will include metadata such as the incoming phone number or the body of an incoming message. Many other modern web services like GitHub and Slack also make use of webhooks to communicate events.

The most important concept to understand with Twilio SIP Domains is each two party call is composed of call legs. This concept of call legs is important because we insert intelligence between the origination and termination call legs to directly affect the call delivery.

The terminology we will use for the initiation or originating leg of the call is the “parent” leg. The parent leg will often generate a "child" leg, as a result of your application returning Twilio Markup Language (TwiML).

Twilio SIP parent and child leg diagram

How your Twilio application works with webhooks and call legs

After an event, a webhook is sent to your application. Your application then needs to return TwiML to Twilio using a number of different approaches.

I am a big proponent of Twilio’s serverless products, which allow us to rapidly implement a solution and elastically scale capacity as required, without requiring your own infrastructure. The two serverless products we will make use of today are TwiML Bins, which return “static” TwiML, and Twilio Functions, which return “dynamic” TwiML, based on the logic we incorporate into our Twilio Functions JavaScript.

Once TwiML is returned by the TwiML Bin or Twilio Function, Twilio has the information needed to set up the “child” leg. The TwiML will tell Twilio what transport to deliver the child leg (PSTN, SIP, or Twilio Programmable Voice SDK powered device such as a web browser or mobile device). Upon successful establishment of the “child” leg, Twilio seamlessly bridges the two call legs together for a successful call.

The benefits and limitations of SIP Domain registered devices

Before we get started, let’s discuss some of the benefits and limitations of using Twilio Programmable Voice SIP Domains.

As all SIP Domain calls are sent and received to your UA over a data network, the voice quality is determined by the current capabilities of the devices underlying network and the path to Twilio's network. Twilio Voice Insights provides the ability to gather additional details in this area.

Benefits

  1. You have access to a very large selection of standards based SIP endpoints across manufacturers, operating systems and mobile device platforms.
  2. The cost for the call leg to or from the Twilio SIP Domain registered device is often less then routing that part of the call across the PSTN. Note that each two party call is made up of two call legs, so the other call leg would most likely incur PSTN costs if you are not calling another SIP endpoint.
  3. Having the ability to add logic between origination and termination call legs provides countless possibilities that you can use to your business’s advantage. You can inject audio prompts, collect digits or speech and route accordingly (IVR), access external API's to make intelligent routing decisions, and otherwise customize for your business needs.
  4. Routing to Twilio SIP Domain registered devices is tightly integrated into Twilio’s APIs, TwiML, and products such as Twilio Studio. This integration provides design flexibility based on your skill set, and allows you to mix and match different types of endpoints.
  5. There is less coding required to use SIP Domain registered clients then there is using Twilio Programmable Voice SDK (WebRTC Client). Clients are readily available from third parties.
  6. You can have up to 10 registered devices under a single username. When you receive a call, all registered devices will ring simultaneously.

Limitations

  1. All registrations must currently occur in the us1 domain.
  2. Programmable Voice and Programmable Voice SIP Domains do not currently support emergency calling services (911/E911, etc.). Twilio Elastic SIP Trunking does support E911.
  3. Twilio SIP Domains do not currently support the SIP REFER method, so call transfers using the native buttons on the SIP endpoint are not possible.
  4. You currently cannot place multiple Sip nouns under a Dial verb like you can for the Number noun or Client noun, so you are not able to simultaneously ring different SIP endpoints using this approach.

My name is Inigo Montoya: setting SIP usernames

When provisioning a SIP domain registration credential list and the associated usernames for your SIP Domain, one best practice is to create the SIP username in E.164 format. E.164 format is used to uniquely identify the PSTN destination for a call. In the United States, this appears as  +1 (Country Code) then ten digits. For other countries, find additional information on the corresponding E.164 format here and here.

Twilio formats all inbound PSTN telephone numbers in E.164 format. We recommend setting the "To" and "From" numbers to E.164 format for outbound calls to remove ambiguity around the intended destinations. Twilio provides a global connected communication Super Network, and we deliver to a lot of international destinations – we suggest you incorporate this best practice.

Why your credential list usernames should use E.164 format

What are some of the benefits of defining your credential list registration usernames in E.164 numbers? Great question!

  1. When your end-users SIP device registers to your Twilio SIP domain, their endpoint will often display the registered username. This is very useful as the end-user can easily recite back the direct telephone number to the calling party, if required. There’s no need to guess what number someone can use to make a call back.
  2. When your end-users are placing calls outside the Twilio network on the PSTN, it’s easy to use the E.164 formatted SIP registration username as an outbound caller Id. Then calls can be directly returned, rather than using a shared caller Id (also know as a pilot number) for all outbound calls across your registered devices.
  3. When receiving calls from parties outside Twilio, Twilio receives the destination To phone number in E.164 format. Using the SIP username E.164 naming convention, it’s simple for us to directly route the call to the correct SIP user without having to use any additional logic or perform special lookups.

We’ll use the E.164 format for the username in this post because of these benefits. However, given the variety of business requirements, for example only SIP to SIP calls, I’ve provisioned for other formats below. SIP to SIP calls are useful, for example, for internal communication between SIP endpoints.

Next steps: approaches and tradeoffs in SIP Routing

We will use the same TwiML Bin routing for inbound calls or calls destined for your SIP Domain registered endpoints.

PSTN to SIP inbound call diagram with Twilio

I will offer two different approaches for outbound routing.

SIP outbound call diagram with Twilio

The simpler TwiML Bin approach for outbound SIP Domain routing is limited, given a TwiML Bin is designed to return mostly static TwiML. This use case is best for registered SIP endpoints making almost entirely outbound PSTN calls (which is also the most common use case).

As TwiML Bins are limited in their ability to dynamically create TwiML, Twilio SIP E.164 username to Twilio SIP E.164 username calls are not optimally routed using this approach.

Twilio charges per call leg. When routing a SIP user to SIP User call using the TwiML Bin approach, four call legs are required [SIP UA "parent" > E.164 Username "child" > Voice URL of Twilio Number "parent" > TwiML Bin point back to E.164 Username "child"].

TwiML Bin SIP Domain Voice URL Supported Call Flows:

  • Twilio E.164 SIP Username > E.164 PSTN (2 call legs)
  • Twilio E.164 SIP Username > Twilio E.164 SIP Username (4 call legs, sub-optimal)

Using a Twilio Function for outbound SIP Domain routing offers more possibilities. As shown below, we can open additional call flows by dynamically returning TwiML based on the type of call being made.

Twilio Function SIP Domain Voice URL Supported Call Flows:

  • Twilio E.164 SIP Username > E.164 PSTN (2 call legs)
  • Twilio E.164 SIP Username > Twilio E.164 SIP Username (2 call legs)
  • Twilio E.164 SIP Username > Twilio Alphanumeric SIP Username (2 call legs)
  • Twilio Alphanumeric SIP Username > E.164 PSTN (uses default caller Id, 2 call legs)
  • Twilio Alphanumeric SIP Username > Twilio E.164 SIP Username (uses SIP Username callerId, 2 call legs)
  • Twilio Alphanumeric SIP Username > Twilio Alphanumeric SIP Username (uses SIP Username callerId, 2 call legs)

Let's get started with SIP and Twilio!

Purchase your Twilio numbers

Purchase the Twilio phone numbers your SIP Domain UAs will use to receive calls:

  1. Visit the Phone Numbers page
  2. On the left side of the screen, click Buy a Number.
  3. Purchase your Twilio numbers, and write down these numbers for the later steps. When we create the credential list usernames we’ll bind these numbers to route to our SIP Domain UAs.

Create your SIP Domain

Here’s how to set up your Twilio SIP Domain:

  1. Visit the SIP Domain section of the console
  2. Click the red Create new SIP Domains or click the red plus sign (‘+')
  3. Enter a FriendlyName and give your SIP URI a unique name, (yourdomain), which will be appended to sip.twilio.com.
  4. We’ll change the Voice Configuration Request URL at a later step. This will be either our TwiML Bin example or our Twilio Function example. Note it is currently pointing to a default/placeholder TwiML URL, https://demo.twilio.com/welcome/voice/. This URL returns the following TwiML:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
  <Say voice="alice">Thanks for the call. Configure your number's voice U R L to change this message.
  </Say>
  <Pause length="1"/>
  <Say voice="alice">Let us know if we can help you in any way during your development.
  </Say>
</Response>

We will experiment with this later when making our first outbound call from the SIP UA.

  1. Click ('+') next to credential list and provide a friendly name, then add the username and password for your SIP client. Make your devices usernames the E.164 formatted Twilio number you will bind to this client (example: +15005551212). These should match the Twilio numbers you just purchased. Note the formatting: no space between any digits.
  2. Enter a complex password (12 character minimum, containing at least one uppercase letter, one lowercase letter, and a number), click create.
  3. Enable Registration
  4. Click into the SIP Registration Authentication credential list and select the credential list you created from Step 5 above.
  5. Click ‘Save’

Inbound Calling for both TwiML Bin and Twilio Function approaches

For inbound calls, we will create a TwiML Bin.

  1. Create a TwiML Bin, with a name such as ToSIPClient. Then paste the below TwiML into it and click ‘Create’. NOTE: Swap unique-name (montoya) with the domain name you chose for your SIP Domain.
<?xml version="1.0" encoding="UTF-8"?>
    <Response>
        <Dial answerOnBridge="true">
            <Sip>
 {{To}}@montoya.sip.us1.twilio.com
            </Sip>
        </Dial>
</Response>

TwiML Bins have some built in mustache templates, such as {{To}}, {{From}}, {{#e164}} and others. You can find out more in How To use templates with TwiML Bins

  1. Go to the Phone Number Configuration Page, select the incoming phone number you want to associate to that users SIP phone, then click on it.
  2. Scroll down to ‘Voice & Fax’ and in a ‘A Call Comes In’, Choose ‘TwiML’ from the dropdown. Select ToSIPClient (or whatever name you used) from the next dropdown and click ‘Save’.

Now inbound calls to that Twilio number are ready to ring your SIP phone. Let’s set-up a SIP client for a quick test!

Set up your SIP Client

For our initial testing, we’ll use X-Lite. You can download it for Windows or Mac by scrolling to the bottom of the page after visiting the link.

Once you have X-Lite installed and running, go to the preferences menu and select ‘Accounts’, entering an account name such as ‘TwilioSIPDomain’. Then follow the below steps:

  • User ID: (your E.164 credential list username you created earlier)
  • Domain: (yourSIPdomain - you must use us1) yourdomain.sip.us1.twilio.com
  • Password: (what you put in your credential list for that E.164 username)
  • Display Name: the same as your User ID above.
  • Authorization Name: the same as your User ID above.
  • Register with domain and receive Calls
  • Click ‘OK’

Twilio SIP with X-Lite configuration example

Upon clicking ‘OK’, you should get a green icon showing your SIP UA is successfully registered to Twilio.

SIP UA registered to Twilio in X-Lite

Let's make our first call!

Now that our SIP UA is successfully registered to Twilio and we mapped our Twilio number to point to our SIP UA, we can place an inbound test call to see if our SIP UA rings. Try calling it now, perhaps by calling your Twilio SIP UA's number with your cell phone.

Did your phone ring?

Incoming call example in X-Lit with Twilio

Excellent!

Now, remember that default URL we encountered earlier when setting up our SIP Domain? Let’s place an outbound call from your SIP UA to any destination.

It won’t work! Twilio will request the TwiML at https://demo.twilio.com/welcome/voice/, and end the call.

Did you see what happened? This SIP Domain Voice Configuration Request URL is telling Twilio how to handle the call, and the instructions returned are just the demo TwiML.

Our next steps are to allow outbound calls from your SIP UA. We’ll replace the default URL with either a TwiML Bin or a Twilio Function, as we discussed earlier!

Outbound SIP calling with a TwiML Bin

For SIP UA Outbound calls with a TwiML Bin, follow the steps below:

  1. Go to TwiML Bins on your console
  2. Click the big red plus sign (‘+’)
  3. Give the TwiML Bin a friendly name like ‘SipClientOutbound’
  4. Paste in the TwiML below (replacing the existing content):
<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Dial answerOnBridge="true" callerId="{{#e164}}{{From}}{{/e164}}">{{#e164}}{{To}}{{/e164}}</Dial>
</Response>
  1. At the bottom of the edit box, it should say: ‘Valid Voice TwiML’ if everything went well
  2. Click the ‘Create’ Button
  3. Scroll to the top and copy the URL to your Clipboard (or click the copy icon)
  4. Navigate back to your [SIP Domain](https://www.twilio.com/console/voice/sip/endpoints)
  5. Click on Your SIP Domain - `yourdomain.sip.twilio.com`
  6. Paste the URL into the Voice Configuration Request URL field and click ‘Save’

You should now be able to make outbound calls to the phone network from your SIP Phone.

Let's give it a try: try calling your cell phone number (or another verified number) from your SIP UA. If you are running into issues with the call not going through, please refer to the troubleshooting section.

Outbound SIP calling with a Twilio Function

Let's now replace the TwiML Bin we created in the last step with a Twilio Function, which will allow for more complex call flows (and potentially fewer legs).

  1. Visit your Twilio Function Configuration
  2. Check the Box next to: "Enable ACCOUNT_SID and AUTH_TOKEN"
  3. Under Dependencies, click the plus sign (‘+’) to add a new NPM Module
  4. For Name, enter exactly: google-libphonenumber
  5. For Version, enter: 3.2.2
  6. For the existing Twilio NPM package, update the version number to 3.28.1.
  7. Click ‘Save’ (you may need to click around a bit until the ‘Save’ button is activated).
  8. Visit Twilio Functions
  9. Click the ‘Create a Function’ button
  10. Click the ‘Blank’ template
  11. Click the ‘Create’ button
  12. Enter sipDomainRouter or a name you choose as the Friendly Name
  13. Enter sipDomainRouter or the path name you choose for your path
  14. Copy the contents of the JavaScript below into the code text box (replacing the existing content)
  15. Click ‘Save’
  16. Copy the full URL of this Function by clicking on the copy button icon
  17. Visit the SIP Domain, click on your SIP Domain, and paste the URL into the ‘Voice Configuration Request URL’ field
  18. Click ‘Save’.

NOTE: The default country number formatting is for the United States. You can alter the Voice Configuration Request URL to pass a different defaultCountry parameter, using ISO alpha2 format. For example, for the United Kingdom, the Voice Configuration Request URL would look like:

https://YOURRUNTIMEDOMAIN.twil.io/YOURPATH?defaultCountry=GB

Note the addition of: ?defaultCountry=GB, to the end of the URL.

Go back to your Functions, click on your Function and scroll down to the bottom. There you can view the console output as you make calls from your SIP UA.

Make a SIP UA call, and verify the call is successful.

Note: Please update the value of the variable, defaultCallerId, currently set to +15005551212 to a number in your Twilio account. This number is used as the default Caller ID when placing a phone call from a SIP UA registered with a non-E.164 username.

/* URL Parameters
URL parameters: defaultCountry=[international country code - ISO alpha2]
Feel free to remove any console.log statements.
*/
// Require `PhoneNumberFormat`.
const PNF = require('google-libphonenumber').PhoneNumberFormat;
// Get an instance of `PhoneNumberUtil`.
const phoneUtil = require('google-libphonenumber').PhoneNumberUtil.getInstance();
exports.handler = function(context, event, callback) {1
    const client = context.getTwilioClient();    
    let twiml = new Twilio.twiml.VoiceResponse();
    const { From: fromNumber, To: toNumber, SipDomainSid: sipDomainSid } = event;
    let mergedAggregatedE164CredentialUsernames = [];
    let regExNumericSipUri = /^sip:((\+)?[0-9]+)@(.*)/;
    let regAlphaSipUri = /^sip:(([a-zA-Z][\w]+)@(.*))/;
    // Change the defaultCallerId to a phone number in your account
    let defaultCallerId = '+15005551212';
    let defaultCountry = event.defaultCountry || 'US';
    let fromSipCallerId = (fromNumber.match(regExNumericSipUri)
    ? fromNumber.match(regExNumericSipUri)[1] :
    fromNumber.match(regAlphaSipUri)[2]);
    if (!toNumber.match(regExNumericSipUri)) {
        console.log('Dialing an alphanumeric SIP User');
        twiml.dial({callerId: fromSipCallerId, answerOnBridge: true})
        .sip(toNumber);    
        callback(null, twiml);
    }
    let normalizedFrom = (fromNumber.match(regExNumericSipUri)
    ? fromNumber.match(regExNumericSipUri)[1] : defaultCallerId);
    let normalizedTo = toNumber.match(regExNumericSipUri)[1];
    let sipDomain =  toNumber.match(regExNumericSipUri)[3];
    console.log(`Original From Number: ${fromNumber}`);
    console.log(`Original To Number: ${toNumber}`);
    console.log(`Normalized PSTN From Number: ${normalizedFrom}`);
    console.log(`Normalized To Number: ${normalizedTo}`);     
    console.log(`SIP CallerID: ${fromSipCallerId}`);
    // Parse number with US country code and keep raw input.
    const rawFromNumber = phoneUtil.parseAndKeepRawInput(normalizedFrom, defaultCountry);
    const rawtoNumber = phoneUtil.parseAndKeepRawInput(normalizedTo, defaultCountry);    
    // Format number in E.164 format
    fromE164Normalized = phoneUtil.format(rawFromNumber, PNF.E164);
    toE164Normalized = phoneUtil.format(rawtoNumber, PNF.E164);
    console.log(`E.164 From Number: ${fromE164Normalized}`);
    console.log(`E.164 To Number: ${toE164Normalized}`);
    function enumerateCredentialLists(sipDomainSid) {
        return client.sip.domains(sipDomainSid)
            .auth
            .registrations
            .credentialListMappings
            .list();
    }
    function getSIPCredentialListUsernames(credList) {
        return client.sip.credentialLists(credList)
            .credentials
            .list();  
    }      
    enumerateCredentialLists(sipDomainSid).then(credentialLists => {
        Promise.all(credentialLists.map(credList => {
            return getSIPCredentialListUsernames(credList.sid);
        })).then(results => {
            results.forEach(credentials => {
                // Merge together all SIP Domain associated registration
                // credential list usernames prefixed by + into one array
                mergedAggregatedE164CredentialUsernames.push
                .apply(mergedAggregatedE164CredentialUsernames,
                credentials.filter(record => record["username"].startsWith('+'))
                .map(record => record.username));
            });
            console.log(mergedAggregatedE164CredentialUsernames);
            if (mergedAggregatedE164CredentialUsernames.includes(toE164Normalized)) {
                console.log('Dialing another E.164 SIP User');
                twiml.dial({callerId: fromSipCallerId, answerOnBridge: true})
                .sip(`sip:${toE164Normalized}@${sipDomain}`);
            } else {
               console.log('Dialing a PSTN Number');
               twiml.dial({callerId: fromE164Normalized, answerOnBridge: true},
               toE164Normalized);
            }    
                callback(null, twiml);
            }).catch(err => {
                console.log(err);
                callback(err);
            });
    });
};   

Troubleshooting SIP and Twilio

Trial Account Restrictions

Twilio trial account have certain restrictions. You can follow the steps below to improve your experience:

  • Outbound trial calls can only be placed to a verified phone number. Before attempting to place an outbound call, verify the number you’re calling.
  • Some high cost and premium access numbers aren't reachable by default. For help enabling calling to countries outside of the US and Canada, please see our Geographic Permissions article.
  • Trial accounts can only use your account's Twilio number or a Verified Caller-ID as the Caller-ID (From number) when making outgoing calls.

Additional details on Twilio trial accounts can be found in the article How does Twilio's Free Trial work?.

Debugger / Request Inspector

The Twilio console provides some excellent debugging tools should you hit issues.

In the upper right corner of your Twilio Console session, you will see a small bug. If that bug lights up after an event, it indicates an error has occurred. If that happens, click the bug and select "Go to the Debugger" to view the errors.

You can find more details on using the Debugger by reading Debugging your application.

Summary on SIP Domains, calling, and Twilio

We have accomplished quite a lot in this blog post.

Each SIP Domain call is made up of call legs. For two party communications, there is a “parent” call leg and a “child” call leg, with your routing logic in between. You learned how to set up a Twilio SIP Domain and the best practices for naming credential list usernames while provisioning users. You implemented two different Voice Configuration Request URL design approaches for returning call routing TwiML: TwiML Bins and Twilio Functions. Most importantly, we discussed these different approaches and some of the tradeoffs.

What’s Next?

The next step for most folks is to add logic (using Twilio Functions) for inbound calling to your SIP Domain users’ Twilio numbers. Then you can have unanswered calls divert to voice mail or some alternate destination of your choosing.

I would love to hear and see what you build with it! Please let me know of other future blog posts you would like to see on this or other topics.

Twilio also offers another SIP product, Elastic SIP Trunking. Twilio Elastic SIP Trunking provides a direct SIP (VoIP) connection to the PSTN for calls to and from existing communication infrastructure, usually a Private Branch Exchange (PBX) or equivalent. Functionality such as IVR, SimRing, Voicemail, and so on are provided by your existing infrastructure rather then Twilio.

Later I'll write about integrating with Twilio's Elastic SIP Trunking.

Alan Klein is a Sales Engineer based in the rapidly growing Atlanta, GA Office. Alan is a Serverless solution champion and Programmable Voice and Elastic SIP Trunking SIP Expert at Twilio. He's currently focused on furthering his knowledge in Node.js and front-end development and sharing his knowledge with others. You can reach him at aklein [at] twilio.com or on Twitter at @SystemsEng.

Additional SIP Domain Resources

Authors
Sign up and start building
Not ready yet? Talk to an expert.