Scheduled call forwarding using Twilio, AWS Lambda & API Gateway

Introduction

I was recently tasked with implementing time based call forwarding at my workplace.  My company has an onsite team that takes calls on a zendesk provided number during business hours and we have a team offshore that would get any incoming calls outside our business hours.  We wanted the ability to automatically route incoming calls to Zendesk between the hours of 5 AM to 5PM and to the third party vendor outside of these hours.  Initially, we were working with 8X8 to use their service but due to the need to route calls and the call quality provided, we switched to Twilio.

Design

We are going to use Twilio as our provider for phone numbers. Any time there is a call to the twilio provided number, we can take action by connecting to a certain URL.  In other words, Twilio provides the ability to call a POST or GET on some URL to manage how we handle calls.  For low volume of the calls initially, we will be using AWS Lambda/API Gateway as it is easily scalable and relatively cheap service. In future, if the call volumes increase beyond a certain point, we can expose an endpoint from within our app to handle the response for call forwarding.

TwiML Bins

For simple call forwarding with no scheduled switch, Twilio provides a nice XML like language called TwiML (Twilio Markup Language).  When we port numbers to Twilio, twilio provides us with the ability to call external URL using TwiML (Twilio Markup Language) or webhooks.twilio_1

If you navigate to Phone numbers and purchase a number, you will be taken to the screen as shown above.  You can setup simple call forwarding at all times by clicking on the + sign next to TwiML dropdown which will take you to the screen below and allow you to configure the call forwarding to number 1-123-456-7890 in my sample case.
twilio2
For more information on the TwiML syntax for the Dial verb, you can navigate to Dial Verb API.  For our requirement to allow call forwarding for specific hours, however, this approach will not work.  TwiML doesn’t allow complex conditional call forwarding.  To allow for that, we need to host our own webhook code online.

AWS Lambda

AWS Lambda is a compute service that allows user to upload code that will be run as a service on AWS infrastructure.  In our case, we want to trigger the execution when we have a call event on any of the twilio numbers.  I am using Node.js for the project because it has a good support community for Lambda on AWS.  What we want to do is check for the time of the day when the call is generated and based on that respond with a different TwiML to forward call.

API Gateway

The API gateway will be used by us to provide REST endpoint for the Twilio webhook.  On any incoming call, Twilio will hit the API Gateway endpoint that will trigger the Lambda function and pass back the XML response to Twilio webhook thus forwarding the call.

Node.js callForwarding.js code

  • Install node.js
  • Create a folder called twilio-code
  • npm init
    

    This will setup the node project with package.json file

  • npm install moment
    

    I have used moment library to compare the hour of the day. AWS uses UTC time so factor that in the code.

  • Create the twilioCallForwarding.js code and test it locally
  • Final step is to zip up the contents of twilio-code folder in a file named twilioCallForwarding.zip

twilioCallForwarding.js code

var moment = require('moment');
var now = moment();

exports.handler = function (event, context) {
// Event will contain the information passed from Twilio to Lambda.
console.log("Event information: "+JSON.stringify(event));

qryObject = parseQuery(event.reqbody);
var numCalled = qryObject['To'];
var openXml = '<?xml version="1.0" encoding="UTF-8"?><Response><Dial timeout="60">';
var closeXml = '</Dial></Response>';

// Check for time and act accordingly
var hour = now.hour();
responseXml = '';

// Remember that AWS uses UTC time and I used PDT time
if ((hour >= 12) && (numCalled == '+19876543210')) {
responseXml = openXml+'+11234567890'+closeXml;
} else if (numCalled == '+19876543210') {
responseXml = openXml+'+12345987600'+closeXml;
}

// Log responseXml for verification
console.log(responseXml);

context.succeed(responseXml);
};

// Twilio call passes parameters as application-x-www-urlencoded that need to be parsed for our use and hence we will use the following method to parse it.
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;
}

AWS provides the handler function with two arguments of event and context (additionally you can also have error as an argument) and refer the lambda documentation to refer how we use them.  Event normally stores parameters that were passed as part of the POST request and context will store the state and response value from Lambda function.

Setting up AWS Lambda

Once you login to the AWS management console, navigate to Lambda under compute section.  On clicking the create a new function link, you will be navigated to blueprint page.  In this case, select runtime of ‘Node.js 4.3’ and filter for ‘twilio-simple-blueprint’.

This will take you to the configure triggers page.  We want our trigger to be an HTTP POST call from Twilio and we will be using API Gateway to handle the event trigger.  Configure the service as following figure shows:

trigger

Lastly, we get to the configure function page.  Name your function the same name as the .js file which will be the entry point to the Node.js code and that contains the exports.handler function.  Modify the handler on the config UI to be twilioCallForwarding.handler.  As we are not going to access any other AWS data (RDS, S3, etc) we don’t need to define a VPC for the function.  The final screen after configuration is as follows:

function

Notice that I have used an existing role that I had created previously for another project.  This role has policies defined that allow access to AWS Lambda, Cloudwatch, API gateway and S3 bucket operations.  Upload a zip named twilioCallForwarding.zip which contains the .javascript source files and all necessary node_modules and head onto the next review screen.  Once you review the function, we can proceed to test the function and verify results.

Setting up API gateway

Proceed to Amazon API Gateway service and click on Create API and enter values as below.

api1

This will create an API for us that we need to add methods/endpoints to. Amazon refers to them as resources.  Click on Actions dropdown and create a New Child Resource with name CallForwarding having resource path of callForwarding.  Select the newly created resource and add a new method to it for POST operation.

 

updatedapi

Next, we will setup the POST method to use our Lambda function located in us-west-2 region.  This will take us to a screen with Method execution flow outlined.  Click on the Integration Request and open the Body mapping templates.  Twilio uses form-urlencoded type to send parameters across which include information such as From number, to number, region of call origination, destination of call, state of the call, etc.  Add a mapping template for type ‘application/x-www-form-urlencoded’ and text as shown in the diagram below and click save to save the changes.

api3

Modify the Method Request to be open for everyone so as to allow everyone access to the API without the need for API key.  This will allow Twilio to call our Endpoint from outside the amazon network.

Next, navigate into the Method Response section and add a Response Model to allow for application/xml response as Twilio expects xml response from our service to redirect calls.  Don’t worry about the response headers as they will be set automatically later on.

api4

Lastly, we need to configure the Integration Response section and add Body Mapping Template that will return application/json with following template:

api5

Now navigate back to the method execution screen and click on our resource method. From the Actions dropdown, select Enable CORS and test the API endpoint.

As a final step, we need to set the URL provided by the API gateway in the Twilio webhook section for phone numbers as shown in the diagram below.  Now calling this Twilio number will forward calls depending on the time of the day.

screen-shot-2016-10-17-at-10-48-43-pm