0
votes

This seems like a really simple issue, but I've searched the web and can't find an answer, unfortunately.

We're trying to setup a basic forwarding/voicemail service on Twilio. Our expected behavior is that a caller will call in and be forwarded to 3 different numbers. If none of the numbers answer, the caller is directed to the company voicemail.

Our issue comes in when any of the numbers reject the call (by pressing the red button on their phone) or are set to Do Not Disturb (which seems to act like a rejection). When this happens, the caller is sent directly to the callee's personal voicemail, instead of the company voicemail. I believe this is because Twilio is passed a "in-progress" status even though the call was rejected.

Is there a way to detect when the call is rejected and continue to the "action" part of our Dial? We looked into the Automatic Machine Detection, but am not sure that is the correct route to take, since it would still reveal the callee's personal voicemail until it determined it was a machine.

Thanks for any help! Our simple code is below.

<Response>
  <Dial callerId="+1xxx-xxx-xxxx" timeout="15" action="http://twimlets.com/[email protected]&amp;Message=https://website.com/Audio.mp3">
    <Number>xxx-xxx-xxxx</Number>
    <Number>xxx-xxx-xxxx</Number>
    <Number>xxx-xxx-xxxx</Number>
  </Dial>
</Response> ```
1

1 Answers

1
votes

You can take a look at the blog below, which uses Human Detection (alternatives to AMD) to intelligently handle the dialed party's voicemail.

Outsmart Voice Mail with Human Detection Using Keypress Prompts

You cannot use your current approach with parallel forking, since it cannot account for Voicemail.

You will need to build the sequential dialing logic. Below is some Twilio Function code that may be useful, but you will need to adapt it to meet your needs


Main Function (where you point your Twilio Telephone Number to) is shown first:

Replace: let phoneTreeUrl = "https://YOUR_FUNTION/PATH";

With your unique Function URL and path (this varies for each Twilio customer). Also update the phoneNumbers to be the phone numbers you want to call. You can pass the Timeout as a variable when you call the function from your Twilio phone number or change it in the code below (it defaults to 30 seconds).

Update the PLACE_HOLDER URL with the other Function you will create in the next step further below.

/*
 * 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 this Function
 let phoneTreeUrl = "https://YOUR_FUNTION/PATH";
 
 // Timeout - The amount of time we want to dial before giving up
 let timeout = event.Timeout || 30;
 
 // Attempt - The position in the list we are currently at
 let attempt = parseInt(event.Attempt) || 0;
 console.log(attempt);
 
 // DialCallStatus - Returned by <Dial> action
 let DialCallStatus = event.DialCallStatus || null;
 
 console.log(DialCallStatus);
 
 // Phone Numbers - The list of numbers to cycle through
 let phoneNumbers = [

  "+14073601234", "+16787851234"

 ];​

 // generate the TwiML to tell Twilio how to forward this call
 let twiml = new Twilio.twiml.VoiceResponse();
 
 // If we have successfully contacted a number, then exit Function
  if (DialCallStatus === "completed" || DialCallStatus === "answered") {
    twiml.hangup();
    callback(null, twiml);
  }

 // If we have exhausted 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({ timeout: timeout, action: nextAttemptUrl})
 .number({url: "https://PLACE_HOLDER/humandetect?Detection=required"}, target);
 
 callback(null, twiml);
};

Human Detection Function:

Give this new function the path /humandetect

Update the code below, THIS_FUNCTION, to the unique URL for this FUNCTION (with the path of /humandetect)

exports.handler = function(context, event, callback) {
 
 let twiml = new Twilio.twiml.VoiceResponse();
 
 // REQUIRED - URL to this Function
 let phoneTreeUrl = "https://THIS_FUNCTION/humandetect";
 
 let detection = event.Detection || null;

 if (detection === "required") {
   twiml.gather({timeout: 5, numDigits: 1, action: phoneTreeUrl})
   .say("Press any key to hear an important message about your appointment.");
   twiml.hangup();
}
 callback(null, twiml);
};