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

February 28, 2019
Written by
Alan Klein
Twilion

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 of 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 of SIP Domain registered devices

Before we get started, let’s discuss some of the benefits 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.

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 blue plus sign (‘+')
  3. Enter a FriendlyName and give your SIP URI a unique name, (yourdomain), which will be appended by sip.twilio.com.
  4. We’ll change the Call Controll Configuration at a later step. This will be either our TwiML Bin example or our Twilio Function example. For now, copy and paste the placeholder TwiML URL, https://demo.twilio.com/welcome/voice/ in the edit box titled, A Call Comes In. 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>

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 Telephone. You can download it for Windows or Mac by scrolling to the bottom of the page after visiting the link.

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

  • Full Name: (your E.164 credential list username you created earlier)
  • Domain: yourdomain.sip.us1.twilio.com
  • User Name: the same as your Full Name above.
  • Password: (what you put in your credential list for that E.164 username)
  • Click ‘Done’

Twilio SIP with Telephone configuration example

 

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

SIP UA registered to Twilio

 

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? 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 blue 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>

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 the Twilio Function page
  2. Click on the blue button saying ‘Create Service’.
  3. Enter sipDomainRouter or a name you choose as the Friendly Name
  4. Under Dependencies to add a new NPM Module for the module google-libphonenumber and for version, enter: 3.2.30. Confirm with ‘Add’
  5. In the very same way, add the Twilio NPM package with the version number 3.80.0
  6. Create a new file (via "Add +") and copy the contents of the JavaScript below into the code editor (replacing the existing content)
  7. Click ‘Deploy All’ (you may need to click around a bit until the ‘Save’ button is activated)
  8. Copy the full URL of this Function by clicking on the copy button icon
  9. Visit the SIP Domain, click on your SIP Domain, and paste the URL into the ‘Voice Configuration Request URL’ field
  10. Click ‘Save’

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.

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