Receive a Phone Call with Voice API and Swift
Published on May 12, 2021

In this tutorial you will create a Swift application that can receive phone calls using the Vapor web framework and the Nexmo Voice API. You can follow this tutorial on both MacOS or Ubuntu.

For the complete solution, please check out this Github repo.

Prerequisites

Vonage API Account

To complete this tutorial, you will need a Vonage API account. If you don’t have one already, you can sign up today and start building with free credit. Once you have an account, you can find your API Key and API Secret at the top of the Vonage API Dashboard.

This tutorial also uses a virtual phone number. To purchase one, go to Numbers > Buy Numbers and search for one that meets your needs.

  • The Nexmo CLI - you'll use this to create an application, purchase a number and link the two together

  • Swift 4.1 or greater - on MacOS, Xcode 9.3 or greater will do the trick

The Plan

This tutorial will walk you through the following steps:

  • Learn about Nexmo concepts

  • Create a new Vapor project

  • Add a route for the voice answer

  • Expose the application using ngrok

  • Purchase a Nexmo number

  • Create a Nexmo application to use with the number

  • Test your application

Nexmo Concepts

Before delving into the build, 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 the call is answered

  • event_url - Nexmo sends event information asynchronously to this URL when the call status changes; this ultimately defines 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 application please visit the Nexmo API Reference.

New Vapor Project

You will use Vapor to create a simple Swift web app—if you don't already have Vapor installed, do so by running this command:

brew install vapor/tap/vapor

Extensive installation instructions are available for MacOS and Ubuntu.

From the command line, navigate to an appropriate location where you want your project to reside (e.g. your Documents directory) and create a new Vapor app:

vapor new ReceiveCall cd ReceiveCall/

If you are using MacOS you can have vapor automatically create an XCode project for you (the -y option will automatically open the Xcode project):

vapor xcode -y

Build & Run to test your app ensuring that the Run scheme is selected. Once everything is compiled, the server is started and you will see a notice in the console:

Server starting on http://localhost:8080

Point your browser to that URL and an It works! message should appear.

Add the Route

You'll now add a route that will serve as the answer_url for the Nexmo application. http://localhost:8080/webhooks/answer will respond with the following JSON object:

[
    {
        "action":"talk",
        "text":"<speak>To be <break strength="weak" \=""> or not to be <break strength="weak" \=""> that is the question.<\/speak>"
    }
]
</break></break></speak>

A Vapor project stores its routes in the routes.swift file inside the Sources/App group. Open this file, clear all the existing routes and define the new route:

import Vapor

public func routes(_ router: Router) throws {
    router.get("/webhooks/answer") { request -> String in
        let talk = Action(
            action: "talk",
            text: "<speak>To be <break strength="weak"> or not to be <break strength="weak"> that is the question.</break></break></speak>")
        let encoder = JSONEncoder()
        guard let data = try? encoder.encode([talk]) else { return "error encoding" }
        return String(data: data, encoding: .utf8) ?? "error"
    }
}

Action is a simple Swift Structure to hold the NCCO action details - define it after the router closure:

struct Action: Encodable {
    var action: String
    var text: String
}

By coding Action to conform to Encodable, you ensure that the JSONEncoder can use it.

Build & Run the app and test the new route output at: http://localhost:8080/webhooks/answer.

You now have a URL that will be used as the answer_url.

Expose Your Application

For Nexmo to reach your Vapor application, it needs to access a publicly available URL-your application runs on your machine and is only accessible inside your local network.

ngrok is a simple utility that exposes your local web server through public URLs.

With ngrok installed, run the following command:

ngrok http 8080

Take note of the forwarding address as you will need it when you configure your account — an example output is shown below—the forwarding address is https://7ffc0230.ngrok.io.

ngrok running in terminal with forwarding address https://7ffc0230.ngrok.iongrok running in terminal with forwarding address https://7ffc0230.ngrok.io

Purchase a Number

This will be the number you're going to call to connect to your Nexmo application. The example below uses an US number but numbers for other countries are available.

Note: When signing up for a Nexmo account, €2.00 is added to your balance and this will be more than enough to get a number.

To purchase a new number, use the Nexmo CLI:

nexmo number:buy --country_code US

Take note of the new number assigned to you on purchase; you will need this next.

Create a Nexmo Application

You'll now tie everything together by creating a new Nexmo application using the ngrok forwarding address:

nexmo app:create "Receive Call Demo" http://your-ngrok-forwarding-address/webhooks/answer http://your-ngrok-forwarding-address/webhooks/events --keyfile private.key

Note: The second URL parameter, http://your-ngrok-forwarding-address/webhooks/events, doesn't exist and you'll never actually use it, but an event URL needs to be specified when creating a Nexmo application.

The output given by the above command will include the id of the new application (eg: Application created: 39083ced-5275-423d-8a1f-9db528c106b1). You will need this application id to link your phone number to the application—you can use the Nexmo CLI to do this:

nexmo link:app your-nexmo-phone-number your-application-id

The application will now send a request to your http://your-ngrok-forwarding-address/webhooks/answer URL when it receives a phone call.

Test Your Application

From your phone, make a call to your Nexmo number to hear the most important question of them all.

Conclusion

In a few lines of code you have created an application that can receive a phone call and speak a message to the caller. There are other ways to interact with the caller and other Speech Synthesis Markup Language(SSML) tags you can use.

Where Next?

Want to learn more? Check out our documentation on Nexmo Developer where you can learn about the call flow, Voice API and Nexmo Call Control Objects.

Paul ArdeleanuSr Manager, Developer Relations

Paul is an iOS Developer Advocate at Nexmo. A seasoned software engineer, trainer and speaker, he specialised in data-driven solutions on Apple platforms with an emphasis on prototyping, best practices and balance with agility.

Ready to start building?

Experience seamless connectivity, real-time messaging, and crystal-clear voice and video calls-all at your fingertips.

Subscribe to Our Developer Newsletter

Subscribe to our monthly newsletter to receive our latest updates on tutorials, releases, and events. No spam.