For the longest time, I've used a Skype-powered VOIP phone number as my primary business line. It helps me keep phone calls separate - friends and family call my cell directly, business contacts call Skype. Because the number is virtual, I can disable it overnight to get some sleep (while allowing emergency calls from family to wake me if necessary.

The only problem - there's a software company in town with a customer support line two digits transposed from mine. Their software must not be very good, because I get 3-4 wrong number calls per week from disgruntled customers looking for help or refunds or just to vent.

Some of the customers are getting downright abusive.

could just change my phone number. But I've already printed business cards and, frankly, I'm too lazy to order new ones. Instead, I'm going to transfer the VOIP number to Twilio and program a service to re-route the wrong numbers to the right location.

The Plan

At this year's php[world], I spent a bunch of time working my way through Twilio Quest and learning about the neat features of the platform. One that stuck out to me was the ability to forward calls from a Twilio number to a cell.

Another feature was the ability to create a navigable menu system for callers. I can leverage both of these features to redirect erroneous numbers to the correct location.

In the end, I want to move my Skype number over to Twilio and leverage the Programmable Voice API to allow callers to select out when they misdial. A message will prompt them to press one number to be connected to the other business (in the event of a misdial), while another will either forward them to my cell or prompt them to leave a voicemail (depending on the time of day).

Skype Port

None of this will work so long as my number stays at Skype. Luckily, Twilio states clearly that you can easily port another VOIP number to their platform.

I started through the process, filling out the authorization forms and generating PDF printouts of my Skype bill for the number. It took about a week for the number to transfer over fully, but the process itself was rather painless.

Note: Skype won't actually cancel your number for you. Unless you go into your Skype settings and manually cancel the subscription, you'll get billed by both Twilio and Skype for the same thing!

If you plan to do this yourself, make sure you set the incoming number up within Twilio first. I configured mine to handle both incoming calls and incoming texts by forwarding all traffic to my cell. This meant I wouldn't lose any connections, even while still working on a proper call router.

Forwarding voice is simple with a TwiML Bin:



    555-123-4567

Forwarding text is just as simple with a TwiML Bin:



  : 

Using both of these forwarding systems, I can ensure I don't miss any calls while I wait for things to switch over. It's a solid way to keep track of any incoming messages. The only hitch is that I can't make outgoing calls or send texts from the new number. But that's perfectly OK with me.

The Menu System

Setting up a dynamic menu uses Twilio's Interactive Voice Response (IVR) system. This allows callers to leverage either their touch-tone phone or their voice to navigate through the system.

For my purposes, I wanted people to know they got a wrong number and automatically opt-out of bothering me. In my menu system, I prompt them to "press or say 1" if they wanted to reach the other business. As with the temporary forward above, this leverages TwiML, but using the "gather" verb:



    
        You've reached Eric Mann. If you're looking for [name redacted], you have a wrong number. Press 1 and I'll forward you. Otherwise, stay on the line to speak with Eric.
    
    555-123-4567

The only problem here: the menu doesn't actually handle the keypress. In order to do that, we need a dynamic application that can parse and handle the response then forward the call on to where it needs to go.

AWS Lambda

love building tools atop Amazon Web Services. Their newer serverless offering, Lambda, lets me build one-off functions that run in the cloud and are only billed when they're in use. In other words, you can write a JavaScript routine to handle the incoming request and send out a response; Amazon only bills you when the function is invoked and it only costs pennies.

The first step is to set up a function in the AWS Lambda console. Once logged in, we can create our first function. We'll call it "ivrRedirect," run it on the most modern version of Node available, with a newly-created custom role that just has the "lambda_basic_execution" permission.

AWS Lambda Configuration

The next step is to parse the incoming request from Twilio so we can extract the digits pressed and act upon the user's request. To keep things simple, we'll keep the same order of options from our TwiML above for creating our first function:

console.log('Loading function');
 
exports.handler = function(event, context) {
    var output = {
        message: "You've reached Eric Mann. If you're looking for [name redacted], you have a wrong number.",
        options: [
            "to have me forward you to [name redacted].",
            "speak with Eric."
            ]
    }
    context.succeed(output);
};

We'll also need to follow the same steps to create a second function to wire in the TwiML to make each of these options actually work:

console.log('Loading function');
 
exports.handler = function(event, context) {
    options = [
           "+1-555-123-4567",
           "+1-555-234-5678"
        ]
        
   qryObject = parseQuery(event.reqbody);
   
   context.succeed(options[qryObject['Digits']-1]);
};
 
function parseQuery(qstr) {
        var query = {};
        var a = qstr.substr(0).split('&');
        for (var i = 0; i < a.length; i++) {
            var b = a[i].split('=');
            query[decodeURIComponent(b[0])] = decodeURIComponent(b[1] || '');
        }
        return query;
}

These two functions give us everything we need to handle incoming Twilio requests and figure out what behavior to execute. Unfortunately, neither is directly callable from the web!

API Gateway

To make our function callable from Twilio, we need to put an API in front of it. Amazon's API Gateway gives us all the functionality we need here. We can build a dynamic interface, expose it to Twilio, and route our incoming calls without ever building out a server! We'll call our new API "IVR Redirect" and build it up from scratch:

Create a new API Gateway project

Once we have the API created, we immediately add a new resource called "prompt." This gives us a /prompt endpoint for the API, but otherwise won't do anything on its own. We have to add an action of POST and wire in our lambda function from earlier:

Configuring the POST action to invoke our lambda function.

Everything on the AWS side has dealt with JSON thus far. We need to convert our response to TwiML before we send things back to Twilio. Thankfully, we can do that with some handy templates on the service side:

#set($inputRoot = $input.path('$'))
#set($i = 1)

    
        $inputRoot.message
        #foreach($elem in $inputRoot.options)
            Press $i to $elem
            #set($i = $i + 1)
        #end
        +1-555-555-5555
    

If you look carefully, you'll see this is almost the exact TwiML we started out with! We just use some Amazon magic to map through the various options returned by our lambda function. This will be super useful should we ever want to expand the system in the future!

There is a lot more work that goes into fully fleshing out the templates and opening up API Gateway. The Twilio team has already documented it, so I won't reproduce all of their work here. What I will do, however, is celebrate the chance that I'll not get any more wrong calls intended for this other company!

The only thing I'm worried about now is the potential cost of actually forwarding traffic. The phone number costs $1/month. Incoming calls cost less than 1 cent per minute. I'm not anticipating this will become a huge expense (and will be far less than the loss of productivity when I'm constantly interrupted). If it becomes a problem, though, I'll reach out to the other company and ask them to cover it.

If they won't, I stop forwarding customers. It's simple.