Twilio Node.js - Getting Conference Participant Details In statusCallback - twilio

I'm trying to have the ability to update a call to dial it into a conference, and then I want to keep track of which phone numbers are in the conference. I'll already have the phone number before updating the call, so my plan was to add it as parameter to the statusCallback, then when someone joins, I'll know which phone number has joined (or left). Here is the Twiml I'm using to update the call into the conference.
let conferenceTwiml = function(conferenceName, phoneNumber) {
let voiceResponse = new VoiceResponse();
let options = {
startConferenceOnEnter: true,
endConferenceOnExit: false,
waitUrl: <myWaitUrl>,
statusCallbackEvent: "join leave",
statusCallback: <myStatusCallBackUrl> + '?phoneNumber=' + phoneNumber,
statusCallbackMethod:"POST",
};
voiceResponse.dial().conference(options, conferenceName);
return voiceResponse.toString();
}
The body sent to the statusCallback looks like this:
{
Coaching: 'false',
FriendlyName: 'Room 123',
SequenceNumber: '4',
ConferenceSid: 'CF1c7a162ba5d0587f390a0d7e7c6eb9a5',
EndConferenceOnExit: 'false',
CallSid: 'CA5244195567afec7327bb24d65a2d2b15',
StatusCallbackEvent: 'participant-join',
Timestamp: 'Wed, 17 Jul 2019 18:18:27 +0000',
StartConferenceOnEnter: 'true',
Hold: 'false',
AccountSid: <myAccountSid>,
Muted: 'false'
}
So you can see there's not really any identifying information, without the additional query parameter.
The problem I've run into is that, according to the docs:
The statusCallback URL is set by the first Participant to join the conference, subsequent statusCallbacks will be ignored.
So in essence I can't dynamically set the phoneNumber parameter for each person I'm dialing into the conference, since it will always reflect the phoneNumber of the first person who joined.
My question is, how can I get some kind of identifying information about who is joining or leaving the conference? Where are my twilio evangelists at? Thanks!

Heyooo Developer Evangelist here. 👋
There are two ways to approach this.
1. Persist the call information via CallSid yourself
When you receive the initial phone call and you put people into the conference, what you could do it to persist the call information (including the phone number) on your end and use the CallSid later to reference it when you receive the statusCallback hook. This way you would have all the information at hand using the available CallSid when the statusCallback hook comes in.
2. Fetch the call information when you receive the statusCallback
While the statusCallback hook doesn't include the call details what you can always do is to fetch the call information again by using the CallSid. This way you can take the information from StatusCallbackEvent and merge it with additional information after you received the call details.
Both approaches have pros and cons but are similar in the way that you have to get the call information from "somewhere".
The first approach needs you to find a way to persist call information. This brings additional overhead in your application.
The second approach saves you the need to persist call details but introduces an additional API request.
As always – it depends on your case. I hope that helps. :)

Related

Listen live calls on Twilio

I'm trying to create an interactive dashboard that shows Twilio calls with the ability to listen to any ongoing calls. Is it possible? And what is the best approach I should take?
I saw two methods on the documentation which are Twiml Voice: and Twiml Voice: . Conference doesn't suit with my scenario because incoming calls are not ringing. And I couldn't find a way to listen to voice Streams on the documentation.
Note: Currently inbound calls are handled by Twilio function and WebSocket and outbound calls are handled by Twilio JavaScript SDK.
Thanks in advance.
If you want to listen to a live Voicecall you could try the Stream as IObert suggests. Or, you must use the Conference feature and add yourself as a "Coach." Don't be put off by the name Conference. Think of it as a Voicecall with many more helpful features. You can create a conference from an outbound call like this:
string accountSid = "ACxxxxxx";
string authToken = "xxxxx";
TwilioClient.Init(accountSid, authToken);
var voiceresponse = new VoiceResponse();
var say = new Say("Setting up your conference.");
var dialConference = new Dial();
dialConference.Conference(
name: "Your Conference"
startConferenceOnEnter: true,
endConferenceOnExit: true
);
voiceresponse.Append(say);
voiceresponse.Append(dialConference);
var twiml = voiceresponse.ToString();
var call = CallResource.Create(
twiml: new Twilio.Types.Twiml(twiml),
to: new Twilio.Types.PhoneNumber("E164 Number to Dial"),
from: new Twilio.Types.PhoneNumber("E164 Your Twilio Number")
);
Then once you have a conference started, you can add the second call from either an inbound or outbound call. With an inbound call, use Twiml to send the call to the conference. With an outbound call, use the REST API to add a Conference Participant.
From the client side, using the Twilio Javascript Client, you would then connect your device to the Conference with the correct Conference Twiml parameters which is explained here:
https://www.twilio.com/docs/voice/sdks/javascript/twiliodevice#deviceconnectconnectoptions
const device = new Device(token);
let call = await device.connect({
params: {
To: 'Your Conference'
}
});
I use a slightly different method...I use a button on the client that when you click it makes an outbound call to the "coach" using the Conference Participant REST API. The coach answers and is added with mute = true. The "coach" uses the Twilio Client for WebRTC but the same process will work with a "regular" phone line with a phone number. Using the Twilio Client in this way allows the coach to listen on their computer speakers which is convenient.
The harder part is you will need to keep track of which calls are active on the client side. Otherwise, you won't have an accurate list of which calls or conferences are active. Repeatedly polling the Twilio REST API for active calls is not recommended by Twilio and is super slow compared to using the webhooks to notify of call status changes.

Gathering speech during outbound twilio voice call

I am trying to create a voice call from twilio to a number using programmable voice.
I also intend to gather recipient's speech transcribed. However, the documentation contains examples and tutorials only for inbound voice calls.
This is what I have tried-
Initiating voice call:
client.calls
.create({
twiml: `<Response><Gather input="speech" action="https://ngrok-url-for-my-local-server/voice" method="POST" speechTimeout="5"><Say>Hey there, How are you?</Say><Pause length="4" /></Gather></Response>`,
to: toPhoneNumber,
from: myPhoneNumber,
})
.then((call) => {
console.log(call.sid)
console.log(call)
})
.catch((e) => {
console.log(e)
})
Code in handler for gathering speech-
const VoiceResponse = twiml.VoiceResponse
const res = new VoiceResponse()
res.gather()
console.log(res.toString())
However I am not getting anything useful in the console.
Can anybody point me to a useful tutorial or example or tell me what I should do ?
You need to first make the call and then modify the call to gather.
When you make the call using the new VoiceResponse() call you will be returned a SID for the call. Next, use that SID to modify a call that is in progress by redirecting to the Twiml to gather the digits.
You will have three legs:
Make the outbound call (you provided this code in your questions).
Modify the active outbound call by using the call's SID to redirect to a Gather twiml.
After the gather has finished tell the call what do to using the action parameter of the gather. Here is an example.
If you are trying to go for a conference bridge type feature where you press * to move into an admin type menu, you will need a more complex solution involving a conference call.

How do you forward Twilio calls to different URLs in the middle of a call? (Using Node)

I'd like the following functionality with Twilio/Node: either
my server receives incoming call and the call rings on our custom client; at some point during the call (ideally can work before answering or after answering) or if no one answers on the client, the call is transferred to a webhook on a different server (my CRM provider) so the CRM can deal with it. OR
same as above, but the incoming call posts the incoming call request to both my server & my CRM webhook for the incoming call; I think this might not be possible though, not sure
I'm able to receive a Twilio call on my server without problem, and able to receive Twilio calls in my CRM without problem. However, when I tried to forward a call to the CRM after first receiving it on my custom server/client, it seems to always disconnect abrubtly. Pls help!
The code I'm using to update the call is below. The url works normally if sending the call directly to the CRM webhook. The CallSid is from my custom client from the incoming call
client.calls(req.body.CallSid)
.update({method: 'POST', url: 'https://crm.crmprovider.com/ctiapi/xml/cticall/twilio?authtoken=abc'})
Appreciate any help!
Think I figured out the proper way to do this. Should be using an "action" with "dial" and then checking "DialCallStatus" in the action endpoint and dealing with various statuses as appropriate. Sample code:
// On server, receive call. This is the url Twilio is
// set to post webhook to when call comes in
app.post('/incomingCall', (req, res) => {
const twiml = new VoiceResponse();
// Dial client first; after, call /callAction
// I believe this will call /callAction if call is unanswered for 10 seconds or after a completed call or if there's no client open
const dial = twiml.dial({timeout:10, action: '/callAction'});
const client = 'whateverClientName'
dial.client(client)
res.type('text/xml')
res.send(twiml.toString())
})
app.post('/callAction',(req,res)=>{
const twiml = new VoiceResponse();
// Can set below if for other things like if call not completed, answered, or cancelled
// In this example we say if call's not completed, route call to 3rd party site's webhook to further deal with the ongoing call
if(req.body.DialCallStatus!=='completed'){
twiml.redirect({method: 'POST'},'https://thirdpartywebhook.com/abc')}
else {twiml.hangup()}
res.type('text/xml')
res.send(twiml.toString())
})
I didn't find Twilio docs super straightforward on this so hopefully this helps someone in the future!

Agent to see real caller number with Twilio <Queue>

I've built an IVR system and I cannot achieve how agents can see real callers numbers, not the proxy number (aka Twilio's number):
$response->enqueue('commercial', ['waitUrl' => 'https://xxxxxxxion.com/playStory']);
$call = $client->calls->create(
'+407xxxxxxx15',
'+403xxxxxxx56',
array("url" => "https://xxxxxxxx.com/queues.php?type=commercial", 'timeout' => 15, 'record' => true, "statusCallback" => "https://xxxxxxxxx.com/notify.php", "callerId" => $_REQUEST['From'])
);
I have tried an alternative with "callerId" => $_REQUEST['From'] to get the Caller ID at the end of the call, but this parameter doesn't appear nowere.
With SIP calls is simple because I can set From parameter directly in the method call:
$call = $client->calls->create(
'sip:xxxxxxx.sip.us1.twilio.com',
$_REQUEST['From'], //here I set real Caller ID for Agent to see
Tried also with call forwarding, but cannot put the callers into a queue, or, at least to have a waitUrl for on-hold audio - the part I really need in this story.
Twilio developer evangelist here.
With Twilio you can only set the From parameter, the caller ID, of an outbound call, the call you are making using the REST API, to a number you have either bought with Twilio or verified that you own.
The only way to forward on the original caller ID is to use <Dial> to connect the calls, but you say you need wait music.
One alternative you could use is to perform a call whisper that reads out the number that the agent is about to be connected to, using <Say>, and then connecting them to the queue.
Let me know if that helps at all.

Twilio Gather is recording too soon

The following code is used to build up TwiML to ask the caller which department they are looking for.
If the user is already talking when the gather.Say is being read to the caller, then whatever they are saying over the message is being included, as well as their actual answer to the question in the Action url.
The documentation states:
The following example shows a that specifies speech input
from the user. When this TwiML executes, the caller will hear the
prompt. Twilio will then collect speech input for up to 60
seconds.
However the speech input collection is happening whilst the say is executing.
How do i make sure that whatever is being said whilst the Say is executing is not included as part of the actual response to the question?
...
var call = GetCallData();
var gather = new Gather(
timeout: 4,
input: new List<Gather.InputEnum> { Gather.InputEnum.Speech },
method: HttpMethod.Post,
language: call.TwilioLanguage,
bargeIn: false
)
{
Action = new Uri("MyUrl/Answer/Department")
};
gather.Say("Please say the name of the department you wish to be connected to",
language: call.TwilioLanguage,
voice: call.TwilioVoice);
response.Append(gather);
response.Redirect(new Uri("MyUrl/Hangup"), HttpMethod.Post);
return TwiML(response);
If you do not nest the Say in the Gather, the caller must listen to the Say before the Gather collects input.
More details are here.
TwiML Gather
"By nesting Say or Play in your Gather, you can read some text or play music for your caller while waiting for their input. See "Nest other verbs" below for examples and more information."

Resources