Redirect to Second Number After "Timeout"

1,485 views
Skip to first unread message

pedro.ra...@gmail.com

unread,
Jan 3, 2018, 7:30:47 AM1/3/18
to Twilio Functions

Hello Twilio,

 

I have very basic knowledge with programming in Node.JS but I see that Twilio Functions are powerful and I have managed to achieve 50% of what I want to do even with my basic knowledge.

 

What I am looking to do is forward calls to a number that I purchased with Twilio, to mobile number in Brazil. I managed to do this part using your template “Call Forward” (I attach the code below). Nonetheless, the second part I cannot understand how I should attack the problem. I would like that if the call is not answered in 10 seconds that it should be forward to another number.

 

My doubts are:

- I imagine that I must use the 'timeout' attribute to set the limit in seconds that <Dial> waits for the called party to answer the call. Is that correct?

- Where must I place this code of the identification of the 'timeout' of 10 seconds? Can I place it in the same function as the first call redirection, if so how is this “hook” triggered? Or should I create a second function, and if so how can I call this second function when the ‘timeout’ of 10 seconds it complete?



=======


/**

 *  Call Forward Template

 * 

 *  This Function will forward a call to another phone number. If the call isn't answered or the line is busy, 

 *  the call is optionally forwarded to a specified URL. You can optionally restrict which calling phones 

 *  will be forwarded.

 */


exports.handler = function(context, event, callback) {

  // set-up the variables that this Function will use to forward a phone call using TwiML

  

  // REQUIRED - you must set this

  let phoneNumber = event.PhoneNumber || "+5511********";    

  // OPTIONAL

  let callerId =  event.CallerId || null;

  // OPTIONAL

  let timeout = event.Timeout || null;

  // OPTIONAL

  let allowedCallers = event.allowedCallers || [];

  // new

  

  let callStatus = event.CallStatus || '';

  let answeredBy = event.AnsweredBy || '';

  

  // generate the TwiML to tell Twilio how to forward this call

  let twiml = new Twilio.twiml.VoiceResponse();

  


  let allowedThrough = true

  if (allowedCallers.length > 0) {

    if (allowedCallers.indexOf(event.From) === -1) {

      allowedThrough = false;    

    }

  }


  let dialParams = {};

  if (callerId) {

    dialParams.callerId = callerId

  }

  if (timeout) {

    dialParams.callerId = timeout

  }

  

  if (allowedThrough) {

    twiml.dial(dialParams, phoneNumber);

    console.log('Dialing:');

  }

  else {

    twiml.say('Sorry, you are calling from a restricted number. Good bye.');

  }

  

  if (callStatus === 'in-progress') { 

    console.log('AnsweredBy:' + answeredBy);

   }

  

  // return the TwiML

  callback(null, twiml);

};

Chris Corcoran

unread,
Jan 4, 2018, 7:36:54 PM1/4/18
to Twilio Functions
Hey,

Thanks for your question about Twilio Functions, I'd be happy to help you get up and running. If I'm understanding your question correctly, it sounds like you want to setup a linear phone tree of some sort. Basically, you want to call a number and if doesn't answer you want to try another number. I think this is pretty easy to do with a little bit of basic logic in your Function. I've included a simplified version of what a "Strictly Linear" phone tree might look like. Let me know if you think something like that could work for your solution.

/*
 * Example: Strictly Linear Phone Tree
 * This example shows how you might iterate through a list of numbers. 
 * Each will be tried for 10 seconds before moving on to the next.
 */
exports.handler = function(context, event, callback) {
// REQUIRED - URL to hangup Function
let hangUpAction = "";
// REQUIRED - URL to this Function
let phoneTreeUrl = "";
// Timeout - The amount of time we want to dial before giving up
let timeout = event.Timeout || 10;
// Attempt - The position in the list we are currently at
let attempt = event.Attempt || 0;
// Phone Numbers - The list of numbers to cycle through
let phoneNumbers = [
"+5511********"
];

// generate the TwiML to tell Twilio how to forward this call
let twiml = new Twilio.twiml.VoiceResponse();
// If we have exhaused all numbers end the attempts
if (attempt > phoneNumbers.length) {
twiml.say("Sorry, we could not find someone to take your call. Please try again later");
callback(null, twiml);
}
// Build the state for our Twiml response
let target = phoneNumbers[attempt];
let nextAttempt = attempt + 1;
let nextAttemptUrl = phoneTreeUrl + "?Attempt=" + nextAttempt;
twiml.dial(target, { timeout: timeout, action: hangUpAction });
twiml.redirect(nextAttemptUrl);
callback(null, twiml);
};

Alternatively, if your phone tree doesn't need to be linear you could use a "simul-ring". With a simul-ring all of the phone number you specify in the <Dial> verb are called and the first to answer gets connected. This is what I normally recommend for situations like this. Typically your caller will get connected faster and your answering party doesn't need to jump to beat the timeout. I've included a simplified example of how you might do this with a Function.

/*
 * Example: Simplified Simulring.
 * This will dial all of the phone numbers specified in the phoneNumbers array at one.
 * The first number ot answer the call will be connected.
 */
exports.handler = function(context, event, callback) {
// Phone Numbers - The list of numbers to cycle through
let phoneNumbers = [
"+5511********"
];

// generate the TwiML to tell Twilio how to forward this call
let twiml = new Twilio.twiml.VoiceResponse();
let dial = twiml.dial();
for (var phoneNumber in phoneNumbers) {
dial.number(phoneNumber);
}
callback(null, twiml);
};

Hopefully, this helps point you in the right direction. Let me know if you have any follow up questions.

Thanks,
Chris Corcoran
Product Manager, Twilio Runtime

pedro.ra...@gmail.com

unread,
Jan 5, 2018, 11:56:17 AM1/5/18
to Twilio Functions

Thank you Chris, that has helped me immensely.

 

Just two more quick questions if I may?

 

1)   1) How can I tell if a call to a particular number on the “twiml.dial(target, { timeout: timeout, action: hangUpAction }); was answered? And if it was answered, I will update a value of a certain pre-declared variable, which I will use later on in the function?

 

2)   2) Is it possible that I can obtain the caller´s number and pass it on to another function I created? This other function I have linked to the “CALL STATUS CHANGES and when the call ends I need the callers number to send an SMS with some information; I am not sure if the is the correct an recommended procedure.

 

Thank you in advance,

Pedro

Chris Corcoran

unread,
Jan 5, 2018, 5:40:41 PM1/5/18
to Twilio Functions
Hey Perdo,

I'm happy to hear that my response was helpful. I've tried to answer your follow up questions below. 

1) I would recommend looking at the documentation for the <Dial> verb. According to the docs the 'action' URL will only be invoked once the call is completed. In the example code I provided we're using the 'action' verb to invoke another Function that will return the <Hangup/> verb. I've suggested implementing it this way because you want the call flow to stop after someone has answered. Without this <Hangup> instruction the call flow will continue dialing other numbers in the phoneNumbers array.

2) Yes, it is possible to obtain the callers number in a Function. I would recommend taking a look at the Twilio Voice Request documentation for the parameters that are available to you. From your Function all should need to do is use "event.From" to get the phone number and then dispatch it to another Function.

Hopefully this helped, let me know if you have any other questions.

Thanks Again,
Chris Corcoran
Product Manager, Twilio Runtime 

Nir Montag

unread,
Apr 10, 2018, 7:33:46 AM4/10/18
to Twilio Functions
Hi,


For some reason I couldn't get the "Linear Phone Tree" to work after the 1st number wasn't answered, the hangUpAction fired immediately.
This is the code I've tried to execute:

/*
 * Example: Strictly Linear Phone Tree
 * This example shows how you might iterate through a list of numbers. 
 * Each will be tried for 10 seconds before moving on to the next.
 */
exports.handler = function(context, event, callback) {
// REQUIRED - URL to hangup Function
// REQUIRED - URL to this Function
// Timeout - The amount of time we want to dial before giving up
let timeout = event.Timeout || 10;
// Attempt - The position in the list we are currently at
let attempt = event.Attempt || 0;
// Phone Numbers - The list of numbers to cycle through
//"
        let phoneNumbers = [
          "+111...",
          "+222..."
];

// generate the TwiML to tell Twilio how to forward this call
let twiml = new Twilio.twiml.VoiceResponse();
// If we have exhaused all numbers end the attempts
if (attempt > phoneNumbers.length) {
twiml.say("Sorry, we could not find someone to take your call. Please try again later");
callback(null, twiml);
}
// Build the state for our Twiml response
let target = phoneNumbers[attempt];
let nextAttempt = attempt + 1;
let nextAttemptUrl = phoneTreeUrl + "?Attempt=" + nextAttempt;
twiml.dial(target, { timeout: timeout, action: hangUpAction });
twiml.redirect(nextAttemptUrl);
callback(null, twiml);
};


So, I tried a different approach, where each function will be responsible for 1 redirection (as I have only 2).

CM1 function calling "+111..." and calling the CM2 function as the hangUpAction
CM2 function calling "+222..." and calling a voice mail function as the hangUpAction.

Problem was, that even after picking up the phone, the linear path continued (calling the hangUpAction).

Can you please assist?
Reply all
Reply to author
Forward
0 new messages