Make and Receive Calls with JavaScript + Vonage APIs 🚀
Tags: javascript, tutorial
Published: 2021-03-26 19:31:25

---
title: Make and Receive Calls with JavaScript + Vonage APIs 🚀
published: true
description: 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.
tags: javascript, tutorial
cover_image: https://i.postimg.cc/wBw1KPqm/Dev-Poster-01.png
---

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](https://developer.nexmo.com/voice/voice-api/overview) and the [Node.js Server SDK for Vonage APIs](https://github.com/vonage/vonage-node-sdk) to do the heavy-lifting for us.

{% youtube 2UtY5FOmMGU %}

All of the code covered in this tutorial is available on the [companion repository on GitHub](https://github.com/sudiptog81/calls-with-js) in case you want to take a look at the code directly.

{% github sudiptog81/calls-with-js %}

## 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.

```bash
$ node -v        
v15.11.0
$ npm -v                 
7.6.3
$ yarn -v        
1.22.10
$ ngrok -v
ngrok version 2.3.35
```

We will also need a code editor such as [Visual Studio Code](https://code.visualstudio.com/). Apart from these, we will need a [Vonage API account](http://developer.nexmo.com/ed?c=dev_to&ct=sg-codes). If you don’t have one already, you can [sign up today](http://developer.nexmo.com/ed?c=dev_to&ct=sg-codes) 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.

```bash
mkdir js-calls
cd js-calls
```

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

```bash
yarn init -y # or npm init -y
```

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:

```bash
yarn init # or npm init
```

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.

```bash
yarn add express morgan dotenv @vonage/server-sdk
yarn add -D nodemon
```

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.

```json
{
  ...
  "scripts": {
    "start": "node .",
    "dev": "nodemon ."
  },
  ...
}
```

## 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](http://developer.nexmo.com/ed?c=dev_to&ct=sg-codes) and click on `Your Applications` in the sidebar. Continue to `Create a new application`.

![Creating a New Application - 1](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/te6rf8v1542vkyj0sq24.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lrino31v1ikzxagp67e3.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/dnkamrjlvei5xqtxbx1v.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/r51x91zvyqkvavw3dipi.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/38sjilni439wwu5gi3u0.png)

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](https://en.wikipedia.org/wiki/E.164), 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=
```

## 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.

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

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.

```js
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
});
```

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

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

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`:

```js
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);
});
```

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](https://developer.nexmo.com/voice/voice-api/ncco-reference) that defines the flow of a call made using the Vonage Voice API. The [Voice API Reference](https://developer.nexmo.com/api/voice.v2) 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](https://developer.nexmo.com/voice/voice-api/ncco-reference)!

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ycldqfz5rt5h9l3z2xoe.png)

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.

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

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.

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

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.

```bash
ngrok http 5000 # replace this with the correct PORT
```

![Using ngrok to create a tunnel](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7vcg6ho0tpkeirmhhysc.png)

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/7qv2zwossq0lexvu33r7.png)

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

```js
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}`));
```

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/umci247dtsveiu1cy6rm.png)

Here is a recording of the call you should expect:

{% soundcloud https://soundcloud.com/sudipto-ghosh-510823840/call-recording-1-making-a-call-with-javascript %}

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:

```js
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');
});
```

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

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

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

![Outbound request](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2nrmesmotkk0c8cq7hyo.png)

{% soundcloud https://soundcloud.com/sudipto-ghosh-510823840/call-recording-2-making-a-call-with-javascript %}

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](https://developer.nexmo.com/voice/voice-api/ncco-reference).

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.

```js
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);
});
```

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

{% soundcloud https://soundcloud.com/sudipto-ghosh-510823840/call-recording-receiving-a-call-with-javascript %}

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](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/5rsw6g2epis8who9dl4w.png)

Learn more about the Vonage APIs on their [Developer Education Portal](https://developer.nexmo.com/).