Twilio Send & Wait for Reply widget - twilio

I'm using an incoming call flow that starts call recording, asks a bunch of questions, gathers responses, at the end of the call: stops recording and sends a sms to caller using send/wait for reply widget. A response is expected and based on what's in the body of the incoming call, it calls a function.
All this works, except, I am not receiving a response back from the caller.
My concurrent call setting =off
incoming trigger = incoming call
the flow is tied to a phone number (voice)
I'm not sure how to get a reply back into the same flow. Do I need to attach something to the message section of the phone number?
Any guidance would be appreciated

A Studio flow execution represents one call, one SMS, or the incoming call trigger from the REST Trigger. As the call initiates your flow, it will terminate when the call ends.
But you can work around this by using a function that gets invoked when the recording is done. This function can then use the Twilio APIs to fetch contextual information from the call and trigger the REST API interface of the same flow (but with a different trigger).
I created a small example that does something similar:
The flow is triggered by a call, starts a recording, and gathers data
There is a recording callback URL that points to my function
// This is your new function. To start, set the name and path on the left.
exports.handler = function (context, event, callback) {
console.log(`Recording ${event.RecordingSid} state changed to ${event.RecordingStatus}.`)
if (event.RecordingStatus === "completed") {
const client = context.getTwilioClient();
return client.calls(event.CallSid).fetch()
.then(call => {
client.studio.v2.flows(<Flow ID>)
.executions
.create({
to: call.from,
from: <YOUR NUMBER>,
parameters: {
RecordingUrl: event.RecordingUrl,
}
})
.then(execution => {
console.log(`Triggered execution ${execution.sid}`)
return callback(null, "OK");
});
})
.catch(callback)
}
return callback(null, "OK");
};
You can find the ID of your flow in the console (or when you click on the root element and check the Flow Configuration):
The REST API triggers a second flow execution that reads the parameter and uses them to send a text message:

Related

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.

Twilio Voice SDK - Capture Client Identity for Incoming and outgoing calls

I have implemented Twilio Voice JS SDK to make/receive outgoing/incoming calls from within browser.
Using the status callbacks, I get to know when the call was initiated, ringing, in progress and completed.
However, I am not able to find and record which user made/answered a call (All users have different log id and different client identity id).
When the Incoming call is received, incoming event is triggered on voice client (browser), however, there is no call information availale (call SID etc) to record it.
Similarly, when an outgoing call is made, Call SID information is not available.
Code for incoming calls and to record callsid
device.on("incoming", handleIncomingCall);
function handleIncomingCall(call) {
try{
console.log(call.properties.CallSid);
}
catch (err)
{
console.log("An error occurred while retrieving callsid properties from call object.");
}
//show incoming call div
incomingCallDiv.classList.remove("d-none");
//add event listeners for Accept, Reject, and Hangup buttons
incomingCallAcceptButton.onclick = () => {
acceptIncomingCall(call);
};
incomingCallRejectButton.onclick = () => {
rejectIncomingCall(call);
};
incomingCallHangupButton.onclick = () => {
hangupIncomingCall(call);
};
}
Message that I am getting in the console
An error occurred while retrieving callsid properties from call object.
When you make an outgoing call or recive an incoming call event with the Twilio Voice SDK, the Call object has a parameters property that contains the call parameters you would also receive via the webhook.
So, if you are placing an outgoing call, you can get the call Sid like this:
const device = new Device(token);
const call = await device.connect(options);
console.log(call.parameters.CallSid);
Or if you are receiving a call:
const device = new Device(token);
device.on("incoming", call => {
console.log(call.parameters.CallSid);
})
Note that the CallSid you receive here will not match the outbound CallSid to a another phone when placing an outbound call, and will not match the inbound CallSid when receiving the call. Twilio calls between two people (or phone numbers or clients) have a leg for each connection between Twilio and that person, with a different Call Sid for each leg. You can connect the calls together by understanding the call parent. If you are receiving an incoming call, the parent call is the inbound leg. If you are placing an outgoing call, the parent call is that outbound leg. You can list calls and filter by the parent call Sid using the API.

how to handle call disconnection while call is on hold (queued)

I am following this approach to work on hold and resume of a call from the virtual caller's end. It works but I am facing two more issues. FYI, the setup is exactly same.
First:
The first round of Hold, Resume works perfectly. On Hold, I pass the CallSid, then I apply the <Enqueue> TwiMl to the child calls (only one would be here in my case).
client.calls.list({ parentCallSid: callId }).then(calls => {
calls.forEach(call => {
call
.update({ twiml: '<Response><Enqueue>ADMIN_ID</Enqueue></Response>' });
});
});
And on Resume, I update the Sid of the Caller to Dial again from the queue
client
.calls(callId)
.update({ twiml: '<Response><Dial action="/holding"><Queue>ADMIN_ID</Queue></Dial></Response>' })
It works perfectly foe the first round. When I hit the hold for the second time, it says We are sorry, some application error occurred. Good Bye! at the caller end and disconnects. At the receiver end, it goes to playing hold music. What am I doing wrong?
Second:
I see that setting action in the <Dial> keeps it alive and repeats the action TwiMl in my case. But in a normal scenario without any hold, if the receiver disconnects, I as the caller keeps hearing the action repeatably and the call doesn't hang up. Also while on hold, if the caller or callee hangs up the other one just keeps stuck in the current state. Is there any way to fix this with the above setup?
Fixed the issue by using REST API checks for status of the calls.
client.calls.list({ parentCallSid: callId }).then(calls => {
calls.forEach(call => {
if (call.status !== 'in-progress') {
client
.calls(callId)
.update({ status: 'completed' })
}
});
});
F.e. the above code checks if the parent Sid (virtual caller) is disconnected and in that case it disconnects the child 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!

How to fix Twilio function to accept incoming calls and have voicemail functionality

When the function is configured on a Twilio phone number the function will immediately direct the calling party to voicemail failing to notify the called party of an incoming call and denying the called party (SIP endpoint) (user#domain.sip.us1.twilio.com) the ability to answer call(s).
I have also tried using TwiML XML. When I configure a TwiML XML on a Twilio phone number, the called party (user#domain.sip.us1.twilio.com) is notified of incoming call(s) and is able to answer calls and will automatically direct calling parties to voicemail when the called party is unavailable. However, when the call ends gracefully the calling party is directed to voicemail which is an issue.
exports.handler = function(context, event, callback) {
let phoneNumber = "sip:user#domain.sip.us1.twilio.com";
const twiml = new Twilio.twiml.VoiceResponse();
if (event.DialCallStatus === "completed") {
twiml.hangup();
} else {
twiml.say("You have reached users voicemail. Please leave a message and I will get back to you.");
twiml.record({
transcribe: true,
transcribeCallback: "http://twimlets.com/voicemail?Email=user#domain.com",
action: "/hangup"
});
}
callback(null, twiml);
};
The function should provide the called party (user#domain.sip.us1.twilio.com) the ability to answer calls and automatically direct the calling party to voicemail when the called party (user#domain.sip.us1.twilio.com) is unavailable. If there is a way to achieve this with a function or TwiML XML that would be great.
Thank you
You can borrow from the Twilio Function code detailed below, it will do exactly what you are looking for (need to check the DialCallStatus to intelligently determine next steps.
Implement Voicemail

Resources