DEV Community

Cover image for Make and Receive Calls with JavaScript + Vonage APIs πŸš€
Sudipto Ghosh
Sudipto Ghosh

Posted on • Edited on

Make and Receive Calls with JavaScript + Vonage APIs πŸš€

In this tutorial, we will be creating a Node.js application to have a basic understanding of how to make outgoing calls and handle incoming calls programmatically. We will be leveraging the Vonage Voice API and the Node.js Server SDK for Vonage APIs to do the heavy-lifting for us.

All of the code covered in this tutorial is available on the companion repository on GitHub in case you want to take a look at the code directly.

GitHub logo sudiptog81 / calls-with-js

Make and Receive Calls with JavaScript and the Vonage Voice API

Make and Receive Calls with JS and Vonage APIs

Quick Start

Clone and Install Dependencies

git clone https://github.com/sudiptog81/calls-with-js.git
cd calls-with-js
yarn
Enter fullscreen mode Exit fullscreen mode

Override Environment Variables

Create a file named .env as per the template given in .env.example. Get the values for Vonage specific variables from the Vonage Dashboard.

Start an HTTP Tunnel with ngrok

Assuming PORT has a value of 5000 in .env.

ngrok http 5000
Enter fullscreen mode Exit fullscreen mode

Override WebHook URLs in Vonage Dashboard

  • Answer URL: <ngrok-tunnel-url>/answer
  • Event URL: <ngrok-tunnel-url>/event

Run the Application

yarn dev
Enter fullscreen mode Exit fullscreen mode

Call a Friend

Replace <number> with your friend's number and <message> with a custom message.

curl http://localhost:5000/call?to=<number>&msg=<message>
Enter fullscreen mode Exit fullscreen mode

Ask Them to Call Back

Note: They will be rick-rolled!

License

The MIT Open-Source License.




Requirements

Make sure you have a recent version of the Node.js JavaScript runtime, a package manager for Node.js - npm or yarn - installed, and ngrok for creating a public endpoint.

$ node -v        
v15.11.0
$ npm -v                 
7.6.3
$ yarn -v        
1.22.10
$ ngrok -v
ngrok version 2.3.35
Enter fullscreen mode Exit fullscreen mode

We will also need a code editor such as Visual Studio Code. Apart from these, we will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit.

Initializing Awesomeness

Create a new project directory (I'll call it js-calls in this tutorial) and navigate to that directory in a terminal window.

mkdir js-calls
cd js-calls
Enter fullscreen mode Exit fullscreen mode

Once that is done, use npm or yarn to initialise a new Node.js project.

yarn init -y # or npm init -y
Enter fullscreen mode Exit fullscreen mode

The above command will accept all the defaults, so if you wish to override some of the values, you might prefer using the following instead:

yarn init # or npm init
Enter fullscreen mode Exit fullscreen mode

We will add a few dependencies before we head on to the next section. express is a web framework that we'll use to spin up a few HTTP endpoints, morgan will be a request logger for the said endpoints, dotenv will manage the environment variables for us and @vonage/server-sdk will allow us to interact with the Vonage APIs.

nodemon will be a development dependency that allows us to focus on developing the application without stopping it and running it again, essentially being a live reload solution that restarts the code whenever there is a change in the source code.

yarn add express morgan dotenv @vonage/server-sdk
yarn add -D nodemon
Enter fullscreen mode Exit fullscreen mode

At this point, I like to add a couple of scripts in the package.json file. I'd add a start and a dev script for this.

{
  ...
  "scripts": {
    "start": "node .",
    "dev": "nodemon ."
  },
  ...
}
Enter fullscreen mode Exit fullscreen mode

Taking Care of Chores

In order to work with the Vonage Voice API, we need to create a Vonage Application and provision a virtual phone number. To do this, go to the Vonage dashboard and click on Your Applications in the sidebar. Continue to Create a new application.

Creating a New Application - 1

Give your application a unique name to identify it on the dashboard. Generate a new public-private key pair and save the private key in the project directory.

Creating a New Application - 2

Scroll down and click the button that says Generate new application. Yay! You just created a Vonage application. You'll probably be redirected to the Application Overview page. If you scroll up, you will come across the Application ID. There are some additional configurations that we'll come across as we get this going.

Next up, we have to reserve a phone number and link it to this newly created application. Go to the Numbers section on the sidebar and navigate to Buy Numbers. You'll be greeted with a form asking you for the country and features you want the number to be equipped with.

I'll go ahead with selecting United States for this one. For the features, I'll tick only the VOICE feauture, select Mobile as the type and click on Search. We are greeted with a list of numbers available. If you recall, signing up for a new account gave us a few credits, we may use it as well for reserving a number. Let's buy the first one in the list. It might open a popup asking you to confirm your choice and let you know of any limitations. We will not be using the SMS offering in this tutorial.

Purchasing a number

Once you purchase a number, head back to Your Applications and click on the name of the application that you created for this tutorial. Scroll down and link the number you purchased, with this application.

Link a number with an application

Once all this is done, go to the Dashboard home by clicking on the Vonage icon and also take note of the API key and the API secret. Do not share the API secret with anyone!

dashboard-keys-secrets

At this point, you are aware of few key pieces of information that we will need soon - the Vonage number you purchased, the Vonage application ID, the API key and the API secret. Let's get to the code now.

Create a file named .env and populate the values for environment variables with this information. Populate PORT with the port number you want the application to listen on, I'll use 5000. TO_NUMBER will be a valid phone number in the E.164 format, without any leading +, 00 or any other access code, that we define as the default number to call to.

When working with Vonage APIs, all phone numbers should be in this format, that is, the country code digits followed by the subscriber number.

VONAGE_NUMBER, VONAGE_API_KEY, VONAGE_API_SECRET and VONAGE_APPLICATION_ID can be obtained from the Vonage dashboard. Recall that you generated a public-private key pair while creating a Vonage application. Provide the absolute path to that file with the correct file path separator for your operating system and assign that path to VONAGE_PRIVATE_KEY_PATH.

TO_NUMBER=
VONAGE_NUMBER=
VONAGE_API_KEY=
VONAGE_API_SECRET=
VONAGE_APPLICATION_ID=
VONAGE_PRIVATE_KEY_PATH=
PORT=
Enter fullscreen mode Exit fullscreen mode

Making a Call

Create an index.js file in the project directory, require and configure the dotenv module early in the application and import the dependencies needed in this tutorial - they will be the Vonage Server SDK, Express.js and the Morgan middleware.

require('dotenv').config();
const Vonage = require('@vonage/server-sdk');
const express = require('express');
const morgan = require('morgan');
Enter fullscreen mode Exit fullscreen mode

Next, instantiate an Express.js application and an instance of the Vonage class. The constructor accepts an object with the following required keys - apiKey, apiSecret, applicationId and privateKey - all of which can now be accessed through the process.env object.

const app = express();
const vonage = new Vonage({
  apiKey: process.env.VONAGE_API_KEY,
  apiSecret: process.env.VONAGE_API_SECRET,
  applicationId: process.env.VONAGE_APPLICATION_ID,
  privateKey: process.env.VONAGE_PRIVATE_KEY_PATH
});
Enter fullscreen mode Exit fullscreen mode

Configure Express.js to parse JSON in the request body of POST requests and to use the Morgan logger.

app.use(morgan('tiny'));
app.use(express.json());
Enter fullscreen mode Exit fullscreen mode

In order to create a call with the Vonage SDK for Node.js, you need to call the vonage.calls.create() method. This method takes two required arguments - the first one is a JavaScript object and the second one is a callback that is triggered after the SDK attempts to create the call. An example invocation can be as follows, assuming vonage is an instance of Vonage from @vonage/server-sdk:

vonage.calls.create({
  to: [{
    type: 'phone',
    number: process.env.TO_NUMBER
  }],
  from: {
    type: 'phone',
    number: process.env.VONAGE_NUMBER,
  },
  ncco: [{
    action: 'talk',
    text: 'This call was made from JavaScript.',
    language: 'en-IN',
    style: '4'
  }]
}, (err, resp) => {
  if (err)
    console.error(err);
  if (resp)
    console.log(resp);
});
Enter fullscreen mode Exit fullscreen mode

Here, the to property accepts an array of JS objects which have the following fields - type, number, and optionally dtmfAnswer. The from property accepts a JS object that has the type and number fields. The ncco property accepts a Nexmo Call Control Object that defines the flow of a call made using the Vonage Voice API. The Voice API Reference is also a great resource in know more about the form in which the API expects the requests to be.

Using a Nexmo Call Control Object, you can stream audio files into a call, connect different phones, send synthesized speech generated by a TTS module and what not. Do take a break and look at the documentation on NCCO!

Even if you try to run this application at this stage, assuming you have the environment variables set up correctly, you'll receive an error telling you that Voice Capabilities are not enabled in the Vonage application that we create using the dashboard. Let's backtrack a bit and revisit the application on the Vonage Dashboard.

Click on the Edit button on the overview page of your application and flip the switch for Voice under the Capabilities section. You'll notice that there are a few text fields that need to be filled before we can turn this capability on - the first two are mandatory. These are expected to be webhook endpoints to which the Vonage APIs make HTTP requests to. If you observe carefully, these can be GET or even POST endpoints.

Capabilities page

Let us go back to our code and define these endpoints. For the Event Webhook, we just need to return a status code 200 for all incoming requests. I like to use POST for my endpoints when possible.

For the Event URL, we will use the /events route and simply log the request body to the console and reply with a 200 status code.

app.post('/event', (req, res) => {
  console.log(req.body);
  res.status(200).send('');
});
Enter fullscreen mode Exit fullscreen mode

We will take a look at how to handle incoming calls in the next section. At this point, we can assume that we shall use the /answer route for the Answer URL webhook endpoint.

Configure the Express.js instance to listen on a specified port.

app.listen(process.env.PORT, () => console.log(`Running on port ${process.env.PORT}`));
Enter fullscreen mode Exit fullscreen mode

At this point, we have a basic structure for the endpoints, however, we need a publicly accessible URL for these endpoints. We will use ngrok to create a tunnel to our application running on localhost. Execute the following command on another terminal window. Take note of the URLs that are displayed on the terminal.

ngrok http 5000 # replace this with the correct PORT
Enter fullscreen mode Exit fullscreen mode

Using ngrok to create a tunnel

The web interface for ngrok allows us to inspect and replay the HTTP requests being received by the tunnel. Requests sent to the two URLs displayed below that will be forwarded to our application. We now have predefined routes and a publicly accessible endpoint for our application. We can now fill in the details for enabling the Voice capability. Save the application on the dashboard once the details are filled in.

Updating webhook endpoints

At this point, the index.js file should look like this:

require('dotenv').config();
const Vonage = require('@vonage/server-sdk');
const express = require('express');
const morgan = require('morgan');

const app = express();
const vonage = new Vonage({
  apiKey: process.env.VONAGE_API_KEY,
  apiSecret: process.env.VONAGE_API_SECRET,
  applicationId: process.env.VONAGE_APPLICATION_ID,
  privateKey: process.env.VONAGE_PRIVATE_KEY_PATH
});

app.use(morgan('tiny'));
app.use(express.json());

vonage.calls.create({
  to: [{
    type: 'phone',
    number: process.env.TO_NUMBER
  }],
  from: {
    type: 'phone',
    number: process.env.VONAGE_NUMBER,
  },
  ncco: [{
    action: 'talk',
    text: 'This call was made from JavaScript.',
    language: 'en-IN',
    style: '4'
  }]
}, (err, resp) => {
  if (err)
    console.error(err);
  if (resp)
    console.log(resp);
});

app.post('/event', (req, res) => {
  console.log(req.body);
  res.status(200).send('');
});

app.listen(process.env.PORT, () => console.log(`Running on port ${process.env.PORT}`));
Enter fullscreen mode Exit fullscreen mode

If you try running this application now, by executing yarn dev, you should notice a call being made to the number as defined in TO_NUMBER, and a few requests being received on the ngrok web interface.

You should also see a request like this being sent to /events:

Phone ringing event log

Here is a recording of the call you should expect:

We can now clean this up by creating a /call route responsible for making a call to a number and instructing the API to speak a message provided in the request. Replace the earlier invocation to vonage.calls.create() with the following:

app.get('/call', (req, res) => {
  vonage.calls.create({
    to: [{
      type: 'phone',
      number: req.query.to || process.env.TO_NUMBER
    }],
    from: {
      type: 'phone',
      number: process.env.VONAGE_NUMBER,
    },
    ncco: [{
      action: 'talk',
      text: req.query.msg || 'This call was made from JavaScript.',
      language: 'en-IN',
      style: '4'
    }]
  }, (err, resp) => {
    if (err)
      console.error(err);
    if (resp)
      console.log(resp);
  });
  res.json('ok');
});
Enter fullscreen mode Exit fullscreen mode

Run the application now and make the following cURL request after replacing the number.

$ curl "http://localhost:5000/call?to=<phone-number>&msg=You%20just%20got%20rickrolled\!"
"ok"
Enter fullscreen mode Exit fullscreen mode

You should expect the messages and the call to go somewhat like the one given below.

Outbound request

Hooray! You can make a few calls now! In the next section, we go over how to handle an inbound call.

Receiving a Call

For handling an incoming call, the webhook endpoint for the Answer URL must respond with an NCCO as application/json. We can access the calling number using req.body.from. This might be a good point to refer back to the documentation for call control objects.

In the previous section, we assumed that we are going to use the /answer route for handling inbound calls. We define a handler for that in this section. Here, I am responding to a POST request with a NCCO object, as JSON, that will be responsible for greeting the caller and speaking out the phone number from which the call is being made from, and also play an audio stream into the call.

app.post('/answer', (req, res) => {
  const number = req.body.from.split('').join(' ');
  const ncco = [
    {
      action: 'talk',
      text: 'Thank you for calling from ' + number,
      language: 'en-IN',
      style: '4'
    },
    {
      action: 'stream',
      streamUrl: ['https://www.albinoblacksheep.com/audio/mp3/RickRollMarioPaint.mp3']
    }
  ];
  res.json(ncco);
});
Enter fullscreen mode Exit fullscreen mode

Make a call to your Vonage number and keep your fingers crossed! You might hear something like this:

You can also accept user input using DTMF Tones and Speech Recognition, which we can go over in some other tutorial. This shows that we can achieve a lot leveraging Vonage Voice APIs!

Taking a Step Back

Congratulations! We went through setting up the environment, creating a Node.js application, building a few endpoints, and the great part being able to make phone calls and answer them using code that you can reuse in a lot of use cases!

Social Banner

Learn more about the Vonage APIs on their Developer Education Portal.

Top comments (0)