Skip to main content

Screen Calls & Record Voicemail - PHP & Slim

In a telecommunication world as abundant as the one we are living in, it is simply not practical to answer every call that lands in your system. That is why we have created a simple solution to redirect calls based upon the caller's input to a given question.

This example will show how you can easily handle incoming calls, screen them through a prompt, and record a voicemail if you do not want to speak with the caller at the current time based upon their answer to the prompt.

What do I need to run this code?

You can find the full github repository HERE

This guide uses the PHP SignalWire SDK, for a guide on installation click here

You will need a SignalWire phone number as well as your API Credentials (API Token, Space URL, and Project ID) which can all be found in an easily copyable format within the API tab of your SignalWire portal.

For more information on where to find these, check out our Navigating your SignalWire Space section!

How to Run the Application

Use composer install to install dependencies, then run TO_NUMBER=+15558877444 php -S localhost:8080 -t public/, of course replacing TO_NUMBER with your own number you want to have calls screened to.

You may need to use an SSH tunnel for testing this code if running on your local machine. – we recommend ngrok. You can learn more about how to use ngrok with SignalWire here.

Step by Step Code Walkthrough

We will start by defining our first route / which will handle the original inbound call. In this route, we will create a Dial verb using the action URL parameter to redirect to the /voicemail route when the dialed call has ended. We will then use the Number noun inside of Dial along with the url parameter which redirects to the /screen calls route after the dialed call is answered but before the dialed call is connected. In this example, we use an environment variable for the to number, but in practice, it would be best to replace this with the number you would like all calls forwarded to or a database that can locate the correct number necessary.

# when a call comes in to this route, we will dial the env variable To number
$app->post('/', function (Request $request, Response $response, $args) {
# instantiate voice response
$laml = new VoiceResponse;

# create a <Dial> verb with an action url that will redirect to the voicemail route
$dial = $laml->dial('', array('action' => '/voicemail', 'answerOnBridge' => true));

# use <Number> noun inside of dial and use url to redirect to /screen call route
$dial->number(getenv('TO_NUMBER'), array('url' => '/screen'));

# convert response to XML
$xmlResponse = $response->withHeader('Content-type', 'application/xml');
$xmlResponse->getBody()->write(strval($laml));
return $xmlResponse;
});

If the dialed call is answered, we will next go to the /screen route. We will create a Gather with the action URL that will redirect to the /connect route when any key is pressed. We will play a short message for the callee that tells them the number of the caller and asks for input to decide whether to accept or send to voicemail. If no input is detected, we will hang up the call. When the dialed call ends, we will execute the /voicemail route as indicated in the action URL of the original dialed call.

# check if callee wants to accept call or send to voicemail 
$app->post('/screen', function (Request $request, Response $response, $args) {
# instantiate voice response
$laml = new VoiceResponse;

# get request parameters so that we can access the From number of the caller
$post = $request->getParsedBody();

# create a <Gather> where we expect 1 digit to be pressed and if pressed
# we will redirect to the /connect route
$gather = $laml->gather(array(
'action' => '/connect',
'numDigits' => 1,
'timeout' => 5
));

# play message stating the caller's number and prompt for input in order to connect the call
$message = "You have a call from: {$post['From']}";
$gather->say("{$message}. Press any digit to accept the call.");

# if no input is connected, we will hang up and redirect to the voicemail route
$laml->say('Hanging up');
$laml->hangup();

# convert response to XML
$xmlResponse = $response->withHeader('Content-type', 'application/xml');
$xmlResponse->getBody()->write(strval($laml));
return $xmlResponse;
});

If the callee presses any key, we will use Say to play a short message alerting the callee that they will be connected now.

# play message to tell the callee that they are being connected to the original caller
$app->post('/connect', function (Request $request, Response $response, $args) {
# instantiate voice response
$laml = new VoiceResponse;

# use TTS to alert callee of impending connection
$laml->say('Connecting you');

# convert response to XML
$xmlResponse = $response->withHeader('Content-type', 'application/xml');
$xmlResponse->getBody()->write(strval($laml));
return $xmlResponse;
});

When the dialed call ends, we will redirect to the /voicemail route. We will first check if the DialCallStatus is completed (i.e. answered and not in need of voicemail) and if it is, we will hang up the call. If the DialCallStatus is anything other than completed, we will use Say to play a voicemail prompt and Record to record a message. The action URL in Record will redirect to the /store route when the recording is complete.

# this route will record a voicemail message 
$app->post('/voicemail', function (Request $request, Response $response, $args) {

# instantiate voice response
$laml = new VoiceResponse;

# get request parameters so we can check the dial call status
$post = $request->getParsedBody();

# check if dial call status is completed
# if status is not completed, record a voicemail
if ($post['DialCallStatus'] != "completed") {
# play a prompt for the caller
$laml->say('Please leave a message after the beep. Press the pound key when done.');
# use <Record> verb to record a message and finish on #, redirect to /store route when done
$laml->record(array(
'action' => '/store',
'maxLength' => 15,
'finishOnKey' => '#'
));

} # if dial call status is completed (and therefore was answered), hang up the call
else {
$laml->hangup();
}

# convert response to XML
$xmlResponse = $response->withHeader('Content-type', 'application/xml');
$xmlResponse->getBody()->write(strval($laml));
return $xmlResponse;
});

Our final route is more of a placeholder that you can fill based on your business needs! In the /store route, you can use the HTTP request parameters to get the recordingUrl, From, To, or many other parameters. You can use this to store on a server, update your CRM, or even send an SMS with the recording URL. If you don't want to do anything with the recording, you can replace this function with the code to Hangup when the recording is complete instead.

# in this route, you can save the recording, upload it somewhere, send it via sms, etc
$app->post('/store', function (Request $request, Response $response, $args) {
$post = $request->getParsedBody();

// do something with the recording
// saveRecordingSomehow($post['RecordingUrl'], $post['From'], $post['To']);
$response->getBody()->write('');
return $response;
});

Wrap Up

It is time to stop wasting your time with calls that you do not care about, just send them to voicemail. Through the usage of the SIgnalWire PHP SDK, we can easily build out a call flow that tests the user calling into you, and only allows those important calls to get through.

Once our application was running, ngrok helped transform our local port into a webhook that could then be configured to our SignalWire number.

Required Resources:

Sign Up Here

If you would like to test this example out, you can create a SignalWire account and space here.

Please feel free to reach out to us on our Community Slack or create a Support ticket if you need guidance!