Redirecting a Call to a new Twiml URL

2.5k views Asked by At

I am following the tutorial on https://www.twilio.com/docs/api/rest/change-call-state#post I am coding in php the portion that allows you to forward a current inbound call to a new Twiml URL. I am finding that in order for this to work, I have to specify a To and From parameter in the update array. I need the call forwarded to the URL specified not the number specified in the To parameter. However, the Twilio API throws an error that says the To parameter is required but the docs indicate that it is not. Is there something I am doing wrong here?

<?php
// Get the PHP helper library from twilio.com/docs/php/install
require_once('TwilioAPI/twilio-php-master/Services/Twilio.php'); // Loads the library

// Your Account Sid and Auth Token from twilio.com/user/account
$sid = 'XXXXXXX';
$token  = 'XXXXXXX';
$callSid = $_POST['CallSid'];
$client = new Services_Twilio($sid, $token);

// Get an object from its sid. If you do not have a sid,
// check out the list resource examples on this page



$call = $client->account->calls->get($callSid);

$call->update(array(
        "Url" => "http://ftstoo.com/Phone/TheFinalTouchSecurity/forwardToBob.xml",
    "Method" => "POST"
    ));?>

forwardToBob.xml contains a Response with a Say Verb. This php code (not the twiml) throws the error

Uncaught exception 'Services_Twilio_RestException' with message 'No 'To' number is specified' in /home/wcmtechnologies/public_html/Phone/TheFinalTouchSecurity/TwilioAPI/twilio-php-master/Services/Twilio.php:297

If I add "To" => "Some Ten Digit Phone Number", "From" => "Some Ten Digit Phone Number", to the array, the error is not thrown. The call is then directed to the "To" phone number. If the phone number specified in the "To" parameter answers, then the call is connected AND the twiml at forwardToBob.xml executes all at the same time.

EDIT # 3----------------------------------------------------------------------

Here is my entire code....

This is the Twiml that is executed everytime the Twilio verified number is called. I got this code from the Twilio quickstart site.

    <?php
    header('Content-type: text/xml');

    $callerId = "+19012311158";

    // put your default Twilio Client name here, for when a phone number isn't given
    $number   = "Bob";

    // get the phone number from the page request parameters, if given
    if (isset($_REQUEST['PhoneNumber'])) {
        $number = htmlspecialchars($_REQUEST['PhoneNumber']);
    }

    // wrap the phone number or client name in the appropriate TwiML verb
    // by checking if the number given has only digits and format symbols
    if (preg_match("/^[\d\+\-\(\) ]+$/", $number)) {
        $numberOrClient = "<Number>" . $number . "</Number>";
    } else {
        $numberOrClient = "<Client>" . $number . "</Client>";
    }
    ?>

    <Response>
        <Dial callerId="<?php echo $callerId ?>">
              <?php echo $numberOrClient ?>
        </Dial>
    </Response>

This is the client browser which I mostly copied from the Twilio quickstart site.

<?php
include 'TwilioAPI/twilio-php-master/Services/Twilio/Capability.php';

// put your Twilio API credentials here
$accountSid = 'XXXXXXXX';
$authToken  = 'XXXXXXXX';

// put your Twilio Application Sid here
$appSid     = 'XXXXXXXXXXXXX';

// put your default Twilio Client name here
$clientName = 'Bob';

// get the Twilio Client name from the page request parameters, if given
if (isset($_REQUEST['client'])) {
    $clientName = $_REQUEST['client'];
}

$capability = new Services_Twilio_Capability($accountSid, $authToken);
$capability->allowClientOutgoing($appSid);
$capability->allowClientIncoming($clientName);
$token = $capability->generateToken();
?>

<!DOCTYPE html>
<html>
  <head>
    <title>Demo</title>
    <script type="text/javascript"
      src="//static.twilio.com/libs/twiliojs/1.2/twilio.min.js"></script>
    <script type="text/javascript"
      src="https://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js">
    </script>
    <link href="http://static0.twilio.com/bundles/quickstart/client.css"
      type="text/css" rel="stylesheet" />
    <script type="text/javascript">
      var callSid = ""; 
      Twilio.Device.setup("<?php echo $token; ?>");

      Twilio.Device.ready(function (device) {
        $("#log").text("Client '<?php echo $clientName ?>' is ready");
      });

      Twilio.Device.error(function (error) {
        $("#log").text("Error: " + error.message);
      });

      Twilio.Device.connect(function (conn) {
        callSid = conn.parameters.CallSid; 
        $("#log").text("Successfully established call");
      });

      Twilio.Device.disconnect(function (conn) {
        $("#log").text("Call ended");
      });

      Twilio.Device.incoming(function (conn) {
        $("#log").text("Incoming connection from " + conn.parameters.From);
        // accept the incoming connection and start two-way audio
        conn.accept();
      });

      Twilio.Device.presence(function (pres) {
        if (pres.available) {
          // create an item for the client that became available
          $("<li>", {id: pres.from, text: pres.from}).click(function () {
            $("#number").val(pres.from);
            call();
          }).prependTo("#people");
        }
        else {
          $("#" + pres.from).remove();
        }
      });

      function call() {
        // get the phone number or client to connect the call to
        params = {"PhoneNumber": $("#number").val()};
        Twilio.Device.connect(params);
      }
      function forward() {
        var xmlhttp = new XMLHttpRequest();

        params = "?CallSid=" + callSid + "&ForwardTo=" + document.getElementById("number").value;

        xmlhttp.open("POST","forward.php" + params,false);
    xmlhttp.send();
    document.getElementById("log").innerHTML=xmlhttp.responseText;
      }
      function hangup() {
        Twilio.Device.disconnectAll();
      }
    </script>
  </head>
  <body>
    <button class="call" onclick="call();">
      Call
    </button>

    <button class="hangup" onclick="hangup();">
      Hangup
    </button>

    <input type="text" id="number" name="number"
      placeholder="Enter a phone number or client to call"/>

    <button class="call" onclick="forward();">
      Forward
    </button>

    <div id="log">Loading pigeons...</div>

    <ul id="people"/>
  </body>
</html>

This is the forwarding code that is called via an HTTP POST request from my forward() function.

<?php
// Get the PHP helper library from twilio.com/docs/php/install
require_once('TwilioAPI/twilio-php-master/Services/Twilio.php'); // Loads the library

// Your Account Sid and Auth Token from twilio.com/user/account
$sid = 'XXXXXX';
$token  = 'XXXXXX';
$callSid = $_POST['CallSid'];
$client = new Services_Twilio($sid, $token);

// Get an object from its sid. If you do not have a sid,
// check out the list resource examples on this page



$call = $client->account->calls->get($callSid);

$call->update(array(
        "Url" => "http://ftstoo.com/Phone/TheFinalTouchSecurity/forwardToBob.xml",
    "Method" => "POST"
    ));

The first code snippet shows the Twiml that is executed when 901-231-1158 is called. It is then directed to the Client "Bob". Once the connection is successful, I press the forward button which I added in. This forward button calls the forward function which then makes an HTTP POST request to the PHP script which is the last snippet. Upon executing, if I do not have the "To" and "From" parameters specified in the array for the update function, I receive an error. Any suggestions on what I should try to fix this would help very much!

PLEASE NOTE: The button that I created in HTML is called Forward and it calls the function forward() which I created. I am getting the call Sid and saving it in an instance variable. I retrieve this value in the Twilio.Device.Connect function.

The full stack trace.

Stack trace:
#0 /home/wcmtechnologies/public_html/Phone/TheFinalTouchSecurity/TwilioAPI/twilio-php-master/Services/Twilio.php(180): Base_Services_Twilio->_processResponse(Array)
#1 /home/wcmtechnologies/public_html/Phone/TheFinalTouchSecurity/TwilioAPI/twilio-php-master/Services/Twilio/InstanceResource.php(31): Base_Services_Twilio->createData('/2010-04-01/Acc...', Array)
#2 /home/wcmtechnologies/public_html/Phone/TheFinalTouchSecurity/forward.php(22): Services_Twilio_InstanceResource->update(Array)
#3 {main}
  thrown in /home/wcmtechnologies/public_html/Phone/TheFinalTouchSecurity/TwilioAPI/twilio-php-master/Services/Twilio.php on line 297
[12-Jun-2015 00:19:39 UTC] PHP Fatal error:  Uncaught exception 'Services_Twilio_RestException' with message 'No 'To' number is specified' in /home/wcmtechnologies/public_html/Phone/TheFinalTouchSecurity/TwilioAPI/twilio-php-master/Services/Twilio.php:297
1

There are 1 answers

2
philnash On

Twilio developer evangelist here.

Thanks for all the details, I managed to put together most of what you were trying to do in order to find the errors. I never received the error message you had though, so bare that in mind.

I found I had to change the following parts of your code to get this to work.

In your XHR request, stop trying to make the request synchronously (I was using Firefox and it was deprecated), just use:

xmlhttp.open("POST","forward.php" + params);

I was also not getting the call sid from the XHR request in my PHP, so I changed $_POST to $_REQUEST and that started to work.

Finally, the call sid on the client side is not the same as the originating call sid. That is the parent call and you can get hold of it like this using the twilio-php helper library:

$callSid = $_REQUEST['CallSid'];
$client = new Services_Twilio($sid, $token);

// Get an object from its sid. If you do not have a sid,
// check out the list resource examples on this page

$call = $client->account->calls->get($callSid);

$parentCall = $client->account->calls->get($call->parent_call_sid);

$parentCall->update(array(
    "Url" => "http://ftstoo.com/Phone/TheFinalTouchSecurity/forwardToBob.xml",
    "Method" => "POST"
));

You then need to update the parent call to forward it on to your original URL and hang up on the client side.

I hope this helps!