How to Make Phone Calls with the Nexmo Client SDK in JavaScript

In this guide, you'll learn how to place a phone call from a Nexmo application to a phone device (PSTN) by implementing a webhook and linking that to a Nexmo application.

You will create an app to place a call. The app will log in a user called Jane. After logging in, Jane is able to place a call as well as to end it.

Nexmo Concepts

Before proceeding any further, here are couple of concepts that you'll need to understand.

A Nexmo application allows you to easily use Nexmo products, in this case the Voice API to build voice applications in the Cloud.

A Nexmo application requires two URLs as parameters:

  • answer_url - Nexmo will make a request to this URL as soon as someone makes a call to your Nexmo number. It contains the actions that will happen throughout the call.
  • event_url - Nexmo sends event information asynchronously to this URL when the call status changes; this ultimately depicts the flow of the call.

Both URLs need to return JSON and follow the Nexmo Call Control Object (NCCO) reference. In the example below, you will define an NCCO that reads a predefined text for an incoming call, using the Text to Speech engine.

A Nexmo virtual number will be associated with the app and serve as the "entry point" to it - this is the number you'll call to test the application.

For more information on Nexmo applications please visit the Nexmo API Reference.)

Prerequisites

Application webhook

For your application to place a phone call, you'll need to provide a URL as the Answer URL webhook. For the purpose of this tutorial, you will create a gist with the content below:

[
    {
        "action": "talk",
        "text": "Please wait while we connect you."
    },
    {
        "action": "connect",
        "timeout": 20,
        "from": "YOUR_NEXMO_NUMBER",
        "endpoint": [
            {
                "type": "phone",
                "number": "CALLEE_PHONE_NUMBER"
            }
        ]
    }
]

Do not forget to replace YOUR_NEXMO_NUMBER and CALLEE_PHONE_NUMBER with the relevant values for your app.

Once created, add the gist raw URL (make sure you're using the raw version) to your Nexmo dashboard. To do this, navigate to applications, select your application and click the 'Edit' button. Set the application's Answer URL and click 'Save changes'.

You will need to repeat this process every time you're changing the gist as a new revision (with the new raw URL) is being created.

Note: The gist you created is specific to this tutorial. In a real-life scenario, the Answer URL should be provided by a purposely built web solution. Your backend should provide that can serve custom NCCOs and, for this case, receive and validate the phone number dialled from the app.

Adding the Nexmo Client to your application

We'll start with a blank HTML page with two buttons for calling a phone and hanging up a call. Create a minimal index.html file, for example:

<html>
  <head>
    <title>Make Phone Calls</title>
    <script src="./node_modules/nexmo-client/dist/conversationClient.js"></script>
  </head>
  <body>
    <p id="notification"></p>
    <button type="button" id="call">Call</button>
    <button type="button" id="hangup">Hang Up</button>
    <script>

    </script>
  </body>
</html>

We'll need to add the Nexmo Client to it, in order to do that we'll install it from NPM first, by running this command in the same folder as your index.html file:

$ npm install nexmo-client --save

Login

Using the Nexmo Client SDK should start with logging in to ConversationClient, using a jwt user token.

In production apps, your server would authenticate the user, and would return a correctly configured JWT to your app.

For testing and getting started purposes, you can use the Nexmo CLI to generate JWTs.

We'll update the empty <script> tag that's at the bottom of your <body> tag to login with a USER_JWT, and update the notification paragraph when the login was successful. We'll create a new ConversationClient, and then call the login method, with a string for the user JWT. That returns a promise containing an application object, and we'll use that to check we're logged in with the correct user.

<script>
  const USER_JWT = "YOUR USER JWT";

  let notification = document.getElementById("notification");

  new ConversationClient()
      .login(USER_JWT)
      .then(application => {
          notification.textContent = `You've logged in with the user ${application.me.name}`
      })
      .catch(console.log);
</script>

At this point you should already be able to run the app and see that you can login successfully with the SDK. Because the Nexmo Client uses IndexedDB for its sync mechanism, we suggest you don't serve index.html using the file:// protocol. That corrupts the IndexedDB for any other users and makes the SDK behave inconsistently. You can use any HTTP server, like http-server. If you want to install it from NPM and then run it with cache disabled, here are the terminal commands:

$ npm install -g http-server
$ http-server -c-1

Make a call

In order to make a call, you'll have to use the callPhone() method on the application object that is returned by the login() promise. The method accepts a string as parameter that it passes along to your answer_url, but since ours is a static file, we'll leave the method parameter empty.

new ConversationClient()
    .login(USER_JWT)
    .then(application => {
        ...
        document.getElementById("call").addEventListener("click", () => {
          application.callPhone();
          notification.textContent = `You're calling a phone number`;
        })
    })
    .catch(console.log);

Listen for call events

When the application makes a call, you can start listening for member:call events on the application. That's going to return a call object, so you can start interacting with the call later on.

new ConversationClient()
    .login(USER_JWT)
    .then(application => {
        ...
        application.on("member:call", (member, call) => {
          notification.textContent = `You're receiving a call`;
        })
    })
    .catch(console.log);

The listener method receives a member object that contains information about who's calling, and a call object, that lets you interact with the call in progress.

Hangup a call

You can hang up a call after you've initiated it by using the hangUp() method on the call object.

new ConversationClient()
    .login(USER_JWT)
    .then(application => {
        ...
        application.on("member:call", (member, call) => {
          notification.textContent = `You're receiving a call`;
          ...
          document.getElementById("hangup").addEventListener("click", () => {
            call.hangUp();
            notification.textContent = "The call has ended";
          })
        })
    })
    .catch(console.log);

Conclusion

You have implemented your first App to Phone Voice application with the Nexmo Client SDK for JavaScript.

Open the webpage in a browser to see that you can make a call and hangup a call to a phone number. If you've followed along this tutorial, your code should look similar to this.