Voice Calling Using Twilio in Node.js

Introduction

Twilio refers to a set of web services, APIs and tools provided by the Twilio company. These are used to send and receive text/picture messages, make and receive phone calls, and embed VoIP calling into web and native mobile applications. They provided many helper libraries, available for various server-side programming environments like Node.js, PHP, .NET, Java, Ruby, Python, Apex etc.

In this blog, we will use the Twilio node module to implement inbound and outbound voice calls in Node.js.

Prerequisites

The code snippets shown in this blog are written using Node.js version 8.9.4.

Create a Twilio account

Before you can make a call from Node.js, you’ll need to sign up for a Twilio account or log in to an account you already have. Head over to Twilio.com/try-twilio to sign up.

Buy a Twilio Number

The next thing you’ll need is a voice-capable Twilio phone number. If you currently do not own a Twilio phone number with voice call functionality, you’ll need to purchase one.

Get Twilio Credentials

Install Twilio node module

You could use Twilio’s HTTP API to make phone calls, but we’ll make things even simpler by using the Twilio module for Node.js.

Let’s use npm to install the required library. Simply fire up a terminal or command line interface on your machine that already has Node and npm installed, and run the following command in your project directory.

1

npm install twilio

The code snippets uses Twilio SDK v3.17.2. Please check the migration guide while migrating from one version to other.

TwiML

TwiML (the Twilio Markup Language) is a set of instructions you can use to tell Twilio what to do when you receive an incoming call, SMS, or fax.

At its core, TwiML is an XML document with special tags defined by Twilio to help you build your Programmable Voice application.

The following will say Hello, world! when someone dials a Twilio number configured with this TwiML:

In the above screenshot the webhook event is A CALL COMES IN.This event is triggered when you receive a call on your Twilio number. When this happens Twilio makes an HTTP request (usually a POST or a GET) to the URL you configured for the webhook.

The application should return TwiML response back to Twilio server.

The Twilio server will then parse that TwiML response and respond to the caller based on that response.

API Code

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

constexpress=require('express');

constVoiceResponse=require('twilio').twiml.VoiceResponse;

constapp=express();

// Create a route that will handle Twilio webhook requests, sent as an

// HTTP GET to /v1/greeting in our application

app.get('/v1/greeting',(request,response)=>{

// Use the Twilio Node.js SDK to build an XML response

consttwiml=newVoiceResponse();

twiml.say({voice:'alice'},'Hello');

// Render the response as XML in reply to the webhook request

response.type('text/xml');

response.send(twiml.toString());

});

// Create an HTTP server and listen for requests on port 3000

app.listen(3000);

The above API will return the following TwiML,

1

2

3

4

<?xml version="1.0"encoding="UTF-8"?>

<Response>

<Say voice="alice">Hello</Say>

</Response>

How we used Twilio’s voice call APIs

We would like to share how we structured our application to handle different voice API calls.

Architecture

We have an alert notification system which sends notification through different mediums such as,

SMS

Email

Voice call

Pager

For sending SMS and making voice calls we used the Twilio API.

The system architecture is very simple to understand.

We wanted to separate the code into various modules based on the role,

Application

This contains the core logic of our application. This is a REST API server developed using NodeJs which handles all the requests from our front end applications (Web portal, mobile app and IoT devices).

Microservice

This micro-service will handle the sending of notifications. This will send SMS, Email, Pager and Voice calls by using the Twilio and Mailgun APIs.

Voice API server

We developed a different server specially to handle all the voice call related routes. This server generates TwiML which gathers user input and submits the user’s response back to one of its own route, which then does further processing.

There is a two way communication between this component and the Twilio API. For example,

Twilio makes a request to this component to get the TwiML to play a message and ask for user input.

The Voice API server will return TwiML which will contain that message.

Twilio server will play that message to the user.

After user gives feedback by pressing a digit, the Twilio server will make another request to Voice call API with the user’s entered digit.

Voice call API will then take the user input, do some processing and respond back with another TwiML. (“Thank you for giving feedback” message)

Twilio server will play the thank you message to the user and the transaction ends here.

Advantages

Following are some of the major advantage,

Well maintained code

Every component does what it needs to do. The core application will have the APIs which are required for the application to run. The micro-service (Notification processor as we named it) will take care of sending different notifications. Finally all the HTTP requests made by Twilio will land on Voice API server which will serve the TwiML.

Quick problem identification

It is very easy to identify an issue or bug, since we have different components that perform specific jobs. If there is an issue receiving notifications then we check only the microservice. If there is an issue with voice calls not being parsed properly then we know that we need to check Voice API server.

Ease of adding new notification type

Adding a new notification type is easy. If tomorrow we decide to add webhook notifications then we need to update the microservice and integrate webhook. No changes are required in the core application and the Voice API server.

Reduced testing scope

The scope of testing and causing a bug is limited to a particular component. If we do code modifications in a component then we are confident that it will not cause any issues in other components.

Use cases

Problem

We had to notify the user for different type of actions through voice call, then take input from the user and update records in our database based on the user’s input.

Goal

To keep it simple lets assume we have 3 different type of actions

Action I

Action II

Action III

For each action we want to take user’s feedback, assume the feedback to be,

Yes (Press 1)

No (Press 2)

Based on the input we want to update the database records. We wanted the system to easily handle any new actions as well.

Solution

Lets try to understand the solution using a block diagram

Microservice will make HTTP request to Twilio server for different actions. Each action will have a corresponding REST API in our Voice API server which will return the TwiML.

Twilio server will then parse this TwiML and make a call to the user.

Once the user enter digits on their keypad, Twilio will submit those digits in a POST request back to our Voice API server.

Voice API server will then update database based on user input.

Code

Let us try to understand the code sample,

Microservice sending notifications

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

constaccountSid='your_account_sid';

constauthToken='your_auth_token';

constclient=require('twilio')(accountSid,authToken);

// Method to make a twilio call for different action type with data

functionsendVoiceNotification(actionType,id){

client.calls

.create({

url:`http://notification.voice.com/${actionType}/id/${id}`,

method:'GET',

to:'+123456789',

from:'+987654321'

})

.then(call=>console.log(call.sid))

.done();

}

// Make a twilio call for action type 1 with id 3 (Some data which will be used later for processing)

sendVoiceNotification('action1',3);

// Similarly make calls for different action type

// sendVoiceNotification('action2', 15);

// sendVoiceNotification('action3', 16);

To keep things simple we wrote a function
sendVoiceNotification() which takes
actionType and
id. When the callee answers the call, Twilio will make a HTTP GET request to our application.

The user entered digits are available in the request body i.e.
request.body.Digits. You can update the database or take further action based on the entered digit.

Note that the call will end with an error if your server doesn’t respond back with some TwiML.

Alternative – Call SID

For every call which is initiated by Twilio there is a unique ID associated with it.
client.calls.create() will return a
call object which contains a
call.sid. This SID can be used to uniquely identify a call.

Alternatively instead of passing data as part of URL like we did i.e.
http://notification.voice.com/action/${actionType}/id/${id}, we could store this info in database and use call SID.

After initiating the Twilio call, we will store the details into database as shown below,

call_sid

action_type

id

CAed0ea7ab63d425e987cb24eXXXX

action1

3

CAed0ea7bb63d425e987cb24eXXXX

action2

15

Instead of using
http://notification.voice.com/action/${actionType}/id/${id} we could simply use
http://notification.voice.com/action

1

2

3

4

// HTTP GET

constcallSID=request.params.CallSid;

// HTTP POST

constcallSID=request.body.CallSid;

Once you have the call SID further processing can be carried out by fetching the additional details from database using the call SID.

Twilio logs

Twilio provides logs for each call made. This is the first place you should check in case your users are complaining about not receiving phone calls, abruptly ending phone calls or any other issue.

Debugging

To debug an issue, click on any call log which failed. Failed calls are highlighted with red color.​

Log summary

This gives a brief detail about the call.

Error and Warning

This section will list out the error or the warning that occurred while processing the call.

For example, in the above image we gave an API route which does not exist.

Request Inspector

This section contains all the requests which were made during the call.

Twilio initially requested for the TwiML using an HTTP GET request.

You can see the TwiML being sent back in response body.

This TwiML is used to take the user’s input (
Gather)and then POST that input to another URL which is specified in the action attribute.

To demonstrate an error condition, we’ve specified an invalid URL in the action attribute.

When the user presses 2 you can see that a request is made by Twilio to the specified API for the next TwiML. The
Digits parameter in the request contains the number that the user dialed.

Note that this request failed with status
404 since the route does not exist.

Summary

Rather than building an app’s Voice and SMS functionality from scratch, developers can make use of Twilio APIs which will be a huge time saver. Here are some other interesting use cases that we found that leverage the power of Twilio to automate things,