How to Initiate a Voice Call from Laravel PHP with Twilio Programmable Voice

September 24, 2019
Written by
Ugendu Ositadinma
Contributor
Opinions expressed by Twilio contributors are their own

Initiate a Voice Call from Laravel PHP with Twilio Programmable Voice.png

In this tutorial, we will be creating a Laravel application that will be used to make outbound voice calls. We will be making use of Twilio's Programmable Voice feature to learn how to initiate voice calls.

Technical Requirements

Completing this tutorial will require the following dependencies and a basic understanding of them.

  1. PHP (Version 7.1 or higher).
  2. Composer.
  3. Laravel.
  4. A Twilio Account.

Before we proceed with this tutorial, it is expected that you have a voice-enabled Twilio number. In case you do not have one, please proceed to purchase one here. This number will be used for the "from" number later in this tutorial.

Setting Up Your Development Environment

Let's install a new Laravel project via the Composer create-project command. From your terminal, run the following command:

$ composer create-project --prefer-dist laravel/laravel twilio-voice

This will create a Laravel project for us in the twilio-voice directory.

Our project will require the Twilio PHP Helper Library in order to connect to Twilio's Voice API. Using Composer, use the command below to install the SDK:

$ composer require twilio/sdk

NOTE: Ensure that you are in the working directory of the Laravel application you created.

After installing the SDK, a connection between the client application and Twilio will need to be enabled. Edit your .env file to update the parameters needed to create this connection. They can be retreived from your Twilio Dashboard.

ACCOUNT_SID=ACXXXXXXXXXXXXXXXXXXX
AUTH_TOKEN=XXXXXXXXXXXXXXXXXXXXX
TWILIO_PHONE_NUMBER=+18005551212

The dotenv file allows us to securely use these credentials without exposing them to the public. To understand this better, please check out How to store your credentials securely.

Let's create a Controller that will house most of the logic for our application. Run the following command in your terminal:

$ php artisan make:controller VoiceController

This command has created a controller VoiceController.php in the app\Http\Controllers directory of your Laravel application.

Open the VoiceController.php file and import the Twilio Rest Client class.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Twilio\Rest\Client;

Using the DRY principle as a guide, we will initialize a constructor to make the variables we need accessible by the controller, and avoid redefining them when we do need them. Add the following code to achieve that:

public function __construct() {
    // Twilio credentials
    $this->account_sid = env('ACCOUNT_SID');
    $this->auth_token = env('AUTH_TOKEN');

    //The twilio number you purchased
    $this->from = env('TWILIO_PHONE_NUMBER');

    // Initialize the Programmable Voice API
    $this->client = new Client($this->account_sid, $this->auth_token);
  }

Creating a View

Let's proceed to create a view for the purpose of making a call. This view will allow us to create a form that captures the user's phone number. Upon submit, a call will be placed to the provided number.

In the resources/views directory, create a file call.blade.php. This is where our frontend design will be housed. Below is the code for this interface.

<!doctype html>
<html lang="{{ str_replace('_', '-', app()->getLocale()) }}">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">

    <title>Twilio Call</title>
    <style>
      form {
      background-color: #fff;
      width: 1000px;
      float: center;
      margin: auto;
      margin-top: 100px;
    }
    </style>
  </head>
  <body>
    <form method="post" action="{{ route('initiate_call') }}">
      @csrf
      @if ($errors->any())
        <div class="alert alert-danger">
            <ul>
                @foreach ($errors->all() as $error)
                    <li>{{ $error }}</li>
                @endforeach
            </ul>
        </div>
      @endif
      <div class="form-group row col-8">
        <div class="form-group col-12">
          <label for="phoneNumber">Phone number</label>
          <input type="text" class="form-control" name="phone_number" id="phoneNumber" aria-describedby="phoneHelp" placeholder="Example, +18005551212" required>
          <small id="phoneHelp" class="form-text text-muted">Phone number should match <code>[+][country code][phone number including area code]</code></small>
        </div>
        <button type="submit" class="btn btn-primary">Submit</button>
      </div>
    </form>

    <!-- Optional JavaScript -->
    <!-- jQuery first, then Popper.js, then Bootstrap JS -->
    <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js" integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo" crossorigin="anonymous"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
  </body>
</html>

Looking Up the Phone Number

It would be really nice if we at least check to make sure that the target phone number exists or is valid before initiating the call. This line of code below performs that function.

public function initiateCall() {
    //Lookup phone number to make sure it is valid before initiating call
    $phone_number = $this->client->lookups->v1->phoneNumbers($request->phone_number)->fetch();
  }

To learn how to achieve more with this functionality, you can check out the  Lookup Quickstart;

Initiating a Call

Making a call is as simple as a few lines of code with the Twilio SDK. After verifying the phone number, we can proceed to initiate the call from the client object as defined in the constructor. The Programmable Voice API accepts the target phone number as the first parameter.

As an added benefit, calls can also be recorded and listened to on your Dashboard. If desired, you need to enable recording by setting record to True in your array below.

public function initiateCall() {
    //Lookup phone number to make sure it is valid before initiating call
    $phone_number = $this->client->lookups->v1->phoneNumbers($request->phone_number)->fetch();

    // If phone number is valid and exists
    if($phone_number) {
      // Initiate call and record call
      $call = $this->client->account->calls->create(
              $request->phone_number, // Destination phone number
              $this->from, // Valid Twilio phone number
              array(
                "record" => True,
                "url" => "http://demo.twilio.com/docs/voice.xml"));

      if($call) {
        echo 'Call initiated successfully';
      } else {
        echo 'Call failed!';
      }
    }
  }

Our controller will have to be connected to a route in order to make it accessible via HTTP. In the routes/web.php file, update the code as follows:

<?php

Route::view('/', 'call');
Route::post('/call', 'VoiceController@initiateCall')->name('initiate_call');

The completed VoiceController.php code is below.

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use Twilio\Exceptions\RestException;
use Twilio\Rest\Client;

class VoiceController extends Controller
{
  public function __construct() {
    // Twilio credentials
    $this->account_sid = env('ACCOUNT_SID');
    $this->auth_token = env('AUTH_TOKEN');
    //the twilio number you purchased
    $this->from = env('TWILIO_PHONE_NUMBER');

    // Initialize the Programmable Voice API
    $this->client = new Client($this->account_sid, $this->auth_token);
  }

  /**
   * Making an outgoing call
   */
  public function initiateCall(Request $request) {
    // Validate form input
    $this->validate($request, [
      'phone_number' => 'required|string',
    ]);

    try {
      //Lookup phone number to make sure it is valid before initiating call
      $phone_number = $this->client->lookups->v1->phoneNumbers($request->phone_number)->fetch();

      // If phone number is valid and exists
      if($phone_number) {
        // Initiate call and record call
        $call = $this->client->account->calls->create(
          $request->phone_number, // Destination phone number
          $this->from, // Valid Twilio phone number
          array(
              "record" => True,
              "url" => "http://demo.twilio.com/docs/voice.xml")
          );

        if($call) {
          echo 'Call initiated successfully';
        } else {
          echo 'Call failed!';
        }
      }
    } catch (Exception $e) {
      echo 'Error: ' . $e->getMessage();
    } catch (RestException $rest) {
      echo 'Error: ' . $rest->getMessage();
    }
  }
}

Testing

At this point you're probably ready to see the application in action! All you need to do is start up your development using the command below in your terminal.

$ php artisan serve

Finally, using a web browser of your choice, visit http://localhost:8000. Fill in the form and submit.

Conclusion

After completing this tutorial, you should be able to see that using the Twilio Programmable Voice to make outbound calls is pretty easy. Feel free to explore other uses to build upon what we've learned today!

Additional Resources

The DRY principle and why you should use it - A top-level overview of DRY principle with PHP examples by Pety Ialimijoro Rakotoniaina

How to Lookup a phone number with the Twilio CLI - Twilio Lookup explanation and example with the new Twilio CLI by Kelly Robinson

 

I'd love to see what you build. Feel free to reach out to me through the following channels.

Ugendu Martins Ositadinma

Email: ugendu04@gmail.com
Twitter: https://twitter.com/ohssie_
Github: https://github.com/ohssie