Twilio forward incoming calls based on the incoming phone number - twilio

I recently ported my home landline number to Twilio. For now, I created a very basic call forwarding TwiML Bin to forward any incoming calls to this former landline number to my cell phone:
<Response>
<Dial>mycellnumber</Dial>
</Response>
What I'd like to do is have some logic to forward incoming calls to a different cell based on the incoming caller matching a number in a contact list, and default forwarding if the incoming number is not on a contact list.
For example, if the incoming call is from a number on the contact list for Cell-X then forward the call to Cell-X, else if on the contact list for Cell-Y forward to Cell-Y, else maybe go to cloud voice mail or another number.
Is there a way to do something like this as a TwiML Bin or in the Studio or is it too complicated? Maybe TaskRouter? This is residential so I'd like it to be invisible to the caller as opposed to something like an IVR solution where the caller is prompted to press a number for the person they want to reach.
I've not had any luck finding a call forwarding solution with logic like this by looking through the Twilio docs or by searching for examples. Please help!

You could do this with a Twilio function.
Let's say that your Cell-X list looks something like this:
const cellXContactList = ["+17782001001", "+17782001002", "+17782001003"];
and your Cell-Y list looks something like this:
const cellYContactList = ["+17782001004", "+17782001005", "+17782001006"];
then you could distribute incoming calls with something like this:
if (cellXContactList.length && cellXContactList.indexOf(event.From) !== -1) {
// caller number found in Cell-X contact list
destinationPhoneNumber = "+17781001001";
} else if (cellYContactList.length && cellYContactList.indexOf(event.From) !== -1) {
// caller number found in Cell-Y contact list
destinationPhoneNumber = "+17781001002";
}
Below is the entire code for the function (replace with your phone numbers):
// forward calls based on the incoming phone number
exports.handler = function (context, event, callback) {
// reference the Twilio helper library
const twiml = new Twilio.twiml.VoiceResponse();
// contacts lists
const cellXContactList = ["+17782001001", "+17782001002", "+17782001003"];
const cellYContactList = ["+17782001004", "+17782001005", "+17782001006"];
// if not in any contact list forward to this number
let destinationPhoneNumber = "+17781001000";
if (cellXContactList.length && cellXContactList.indexOf(event.From) !== -1) {
// caller number found in Cell-X contact list
destinationPhoneNumber = "+17781001001";
} else if (cellYContactList.length && cellYContactList.indexOf(event.From) !== -1) {
// caller number found in Cell-Y contact list
destinationPhoneNumber = "+17781001002";
}
twiml.dial({}, destinationPhoneNumber);
// return the TwiML
callback(null, twiml);
};
You can create Twilio functions in your Twilio console at (https://www.twilio.com/console/functions/manage). Start with a "Blank" functions template, then replace with the code above.
Once you've created and published your function, you can configure your Twilio number to run it when "A CALL COMES IN" (https://www.twilio.com/console/phone-numbers/incoming).

Related

Twilio Voice conference from Browser using PHP

I have successfully implemented Voice calls functionality in my php application using JS SDK.
Now, I need to implement Call Monitoring and barge in features, that I believe are only available using Twilio Conference.
My current code looks like
$response = new VoiceResponse();
$dial = $response->dial('');
//If Incoming call, redirect the call to my browser client
if($phonenumber == $mytwiliophonenumber)
{
$dial->client($browserclientname);
}
//If outgoing, make the call to the phone number
else
{
$dial->number($phonenumber);
}
Now, what is the easiest way to change this to conference?
I have read that I need to dial the conference, but it is not working.
$dial->conference('anyconferencename');
Any guidance?
A conference has a fundamental difference to connecting two callers together in a regular dial. A conference acts as a room that participants join individually, rather than when you use client or number which places an outbound call leg to the client or number you are dialling.
If you have your user dial into a conference using $dial->conference you will need to create another leg to call the other person into the conference too. You can do this using the conference participants API.
So, instead of your current code, you could update to something like this:
$response = new VoiceResponse();
$dial = $response->dial('');
//If Incoming call, redirect the call to my browser client
if($phonenumber == $mytwiliophonenumber)
{
$participant = "client:" . $browserclientname;
}
//If outgoing, make the call to the phone number
else
{
$participant = $phonenumber;
}
$conferenceName = 'conferencename';
$twilio->conferences($conferenceName)
->participants
->create($mytwiliophonenumber, // from
$participant, // to
);
$dial->conference($conferenceName);
In this option, regardless of whether the call is inbound or outbound, the caller is placed in a conference call. And another call is generated to add the other participant to the conference call too.

Twilio call hold is not working as expected

I am using Twilio to call my customers from my Twilio client and want to put the user on hold whenever is needed. For that i am calling RESTAPI whenever user clicks on the "Hold" Button.
But after calling the method call is getting disconnected for My Twilio client and playing Hold sound for my customer. Can you please suggest something for this. Both the below approaches are not working
var response = new VoiceResponse();
var dial = new Dial();
dial.Conference("Customer Waiting Room", beep: Conference.BeepEnum.False);
response.Append(dial);
var call = Twilio.Rest.Api.V2010.Account.CallResource.Read(parentCallSid: callSid).ToList();
Twilio.Rest.Api.V2010.Account.CallResource.Update(new Twilio.Rest.Api.V2010.Account.UpdateCallOptions(call[0].Sid) { Twiml = response.ToString() });
return Content(response.ToString(), "application/xml");
Alternative:
var response = new VoiceResponse();
response.Say("You have a caller on hold.");
var call = Twilio.Rest.Api.V2010.Account.CallResource.Read(parentCallSid: callSid).ToList();
response.Enqueue("admin");
Twilio.Rest.Api.V2010.Account.CallResource.Update(new Twilio.Rest.Api.V2010.Account.UpdateCallOptions(call[0].ParentCallSid) { Twiml = response.ToString() });
Twilio developer evangelist here.
You have a direct call setup between your agent and you customer. When you move your customer call away from that, then your agent call will move on to the next TwiML instruction. If there are no further TwiML instructions available for your agent, then they will get disconnected.
To overcome this, you need to consider what you want your agent to do while your customer is on hold. It might be better, for example, to have your call take place in a conference. That way, when you put your customer on hold, the agent can remain in the conference.
Otherwise, you should provide further TwiML instructions after your agent's <Dial> so that they continue the call after the customer leg goes away.

Twilio: How to continue the <Dial> Action after callee rejects call

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/voicemail?Email=email#email.com&Message=https://website.com/Audio.mp3">
<Number>xxx-xxx-xxxx</Number>
<Number>xxx-xxx-xxxx</Number>
<Number>xxx-xxx-xxxx</Number>
</Dial>
</Response> ```
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);
};

Displaying Missed Calls Twilio

I've been working on a call system with Twilio. Here is how it works:
1.) When someone calls it plays an IVR and they send a response and it redirects them
2.) We then play ringing to them and forward it to a cell phone using DialCallStatus. We use this because we don't want them to hit the voicemail on the cell phone. So, if no one answers the call they hit the twilio voicemail and not the cell phone voicemail. If an operator answers they hear a "press any key to accept the call" they press a key so twilio knows that someone answered the call.
3.) the issue I am having is when I want to display the "missed call" it's not working. I see the call statuses and I tried using the "missed one" but it seems like almost every call is being marked as "completed". Essentially, I want to be able to pinpoint the calls that were not picked up by an actual operator. So, even if they don't leave a voicemail we can call them back.
Sorry for the lengthy question but if you have any idea how to do this it would be much appreciated.
Specific to the, "press any key to accept the call". Are you using the Number noun url parameter with your Dial verb and using a Gather verb returned with the Number URL to collect this positive input? You will receive a Digits parameter if the dialed party presses any key. The Redirect (see below) is the fall through that hits if no digit is pressed (but the call is answered before the dial timeout). I set the value of Digits equal to timeout if no key was entered.
Look at the Twilio Function code below for an example. In my testing, the Dial action URL does correctly show no-answer if the dialed party answers but does not press a digit before the gather DTMF entry timeout.
Initial Dial Number Code:
exports.handler = function(context, event, callback) {
let twiml = new Twilio.twiml.VoiceResponse();
twiml.dial({action: "https://x.x.x.x/dialAction"})
.number({url: "https://x.x.x.x/gatherWhisp"}, "+15555551212");
callback(null, twiml);
};
Code than runs when Dialed party answers the call:
exports.handler = function(context, event, callback) {
let twiml = new Twilio.twiml.VoiceResponse();
let digits = event.Digits || null;
if (digits === "timeout") {
// The dialed party never pressed a digit to accept call
// The DialCallStatus returned in the Dial action URL should say no-answer
twiml.hangup();
callback(null, twiml);
} else if (digits) {
twiml.say("You pressed a digit");
callback(null, twiml);
} else {
twiml.gather({numDigits: "1", finishOnKey: ""})
.say("Please press a digit to accept the call");
twiml.redirect("https://x.x.x.x/gatherWhisp?Digits=timeout");
callback(null, twiml);
}
};

Twilio modify sms message before forwarding using TWIML

Trying to modify a SMS message (adding a name based on the from phone number) before forwarding the message to a phone using TWIML. The phone no list is small so I will use a switch statement I am guessing in a function. I am not sure how can I wire this together w/o my own server and just using Twilio hosted stuff (TWIML, function, ?)?
Twilio developer evangelist here.
You can absolutely modify the message before forwarding it on.
If you're looking to do so without using your own server, then Twilio Functions is your best bet. Twilio Functions gives you access to a Node.js environment in which you can write functions that respond to webhooks.
To forward a message to a number but add a name based on the incoming number, you can do something like this in a function:
contacts = {
"number": "name"
}
exports.handler = function(context, event, callback) {
const name = contacts[event.From];
if (typeof name !== 'undefined') {
const message = `${name} said: ${event.Body}`;
const response = new Twilio.twiml.MessagingResponse();
response.Message({ to: YOUR_NUMBER, from: YOUR_TWILIO_NUMBER }, message);
callback(null, response);
} else {
// handle not having a name in the contacts
}
}
Check out this quick start on using Twilio Functions for more detail.

Resources