I want to respond to an inbound voice call with a prerecorded message. Can this be done without using the Twilio API - ie similar to https://www.twilio.com/code-exchange/basic-voice-auto-response but my recording rather than a "robot" voice?
Here's the script to be placed in the "Functions and Assets" section of your console:
exports.handler = function (context, event, callback) {
const twiml = new Twilio.twiml.VoiceResponse();
twiml.play('https://filesamples.com/samples/audio/mp3/sample3.mp3');
callback(null, twiml);
};
Three options to host the file:
You can host it on a web server and replace the URL with the one to your file.
You could store the audio file on Twilio's servers.
Upload your file in "Functions and Assets" (click [Add+] > Upload File). Once uploaded, you will get the URL to put in the script by clicking "Copy URL."
Use "Assets (Classic)" to upload the file.
Related
Unfortunately, when I am using Twilio voice message, it does not play the message and some noise gets to play instead. I used the mime-types supported by Twilio, too.
var response = new VoiceResponse();
var call = Twilio.Rest.Api.V2010.Account.CallResource.Read(parentCallSid: callSid).ToList();
if (call[0].Status.ToString() == "in-progress")
{
VoiceMail voiceMail = voiceMailService.GetVoiceMailByVoiceMailId(voiceMailId);
if (voiceMail != null && !string.IsNullOrEmpty(voiceMail.RecordUrl))
{
response.Play(url: new Uri(voiceMail.RecordUrl));
response.Hangup();
}
Twilio.Rest.Api.V2010.Account.CallResource.Update(new Twilio.Rest.Api.V2010.Account.UpdateCallOptions(call[0].Sid) { Twiml = response.ToString() });
status = true;
can you please help
Twilio developer evangelist here.
From the comments, we established that you are creating audio files using the web's MediaRecorder API and trying to play those files back through Twilio.
The MediaRecorder API is only capable of creating webm files. Saving those files with a different mime type/extension does not convert them to that other format.
The Twilio <Play> element can only play files in the following formats: mp3, wav, aiff, gsm, and ulaw.
If you want to use the audio you record in the browser you will need to convert the webm files to one of those formats. You could do this in the browser with a site like Cloudconvert. That is not very scalable though, so you likely want to automate this conversion in your own code.
You could use a third party service, like Cloudinary, to perform these audio transformations. There is example code in the Cloudinary docs for this.
Alternatively you could convert these files on your own server. I am not a C# developer, so I can't give you a good example here. But you likely want to rely on an underlying media library, like ffmpeg or SoX. There are likely libraries to wrap these in C# and tutorials for how to use them, but I can't help any further with that.
Kindly use the method bellow
PHP laravel
use Twilio\TwiML\VoiceResponse;
$response = new VoiceResponse();
$response->play(http://www.yourwebsite.com/dir/welcome_mp3);
echo $response;
exit;
will return this code on your webhooks can play an mp3
<?xml version="1.0" encoding="UTF-8"?>
<Response>
<Play loop="10">https://api.twilio.com/cowbell.mp3</Play>
</Response>
How to download a file with Playwright?
I'm aware of this question
How to catch a download with playwright?
but that example code does not work. Using the latest released Playwright, there is no 'pageTarget' function on the browser instance:
const client = await browser.pageTarget(page).createCDPSession();
All the downloaded files belonging to the browser context are deleted when the browser context is closed. All downloaded files are deleted when the browser closes.
Download event is emitted once the download starts. Download path becomes available once download completes:
const [ download ] = await Promise.all([
page.waitForEvent('download'), // wait for download to start
page.click('a')
]);
// wait for download to complete
const path = await download.path();
...
https://github.com/microsoft/playwright/blob/master/docs/api.md#class-download
Playwright is going to support downloads in a cross-browser compatible way soon, you can track this feature request.
For now the above Chromium-specific snippet could be fixed by changing the line to:
const client = await context.newCDPSession(page);
which uses the new method for creating CDP sessions.
My company uses Twilio Flex as our phone system and I was recently tasked with setting up a feature that will let us edit a TwiML voice message that plays before our normal voice message. This TwiML message will be changed through a Twilio bot that I've published in our Microsoft Teams.
The reason for this is so that our support desk can add a short message in the lines of "We're currently experiencing issues with X" before our normal "Welcome to [Company] support" message.
If TwiML's can be edited using HTTP POST/PUT or Twilio's API this should be a trivial matter, but so far I've not been able to figure out how.
I couldn't find any reference to this in the API doc, so I decided that HTTP POST would be the way to go. Using this as a start off point, I'm able to retrieve my TwiML using HTTP GET:
https://support.twilio.com/hc/en-us/articles/223132187--Not-Authorized-error-when-trying-to-view-TwiML-Bin-URL
const axios = require('axios');
const crypto = require('crypto');
const accountSidFlex = process.env.accountSidFlex;
const authTokenFlex = process.env.authTokenFlex;
var URL = 'https://handler.twilio.com/twiml/EHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + '?AccountSid=' + accountSidFlex
var twilioSig = crypto.createHmac('sha1', authTokenFlex).update(new Buffer(URL, 'utf-8')).digest('Base64')
var config = {
headers:{
'X-TWILIO-SIGNATURE': twilioSig
}
}
axios.get(
URL,config
).catch(error => console.log(error))
.then(response => {
console.log(response.data)
})
response.data shows the TwiML's current XML content.
My attempts at a POST only gives the same output as the GET, while PUT gives 405 Method Not Allowed.
var URL = 'https://handler.twilio.com/twiml/EHXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX' + '?AccountSid=' + accountSidFlex
var twilioSig = crypto.createHmac('sha1', authTokenFlex).update(new Buffer(URL, 'utf-8')).digest('Base64')
var config = {
headers:{
'X-TWILIO-SIGNATURE': twilioSig,
'Content-Type': 'text/xml'
}
}
var xml =
'<?xml version="1.0" encoding="UTF-8"?>\
<Response><Play digits="www"/>\
<Say voice="alice">"We are currently experiencing X related issues". </Say>\
</Response>';
axios.post(
URL,xml,config
)
.catch(error => console.log(error))
.then(response => {
console.log(response.data)
})
Ideally I'd like to be able to change a specific TwiML using either HTTP methods or the Twilio-API, so that we can use it in out Studio Flow. We'd just keep it silent until we need to add something to it and revert back to silent once the issues have passed.
Any help would be appreciated!
You cannot currently change the contents of TwiML Bins, Studio Flows, or Twilio Functions programatically. I believe the key functionality you are looking for is a way to dynamically update the messaging (Say/Play Widget) in a Studio flow based on some condition.
One way is to use a Function Widget to retrieve a Twilio Sync document for the message, returning the message as JSON and have the Say/Play widget play that message. You can find the Twilio Sync REST API examples for Add, Modify, and Retrieve in the associated document.
You can retrieve the parsed response using variable syntax detailed here, https://www.twilio.com/docs/studio/widget-library#run-function.
I've been stalking around here and have gotten most of my answers as I make my way through this new tool, but I'm now stuck and need some direct advice.
The Gather function in Studio is not PCI compliant, so I have to shift my call to a Function and return the parsed data--I finally figured out how to do that one--however, I've found that I cannot call the web service housed within the single function and had to send the with event.Digits to another function to make the web service call to my token provider. This works, however it has led to a strange result: my token is read back as TTS and then the call is hung up. I have no TTS action in play. Below are my sets of code:
Initial function called from Studio:
const got = require('got');
exports.handler = function(context, event, callback) {
let twiml = new Twilio.twiml.VoiceResponse();
twiml.gather({
input: 'dtmf',
finishOnKey: '#',
timeout: 10,
action: 'paymenttest',
method: 'GET'
}).say('Enter CC');
console.log(twiml);
callback(null, twiml);
};
This successfully calls my function with the digits entered:
const got = require('got');
exports.handler = function(context, event, callback) {
let twiml = new Twilio.twiml.MessagingResponse();
const url ='my payment gateway' + event.Digits + '&EXPDATE=1220&CARDTYPE=VI';
got.get(url, {
headers: {
'content-Type': 'application/x-www-form-urlencoded'
}
}).then(function(response) {
// Check the response and ask your second question here
event.callback(null, response.body);
}).catch(function(error) {
// Boo, there was an error.
callback(error)
});
};
This successfully returns the token....but as mentioned prior...it's read back out to me instead of getting included in the data returned back to Studio.
Twilio developer evangelist here.
Right now Studio is not well setup for using TwiML from a Twilio Function and then continuing the flow. In your case when you return the token from your second Function Twilio is dealing with it as if you just returned text to a regular TwiML webhook. When this happens Twilio defaults to assuming you meant <Say> and reads out the text.
While the team work on redirecting calls back into Studio flows there is a workaround.
Instead of returning the token in the second Function, return some TwiML that includes a <Redirect> to your Studio flow's webhook URL with ?FlowEvent=audioComplete appended. You will also need to add a dummy Say/Play widget after your Function widget (it becomes the next part in the flow that can trigger an "audio complete" message, so exists to collect that and send on to the next widget).
The only thing that we haven't handled in thie workaround is sending the token to the flow. I don't believe we can do this via this redirect workaround, so instead I'd recommend storing the token in your own database or something like a Twilio Sync object. This way you can use it outside of Studio however you like. If you need it within the Studio flow then you can create one more Function that returns the token as JSON, and that will be stored within the flow variables then.
If you would prefer to use <Pay>, as this would be a lot easier, I also recommend requesting the pay connector you need.
I think philnash answer here got old, even when it still works.
Right now, you should have to call the first function using TwiML Redirect node.
In the second function, you should have to add a redirect to the webhook of the flow adding ?FlowEvent=return&foo=bar (where foo=bar should be changed by the info you really want to return).
I am trying to make a twilio call with hosting an xml file on Twilio TwiMl Bins and hosting an mp3 file in Assets:
I just want to say a simple sentence and then play a 5-10 second clip. Currently when I run my code:
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client
# Your Account Sid and Auth Token from twilio.com/console
account_sid = "stuff"
auth_token = "stuff"
client = Client(account_sid, auth_token)
call = client.calls.create(
url="https://handler.twilio.com/twiml/EHdff1ba57cc168191864794c6c44c1723",
from_="+1mytwilionumber",
to="+1mynumber"
)
print(call.sid)
I just get a call - the trial message and then silence and then the call is concluded. Any tips?
Never Mind! So this worked:
https://support.twilio.com/hc/en-us/articles/223132187--Not-Authorized-error-when-trying-to-view-TwiML-Bin-URL
But your twilio call will only run once after you "sign" the HTTP request with hmac authentication. The script is
const crypto = require('crypto')
, request = require('request')
const url = process.argv[2] + '?AccountSid=' + process.env.TWILIO_ACCOUNT_SID
const twilioSig = crypto.createHmac('sha1', process.env.TWILIO_AUTH_TOKEN).update(new Buffer(url, 'utf-8')).digest('Base64')
request({url: url, headers: { 'X-TWILIO-SIGNATURE': twilioSig }}, function(err, res, body) {
console.log(body)
})
Make sure to have node, npm, and request module installed.
npm install request --save
and you are good to go! Run this script right before your python calling script.
Just an fyi you can also make TWIML/robocalls on the fly by uploading your TWIML to a bin, just before you make the call. It just needs a public URL. This project that I found actually demonstrates the technique by uploading the TWIML/XML on the fly, getting the new URL (for the newly generated TWIML), and then makes the Twilio call. That restwords.com site is pretty handy for this purpose.