Different Twiml for voicemail - twilio

we have a Windows service, that automatically send multiple voice calls for appointment reminders.
var call = CallResource.Create(
machineDetection: "DetectMessageEnd",
asyncAmd: "true",
twiml: new Twiml(message),
to: new PhoneNumber(toPhone),
from: new PhoneNumber(FromPhone));
The message used for the one above is dynamically generated using the Twiml below.
<Response>
<Pause length="1"/>
<Say voice="alice">Hello {name},</Say>
<Pause length="1"/>
<Say voice="alice">Your appointment is scheduled for {date} at {time}.</Say>
<Pause length="1"/>
<Gather timeout="3" numDigits="1" action="https://6f8137e0cb9a.ngrok.io/Voice/gather?aid=12345" method="GET">
<Say voice="alice">To confirm this appointment press 1, to cancel press 2, or you may hang up.</Say>
</Gather>
</Response>
It works fine, when the call is picked up, but if no answer then when it goes to voicemail. I want to send a different Twiml like the one below
<Response>
<Pause length="1"/>
<Say voice="alice">Hello {name},</Say>
<Pause length="1"/>
<Say voice="alice">Your appointment is scheduled for {date} at {time}.</Say>
<Pause length="1"/>
<Say voice="alice">To confirm or cancel this appointment call 18888888888.</Say>
</Response>
Is this even possible with Twilio ?

Twilio developer evangelist here.
That is absolutely possible! In your original script it shows that you are using asyncAmd, which means that your initial message will start playing even as the machine detection goes on. If a machine is detected then the AMD will want to alert you of that.
To do that, you need to provide an asyncAmdStatusCallback parameter to your outbound call that points to a URL that can receive a webhook when you get the result from the AMD.
That webhook will receive paramters including the CallSid and your AccountSid and most importantly the AnsweredBy parameter. When using DetectMessageEnd for your AMD, the AnsweredBy parameter could be any of "machine_end_beep", "machine_end_silence", "machine_end_other", "human", "fax" and "unknown".
For the machine results, if you want to leave a message you will now need to update your call with new TwiML.
var call = CallResource.Update(
twiml: new Twiml(MACHINE_MESSAGE),
pathSid: CALL_SID
);
Let me know if that helps at all.

Related

How do you access the information gathered on a Twilio phone call?

I have the following code:
<?xml version="1.0" encoding="UTF-8"?>
<!-- page located at http://example.com/simple_gather.xml -->
<Response>
<Pause length="2"/> <Play>https://welcomehisheart.com/wp-content/uploads/2021/10/congress-invitation.mp3</Play>
<Pause length="1"/>
<Say>If you would no longer like to receive information about the Sacred Heart, press 2</Say>
<Gather/>
<Pause length="1"/>
</Response>
The TwiML URL is:
https://handler.twilio.com/twiml/EHe23193a659bfcf74b1061864aea9b224
The code works as expected. You can enter a selection during the phone call.
How to access the information gathered?
Thanks
Twilio developer evangelist here.
It looks like you are working with a TwiML Bin there, which is great for a static piece of TwiML like this first message. However, there are a couple of issues.
Firstly, you are not giving the user the proper time to enter their input. The <Gather> element is best used with the message nested within it, so that a user can press at any time. You can also set a timeout to better control how long they have to respond once the nested <Say> is complete. The default value of timeout is 5 seconds.
Secondly, if you are just waiting for the user to press a single digit, you can add the numDigits="1" attribute to the <Gather>. This will complete the <Gather> once the user presses a single digit.
Finally, and the subject of your question, you need to give the <Gather> a URL as the action attribute. Then, when a user presses a key, Twilio will make an HTTP request to that URL with the results of their input. You need to build an application that will handle that request and do something with the result of the key press.
So, you should update your TwiML to:
<?xml version="1.0" encoding="UTF-8"?>
<!-- page located at http://example.com/simple_gather.xml -->
<Response>
<Pause length="2"/>
<Play>https://welcomehisheart.com/wp-content/uploads/2021/10/congress-invitation.mp3</Play>
<Pause length="1"/>
<Gather numDigits="1" action="https://example.com/gather">
<Say>If you would no longer like to receive information about the Sacred Heart, press 2</Say>
</Gather>
</Response>
and you need to create an application that can receive an HTTP request, in this case at the URL example.com/gather, though you should provide your own URL here.
There are tutorials on how to gather user input in a phone call that will walk through this in more depth with code examples, that you should read next.

Twilio to have pause period when using loop to repeat voice call

I tried repeating a message in voice call as python code here which was guided here but not working i.e. no pause at all whatever number for :length it is <Pause length="3">
call = client.calls.create(
twiml = f'''
<Response>
<Gather>
<Say loop="{loop}">{message}</Say>
<Pause length="3"></Pause>
</Gather>
<Redirect>/gather.xml</Redirect>
</Response>
''',
to = to,
from_ = from_,
)
Take a look at SSML Pause.
Adding a Pause
SSML Break Tag
I tried out the below, and it worked. Don't forget your <Gather> action url.
<Response>
<Gather>
<Say loop="3">This is a message with a pause between loops<break time="3s"/></Say>
</Gather>
<Redirect>/gather.xml</Redirect>
</Response>

Twilio: Responding to a caller after transcript for previous response is received

I'm trying to get the following flow to work:
Caller dials twilio #
We ask a question of the caller and they respond by speaking
Once the transcript is received (not the audio file), we respond by asking them another question... this goes on for 2-3 questions
The problem I'm having is the separation of the calls to the main webhook handler, and the transcript handler.
I have the primary call handler responding with the first question, as follows:
<!-- [/ handler] initial response, with the first question -->
<Response>
<Say voice="alice">What is your favorite color? Press any key when done.</Say>
<Record transcribe="true" transcribeCallback="/transcript" maxLength="60"/>
</Response>
Then we receive a second request to the primary call handler when the recording is completed. I can't respond with another question yet (business requirements), so we respond with a vague confirmation:
<!-- [/ handler] vague confirmation response
<Response>
<Say voice="alice">Got it. Give me a couple seconds to write that down.</Say>
</Response>
Then I receive a hit on the /transcript handler with the transcript, to which I respond with:
<!-- [/transcript handler] Second question -->
<Response>
<Say voice="alice">What is the air-speed velocity of an unladen swallow? Press any key when done.</Say>
<Record transcribe="true" transcribeCallback="/transcription" maxLength="60"/>
</Response>
But apparently you can't respond to that handler with TWiML? The caller is hung up on after the second response from the / handler.
Any ideas on how I can implement this? I don't think I can really have the user wait in silence before responding to the second / handler request...
When you receive a hit on your /transcript handler you have in the request the callSid (CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX) among other parameters.
With this callSid you can modify the "in progress call" my making a request to Twilio and passing a new TwiML.
Not sure what language are you using on your server side but in Node.js would look something like this:
const accountSid = 'ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX';
const authToken = 'your_auth_token';
const client = require('twilio')(accountSid, authToken);
client.calls('CAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
.update({twiml: '<Response>
<Say voice="alice">What is the air-speed velocity of an unladen swallow? Press any key when done.</Say>
<Record transcribe="true" transcribeCallback="/transcription" maxLength="60"/>
</Response>'})
.then(call => console.log(call.to));
Docs: (https://www.twilio.com/docs/voice/tutorials/how-to-modify-calls-in-progress-node-js)
Twilio developer evangelist here.
While you seem to have got this version of your call flow working, it is not the best way of approaching this issue as we now have <Gather input="speech">.
<Gather> with the input set to "speech" will transcribe the user in real time, delivering the SpeechResult to your next webhook URL (the action attribute). This way you don't need to wait while the transcription is performed asynchronously and can respond with TwiML immediately.
Using <Gather> like this would let you build a call flow like:
<!-- [/ handler] initial response, with the first question -->
<Response>
<Gather action="/question2" input="speech">
<Say voice="alice">What is your favorite color?</Say>
<Gather>
</Response>
Then in /question2 you can dynamically read the response straight away. Here's how you could respond using Ruby and Sinatra as an example server side language:
post "/question2" do
favorite_color = params["SpeechResult"]
response = "Great, I love the color #{favorite_color} too. Now, what's your favorite pet?"
return "<Response>
<Gather action="/question3" input="speech">
<Say>#{response}</Say>
</Gather>
</Response>"
end
And so on. You should find it a much better experience than using <Record> with transcription.

Announcing the name of participant joining the Conference

I am building a simple conference using Twilio where a conference is started by Agent using Twilio client and a contact is called and added to this conference. Just before adding this contact to conference, we would like to announce the name of the contact in the conference room (for ex: <Say>Now Joining Sam Carter </Say>). The name of the person is figured out based on their phone number from database.
When a call is connected, the following TwiML is executed which connects the contact to the conference:
<Dial callerId="+1415xxxxxxx" record="true" action="/my/action/url">
<Conference endConferenceOnExit="true" >ConferenceRoom1</Conference>
</Dial>
Is there any way to play a message into conference just before <DIAL> verb is executed. If i write <SAY> verb before <DIAL> then it plays message to the contact, not in the CONFERENCEROOM1.
Are there any events like onConferenceEnter, which can be used to fire another TwiML whenever some participant enters the conference? Please suggest what would be the best way to achieve this behavior.
The short answer to the question is that it can't be done through a Twiml Event however it can be done with a kind of hack using their REST API.
The question has already been asked on SO and the answer is available here:
Use Say verb to all Conference participants
Incase the question/answer is ever deleted/removed i've pasted it below:
Here's something that should resemble a good end-to-end solution.
First, the user dials in and you go through the standard prompts to get the PIN for the conference room and their name.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather action="/conference/pin" finishOnKey="#">
<Say>Please the conference pin number followed by the pound key.</Say>
</Gather>
</Response>
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Say your name and then press the pound key.</Say>
<Record action="/conference/name" finishOnKey="#" />
</Response>
Now, once you have the user's pin and recording, two things will happen; the response from the post to /conference/name will contain the verb, placing the user in the room:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference>{conference ID}</Conference>
</Dial>
</Response>
...and, asynchronous to that, it will use the REST API to initiate a new call back into the conference room.
POST /2010-04-01/Accounts/{AccountSid}/Calls
From = {your conference phone number}
To = {your conference phone number}
SendDigits = wwww{conference PIN}#
Url = /conference/announce?name={name ID}
Now, the next bit gets confusing. Twilio will now be talking to your callback URL for the incoming end of the call, and the URL you specified above for the outgoing end of the call. Your incoming call handler will need to detect that the conference line is calling back into itself and behave differently; it will first need to respond with simple TwiML that allows the outgoing end of the call to enter the pin for the conference room.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather action="/conference/announce-pin" finishOnKey="#" />
</Response>
The SendDigits parameter of the POST will provide the digits that bit of TwiML is expecting. That action should then respond by conferencing in the new call.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference>{conference ID}</Conference>
</Dial>
</Response>
The last piece of the puzzle is the TwiML emitted by the URL you specified in the POST. That's the markup that will run once the loopback call is added to the conference.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Play>/conference/name-recordings/{name ID}</Play>
<Say>has joined the call.</Say>
<Hangup />
</Response>
That markup runs, plays the caller's name and a message into the conference room, and then hangs up.
For benefit of others, this is how I have implemented this behavior :
An agent has started the conference using Twilio client and he is already in conference. As soon as a participant is about to join the same conference, using REST API, modify the URL of the live conference call.
TwilioRestClient client = new TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN);
Map<String, String> filter = new HashMap<String, String>();
filter.put("From", "client:AGENT1");
filter.put("Status", "in-progress");
CallList callList = account.getCalls(filter);
Call agentsCall = null;
for (Call inProgressCall : callList) {
agentsCall = inProgressCall;
break; //return the first one only..there shouldn't be more
}
Map<String, String> agentsCallParams = new HashMap<String, String>();
agentsCallParams.put("Url", "http://myserver.com/twiml/agentmessage.xml");
agentsCallParams.put("Method", "GET");
agentsCall.update(agentsCallParams);`
The above code snippet will update the twiml of existing call as below.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Now joining {name of the participant}</Say>
<Dial>
<Conference>Conference1</Conference>
</Dial>
</Response>
The above Twiml will update the call to play the message in <SAY> verb and then put the agent back into the conference.
Now, make the participant join the same conference by returning the below Twiml:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference>Conference1</Conference>
</Dial>
Hope this helps !!!

Use Say verb to all Conference participants

I'm setting up a pretty simple conference call system, where the user enters a PIN and is connected to a conference associated with that. I'm also setting it up so they record their name before entering the room.
My plan is to take the recording URL, then get the list of participants and make the REST API call to each caller modifying their call to to the Say "Now entering", then Play the recording url. I think I'm going to have to send them back into the room after that as well, I'm not sure.
I think that modifying each call will take them out of the Conference room, which is not ideal. Is there an easier way to use Say/Play to all members of a conference built into the REST API?
As of July 13th 2018, Twilio now allows you to send a POST request to the Conference (to announce something to the whole conference) or Conference Participant (to announce something to a single caller) resources with an AnnounceUrl property that links to either:
a WAV or MP3 audio file, or
a TwiML document that uses the <Say /> and/or <Play /> verbs.
Along with that property, you can also specify an AnnounceMethod property that lets you specify whether to GET or POST (the default) that URL.
A good place to send the aforementioned POST to play back your recorded name might be in a status callback that's set when you use the <Conference /> verb to put each user into the conference, like so:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference statusCallback="/conference/join-callback"
statusCallbackEvent="join">
{conference ID}
</Conference>
</Dial>
</Response>
The old workaround remains below for posterity.
Someone on the Twilio forums was interested in the very same question, and the answer is currently that there isn't a direct REST API call for that.
What you'll need to do is, when a participant joins the conference, you'll use the REST API to make Twilio dial back in to your application. You can choose how to detect that you're calling into your own conference however you like (for example, comparing the outbound and inbound phone numbers for equality); once you've detected that, you can join that call directly to the conference and use the TwiML <Say /> and <Play /> verbs to play back the introduction for everybody.
It's a little bit convoluted, but this way you won't be removing each participant from the conference (preventing them from hearing each other for a moment) and then rejoining them.
Here's something that should resemble a good end-to-end solution.
First, the user dials in and you go through the standard prompts to get the PIN for the conference room and their name.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather action="/conference/pin" finishOnKey="#">
<Say>Please the conference pin number followed by the pound key.</Say>
</Gather>
</Response>
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Say>Say your name and then press the pound key.</Say>
<Record action="/conference/name" finishOnKey="#" />
</Response>
Now, once you have the user's pin and recording, two things will happen; the response from the post to /conference/name will contain the <Conference> verb, placing the user in the room:
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference>{conference ID}</Conference>
</Dial>
</Response>
...and, asynchronous to that, it will use the REST API to initiate a new call back into the conference room.
POST /2010-04-01/Accounts/{AccountSid}/Calls
From = {your conference phone number}
To = {your conference phone number}
SendDigits = wwww{conference PIN}#
Url = /conference/announce?name={name ID}
Now, the next bit gets confusing. Twilio will now be talking to your callback URL for the incoming end of the call, and the URL you specified above for the outgoing end of the call. Your incoming call handler will need to detect that the conference line is calling back into itself and behave differently; it will first need to respond with simple TwiML that allows the outgoing end of the call to enter the pin for the conference room.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Gather action="/conference/announce-pin" finishOnKey="#" />
</Response>
The SendDigits parameter of the POST will provide the digits that bit of TwiML is expecting. That action should then respond by conferencing in the new call.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Dial>
<Conference>{conference ID}</Conference>
</Dial>
</Response>
The last piece of the puzzle is the TwiML emitted by the URL you specified in the POST. That's the markup that will run once the loopback call is added to the conference.
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Play>/conference/name-recordings/{name ID}</Play>
<Say>has joined the call.</Say>
<Hangup />
</Response>
That markup runs, plays the caller's name and a message into the conference room, and then hangs up.

Resources