Forward a Call via Voice Proxy with PHP

Published May 15, 2019 by Mark Lewin

Today’s post shows you how to proxy a voice call so that it appears to come from another number.

This is not as dubious as it sounds: there are many compelling business reasons why you might want to hide a caller’s real number from other parties in the call.

A classic example is an online taxi service. To make the booking experience as smooth as possible, you want your customer and driver to be able to communicate with each other. But you don’t want the driver to know the customer’s real number (because you want to protect that customer’s privacy) and, conversely, you don’t want your customer to know your driver’s number and book rides directly without using your service.

Luckily, this is really easy to do in PHP with the Nexmo Voice API, so let’s get to it! The complete source code is available on Github.


  1. Install dependencies
  2. Define the webhook endpoints
  3. Log call events
  4. Make your webhooks accessible
  5. Purchase a number
  6. Create a Nexmo Voice API application
  7. Link the Application to your Nexmo number
  8. Call your Nexmo virtual number
  9. Implement the proxy logic
  10. Test the voice proxy

Install Dependencies

To work with inbound calls using Nexmo’s Voice API, you must provide webhooks so that Nexmo can send data to your application.

We’ll use slim to code these webhooks: a lightweight web framework for PHP. You can find out more about slim here.

Install slim using composer:

Define the Webhook Endpoints

Create a file called index.php that contains the following code:

This code creates a new slim application and defines two routes. These routes correspond to the following webhook endpoints:

  • /webhooks/answer: Nexmo’s APIs make a GET request to this endpoint when you receive an inbound call on your virtual number.
  • /webhooks/events: Nexmo’s APIs make a POST request to this endpoint every time a significant even occurs (such as call ringing, being answered and completed) to update your application on the status of the call.

Log Call Events

Let’s deal with the /webhooks/events endpoint first. Every time we are notified about an event we want to log it. This will help you debug any issues later on.

This example uses PHP’s built-in web development server and the error_log() function to output data to a log file (event.log).

Create a php.ini file in the root of your application which includes the following settings:

Then, update the /webhooks/events handler to log incoming event data:

Handle Inbound Calls

When you receive an inbound call, Nexmo’s API makes a GET request to your /webhooks/answer endpoint and expects the response to contain instructions on how to process the call.

You provide these instructions in the form of a Nexmo Call Control Object (NCCO) in JSON format. The NCCO defines the various “actions” that the call needs to take, such as input to collect any digits the user might press on their telephone keypad or stream to play audio into the call. You can find the full list of actions in the NCCO Reference.

Before we concern ourselves with the proxy logic, let’s first ensure that we can receive an inbound call on our Nexmo number.

Test your application with a talk action that uses TTS (text-to-speech) to read a message to your caller. Define and return the following NCCO in your /webhooks/answer route handler:

Make Your Webhooks Accessible

For Nexmo’s APIs to make requests to your webhook endpoints they must to be accessible over the Internet.

A great tool for exposing your local development environment to the public Internet is ngrok. Our tutorial shows you how to install and use it.

Launch ngrok using the following command:

Make a note of the public URLs that ngrok created for you. These will be similar to (but different from) the following:

On their free plan, every time you restart ngrok the URLs change and you will have to update your Voice API application configuration. So leave it running for the duration of this tutorial.

Purchase a Number

You need a Nexmo virtual number to receive phone calls. If you don’t already have a Nexmo number you can purchase one easily using the Nexmo CLI.

You can install the Nexmo CLI using the Node Package Manager, npm:

Then, configure the Nexmo CLI with your API key and secret from the developer dashboard:

To see what numbers are available, use nexmo number:search, passing it your two-character country code. For example, GB for Great Britain or US for the USA. You want to ensure that the number you purchase is able to receive voice calls:

Choose a number from the list and buy it using the following command:

You will be prompted to confirm your purchase. Make a note of the number that you bought.

Create a Nexmo Voice API Application

You now need to create a Nexmo Voice API Application. An application in this context is not the same as the application you have just written the code for. Instead, it is a container for the configuration and security information you need to use the Voice API.

You’ll use the Nexmo CLI again for this. You need to specify the following information:

  • A name for your application
  • The public URL to your /webhooks/answer endpoint (e.g.
  • The public URL to your /webhooks/events endpoint (e.g.
  • The name and location of the file that will contain your security credentials

In the same directory as your PHP application, enter the following command, supplying the appropriate URLs for your webhook endpoints:

This configures a Voice API application with your webhooks and downloads your security credentials in a file called private.key. The Voice Application is identified by a unique application ID: make a note of this as you will need it in the next step.

Link the Application to Your Nexmo Number

Next, you need to link your Voice API application to your Nexmo number.

Execute the following command, replacing APPLICATION_ID with the one generated by the nexmo app:create command that you executed in the preceding step:

Verify that the number and application are linked by executing the nexmo app:list command. You can also see this information in the developer dashboard.

Call Your Nexmo Virtual Number

With ngrok running on port 3000 in one terminal window, launch your PHP application on the same port in another:

Call your Nexmo number. If everything is working OK, you should hear the message you defined in your NCCO and then the call terminates.

Check the event.log and note which events were recorded during the call.

Implement the Proxy Logic

To create a voice proxy we can connect the inbound call to our target recipient’s number and use our Nexmo virtual number to hide the inbound caller’s real number.

Create two string constants to store these numbers:

  • FROM_NUMBER: Your Nexmo virtual number
  • TO_NUMBER: A landline or mobile number you can use for testing. This should be different from the number you will use to make the initial call.

Both numbers should include the country code and omit any leading zeroes. For example, in the UK the country code is 44. So if my mobile number is 07700 900004, the correct format is 447700900004.

Use the NCCO connect action to connect the inbound caller to the recipient. Replace the current NCCO in your /webhooks/answer endpoint with the following:

Test the Voice Proxy

Ensure that ngrok is still running in one terminal window and re-launch your PHP application in another:

Call your Nexmo virtual number. When the call is answered it should immediately ring your second number. That call should originate from your Nexmo number rather than the number you used to place the call.

That’s it! You have now implemented a simple voice proxy that hides a caller’s real number.

Further Reading

If you want to learn more about the Voice API, check out the following resources:

Leave a Reply

Your email address will not be published.

Get the latest posts from Nexmo’s next-generation communications blog delivered to your inbox.

By signing up to our communications blog, you accept our privacy policy , which sets out how we use your data and the rights you have in respect of your data. You can opt out of receiving our updates by clicking the unsubscribe link in the email or by emailing us at [email protected].