I've been working with twilio, using Node.js, and dialing call between two web end points. One is client and other is agent. I'm using following code to dial call.
function dialCall(calledNumber, url) {
client.calls.create({
to: `client:${calledNumber}`,
from: twilioNumber,
url: url
})
.then(call => call.sid));
}
I'm using following twiml to establish a call.
const generateTwiml = (conferenceName) => {
let twimlResponse = new VoiceResponse();
twimlResponse.say(`Welcome to unity dialer.`, {
voice: 'alice',
});
const dial = twimlResponse.dial({
timeLimit: '600',
});
dial.conference({
startConferenceOnEnter: true,
endConferenceOnExit: true
}, "Test Room");
return twimlResponse.toString();
};
I've been successfully calling both agents and clients and getting callSid of both calls. However, my question is that at this point of time I also want to get conference Sid as well as I'm dialing the call as conference. What is the method to get that. As per documentation there is a method to fetch conference using conference name and status. However, if I use this some time the same is not returned due to race condition and I have to implement set time out function for same arbitrary delay. I've been getting the result but is there any other solution available for that.
Twilio developer evangelist here.
At the time you return the TwiML to create the conference there is not yet a conference resource so there's no way to get the conference SID at that stage.
As you describe, you can use the conference resource to list conferences and filter by the name you give it. However, you can't list the conferences at the time you return the TwiML because that conference hasn't been created by then.
Rather than setting a timeout, which could be flaky, I recommend you use the statusCallback attribute of the <Conference> TwiML to set a URL to callback to when the conference starts. In the parameters to that callback you will get the ConferenceSid.
Related
I am currently working with the plivo api to build an ivr, however, I have used all the recommendations given by the documentation and so far I can not establish a successful connection within the conference calls in the application, below I attach the code that is involved in the conference function.
getDialConnecting(numberFrom, numberTo, route){
let ivr = new Ivr();
let client = ivr.getClient();
client.calls.create(
`${numberFrom}`,
`${numberTo}`,
`${process.env.HOST}${route}`,
{
answerMethod: "POST"
},
).then(function(response){
console.log(response);
}, function(err){
console.log(err);
});
this function is called each time I make a conference call and enter the following parameters
I am currently working with the plivo api to build an ivr, however, I have used all the recommendations given by the documentation and so far I can not establish a successful connection within the conference calls in the application, below I attach the code that is involved in the conference function.
call.getDialConnecting(`${incomingNumber}`, `${incomingNumberTransmitter}`, 'conference');
in addition this is the path that is performing the handling of the function that accepts the call
const ivrGetConference = route.post('/voice/conference', call.callRequestConfirmed);
My name is Mohammed Huzaif, and I work at Plivo as a Product Evangelist.
From the information shared, I'm unable to determine the error you may have received on your end or the documents utilised.
However, you can follow the below steps to build an IVR.
First, we'll create our IVR, To do so, follow the directions in this documentation.
Once the IVR system is developed, we will make a call to the destination number by using the URL generated in above step.
To make a call, use the below code.
Note: Replace the placeholders "from": with the caller_id, "to": Destination number, and "answer_url": the url generated in above step.
var plivo = require('plivo');
(function main() {
'use strict';
var client = new plivo.Client("<auth_id>","<auth_token>"); // https://console.plivo.com/dashboard/
client.calls.create(
"+14151234567", // from
"+15671234567", // to
"https://s3.amazonaws.com/static.plivo.com/answer.xml", // answer url
{
answerMethod: "POST",
},
).then(function (response) {
console.log(response);
}, function (err) {
console.error(err);
});})();
In case, if you still need any assistance, feel free to reach out to our support-team.
I've nearly finished my phone system with twilio and the final part is a voicemail playback. If the call fails or is declined, the calling party can leave a message and it saves to the twilio recordings. All server side code is done in Twilio Functions.
Now I want the end party to be able to check their voicemail by dialing an extension and playing back the saved messages. Everything up to the playing back of messages is done because I can't get the recording uri from a list of recordings.
Note NodeJS is not my strong suite.
I have tried playing back all recordings with:
exports.handler = function(context, event, callback) {
const twilioClient = context.getTwilioClient();
let response = new Twilio.twiml.VoiceResponse();
twilioClient.recordings.each(recording => response.play(recording.uri));
callback(null, response);
}
But I don't the expected result (i.e. I get a 200 OK and the <Response/> xml). I have Enable ACCOUNT_SID and AUTH_TOKEN enabled in the functions configuration.
I feel like it has something to do with the callback and the request to the api being asynchronous but I couldn't find much information on the recordings docs (https://www.twilio.com/docs/api/voice/recording).
Found the documentation I was after in the automated docs (https://www.twilio.com/docs/libraries/reference/twilio-node/3.11.2/Twilio.Api.V2010.AccountContext.RecordingList.html).
client.recordings.each({
callback: function (recording) {
response.say('New Message');
const recordingSid = recording.sid;
},
done: function () {
callback(null, response);
},
});
I'm trying to move the inbound caller to a conference room:
//this is the endpoint for the voice webhook
app.post('/voice',(req,res)=>{
sid=req.body.CallSid;
conferenceName="test conference room";
params={'conferenceName':conferenceName};
url='https://appname.herokuapp.com/addToConference?conferenceName=test';
console.log('now updating inbound call sid '+sid);
client.calls(sid).update({
url:url,
method:'GET'
});
});
//this is the endpoint for adding a caller to a conference
app.get('/addToConference',(req,res)=>{
var conferenceName=req.query.conferenceName;
const response=new VoiceResponse();
response.say("Now connecting you to conference "+conferenceName);
dial=response.dial();
dial.conference(conferenceName);
responseTwiml=response.toString();
console.log("responseTwiml: "+responseTwiml);
res.send(responseTwiml);
});
Console logging shows that the .update() call is reached:
now updating inbound call sid 9j92f892309
But then the Twilio debugger shows an 11205 error, where the url is https://appname.herokuapp.com/voice/. The console log does not show Now connecting you to conference test, so I'm guessing the /addToConference endpoint isn't being reached. Heroku error log shows a Request timeout error.
How can I reach the endpoint and drop the inbound caller into a conference call? If it matters, I want the app to then call someone else, interact with them, and then transfer that call recipient to the conference where the inbound caller is waiting.
Twilio developer evangelist here.
There's a couple of issues here. To start with, the 11205 error is because of a timeout from the call to your /voice endpoint. The issue here is that you never return anything from the function with the res. You could fix that one by calling res.send('') at the end of that function.
However...
There is no need to do the redirect that you're doing at all. You can use the initial webhook response to both drop the caller into the conference and dial the other party. You would do this with the following code:
app.post('/voice',(req,res)=>{
conferenceName="test conference room";
url='https://appname.herokuapp.com/addToConference?conferenceName=' + conferenceName;
client.calls.create({
from: YOUR_TWILIO_NUMBER,
to: THE_OTHER_PERSON,
url: url
});
const response=new VoiceResponse();
response.say("Now connecting you to conference "+conferenceName);
dial=response.dial();
dial.conference(conferenceName);
responseTwiml=response.toString();
res.set('Content-Type': 'text/xml');
res.send(responseTwiml);
});
For this you will still need the /addToConference endpoint which just adds the other caller to the conference, which would look like this:
app.get('/addToConference',(req,res)=>{
var conferenceName=req.query.conferenceName;
const response=new VoiceResponse();
response.say("Now connecting you to conference "+conferenceName);
dial=response.dial();
dial.conference(conferenceName);
responseTwiml=response.toString();
console.log("responseTwiml: "+responseTwiml);
res.send(responseTwiml);
});
You could also redirect the caller in the way you wanted to do in the first place, but instead of modifying the call with the REST API you would use the TwiML <Redirect> verb. That would look like this:
app.post('/voice',(req,res)=>{
conferenceName="test conference room";
url='https://appname.herokuapp.com/addToConference?conferenceName=' + conferenceName;
client.calls.create({
from: YOUR_TWILIO_NUMBER,
to: THE_OTHER_PERSON,
url: url
});
const response=new VoiceResponse();
response.redirect(url);
responseTwiml=response.toString();
res.set('Content-Type': 'text/xml');
res.send(responseTwiml);
});
Let me know if that helps at all.
I've set up a basic workflow on Twilio/node.js, that will transfer an incoming call to agents' phones. Because the agents might have a voicemail setup on their phone/cell phone, I wanted to prompt them for acceptance through a "gather" instruction. If they press 1, then the call will be transferred ("dequeue" instruction). Otherwise, the reservation is to be rejected.
My problem is that I don't know how to order the instructions: if I gather before enqueuing, then gather doesn't seem to know yet "who to ask". But if enqueue before gathering, then the prompt message will be heard by the caller (incoming client) and it will be too late to reject the reservation...
Twilio developer evangelist here.
In this case you should not respond to the assignment callback with "dequeue". Instead, you should use the "call" instruction to initiate a call to the agent instead.
With the call instruction you include a URL that will be requested when the call connects to the agent. At this point you should read out your message and use <Gather> to ensure the agent is ready for the call. When the agent presses a button or the <Gather> times out, the action attribute of the <Gather> will be requested. Then, if you find the user did enter a digit, by checking the Digits parameter you can respond with TwiML to <Dial> the <Queue>. In order to dial the actual caller that the reservation refers to, you need to add the reservationSid attribute to the <Queue> element. You will receive the ReservationSid as a parameter in the task assignment webhook. When the call bridges it will accept the reservation.
If the <Gather> times out, then you should just reject the reservation and it will be passed to the next worker.
Let me know if that helps at all.
Edit
Example TwiML for this situation.
You first respond to the assignment callback with JSON, using a call instruction:
{
"instruction": "call",
"to": AGENT_PHONE_NUMBER,
"from": YOUR_TWILIO_NUMBER,
"url": "https://example.com/worker_call?ReservationSid=${req.body.ReservationSid}&TaskSid=${req.body.TaskSid}"
}
Note, I have added the ReservationSid and TaskSid from the incoming request to the URL of the webhook that is called when the worker answers their phone.
Then when the worker answers their phone Twilio calls to the url we set above and we use it to ask them if they want to take the call.
# /worker_call
<Response>
<Gather action="/gather_result?ReservationSid=${req.query.ReservationSid}&TaskSid=${req.query.TaskSid}" numDigits="1">
<Say voice="alice">You have an incoming call, dial any number to accept</Say>
</Gather>
<Redirect>/gather_result?ReservationSid=${req.query.ReservationSid}&TaskSid=${req.query.TaskSid}</Redirect>
</Response>
Note, I am passing the ReservationSid and TaskSid along from the incoming request URL to the URL of the <Gather> action. Now, when the action URL is called we need to respond based on whether the call was accepted or not. I need to use some actual code for this rather than just TwiML, so I'll do it with Node. We need to be able to call the reservations resource in the REST API, so this comes with some setup:
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const workspaceSid = 'WSXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const twilio = require('twilio')
const client = twilio(accountSid, authToken);
app.post('/gather_result', function(req, res) {
const twiml = new twilio.twiml.VoiceResponse();
if (req.body.Digits && req.body.Digits.length > 0) {
// There was a positive result, call the Queue and connect the caller
const dial = twiml.dial();
dial.queue({queue: req.query.ReservationSid});
res.send(twiml.toString());
} else {
// no response, reject the reservation.
client.taskrouter.v1
.workspaces(workspaceSid)
.tasks(req.query.TaskSid)
.reservations(req.query.ReservationSid)
.update({ reservationStatus: 'rejected' })
.then(function() {
// once the reservation is updated, then hangup the call.
twiml.hangup();
res.send(twiml.toString());
});
}
});
Following situation:
Someone called my Twilio Number
Twilio requested my url
Caller gets into a conference (don't starts until a second person join)
TwiML makes call to a Mobile
The Moblie dont accept the call
=> no second Person enters the conference so it wont stop and the caller is stuck there.
My solution is to end the whole call if this happens, I already know where to place the endCall function so this is not my problem. The function looks like this (You'll find it in the twilio API too):
client.calls(accountSid).update({
status: "completed"
}, function(err, call) {
if(err){
console.log(err);
}
});
My programm logic is fine, I see that this function is called at the right place but I receive this Error:
{ status: 404,
message: 'The requested resource /2010-04-01/Accounts/AC/Calls/AC.json was not found',
code: 20404,
moreInfo: 'https://www.twilio.com/docs/errors/20404' }
I already red whats at the moreInfo url but I disqualify
the solutions there. Maybe you have an idea whats the problem with this.
Twilio developer evangelist here.
You are almost all the way there. Your problem is that you are using your accountSid when trying to update the call's status.
You need to get hold of the callSid of the original call. You will find the callSid in the parameters that you receive in the incoming webhook when the person calls your Twilio number.
app.post('/calls', function(req, res, next) {
var callSid = req.body.CallSid;
// store callSid somewhere for use later
// return TwiML to set up conference and dial your mobile number
});
You'll need to save that callSid and then use it at this point later when you want to hangup the call.
client.calls(callSid).update({
status: "completed"
}, function(err, call) {
if(err){
console.log(err);
}
});
Let me know if this helps at all.