Twilio Flex - Send Call To IVR After Reject - twilio

Using this plugin as a reference, I have Flex configured to be able to send a call to a Twilio Studio IVR, after an agent has accepted a call.
I'd like to be able to send an incoming call back to Studio when an agent rejects a call (i.e. as soon as they click the reject button). I'm trying to do this by adding a listener to the plugin's init method:
flex.Actions.addListener("afterRejectTask", async (payload, abortFunction) => {
let url: string = payload.task.attributes.transferToIvrUrl;
let menu: string = 'hangup';
await request(url, { CallSid: payload.sid, menu });
});
See here for the full context -- I'm pretty much using that exact code, with the addition of this listener.
I'm getting this error message, and the call is not transferred anywhere.
twilio-flex.unbundled-react.min.js:1574 Error on afterRejectTask: SyntaxError: Unexpected token < in JSON at position 0
Here's additional context from the console, if that's helpful:
Additional info:
The url being requested is a Twilio function, which successfully returns a response like this:
<Response>
<Enqueue workflowSid="WWcc1a650e4175089538d754a6c2e15a98">
<Task>{"transferToIvrUrl": "https://my-twilio-function-service.twil.io/studio-flex-transfer-helper"}</Task>
</Enqueue>
</Response>
Any advice would be appreciated.

Ah, ok, so looking at that plugin I found the example Twilio Function that works with it. From what I can tell, this function is intended to be used in two places, either in Studio to transfer the call to Flex (though I'm not sure it's needed for that) or from Flex to transfer the call back to Studio. The thing that triggers the different response is whether you pass an argument called transferToIVRMenu with the request.
Your current request is not passing that argument, you currently have:
await request(url, { CallSid: payload.sid, menu });
which looks similar to the original plugin's request:
await request(transferToIvrUrl, { CallSid: call_sid, transferToIVRMenu });
The difference is in the second property in the object. When you just pass the name of the variable in an object, it expands to call the property the same name as the variable and set the value to the value within the variable. So the original request expands out to:
await request(transferToIvrUrl, { CallSid: call_sid, transferToIVRMenu: transferToIVRMenu });
but your request only expands to:
await request(url, { CallSid: payload.sid, menu: menu });
So you are passing a parameter called menu not transferToIVRMenu and that triggers the Function on the back end to return TwiML and not to update the call.
To fix this, you can update your plugin code to send the transferToIVRMenu parameter, like:
flex.Actions.addListener("afterRejectTask", async (payload, abortFunction) => {
let url: string = payload.task.attributes.transferToIvrUrl;
let menu: string = 'hangup';
await request(url, { CallSid: payload.sid, transferToIVRMenu: menu });
});

Related

Online docs for getTwilioClient() as used in "Functions and Assets"

I have found a few examples of context.getTwilioClient(), but I have not been able to locate any online documentation. It's probably right under my nose, but it is eluding me. In particular, I'm trying to get information about workers in a Task Router queue (i.e., how many workers are in the different statuses and how many workers are available), but having the documentation will help with future projects.
I found some documentation saying that the context.getTwilioClient(), "enables you to invoke the getTwilioClient method on the context object for a fully-initialized Twilio REST API client." (https://support.twilio.com/hc/en-us/articles/115007737928-Getting-Started-with-Twilio-Functions)
It then shows this example, but there is no implementation of "messages" when I attempt to run this code:
var client = context.getTwilioClient();
client.messages.create({
to: '+12025551212',
from: '+12065551212',
body: "hello world!"})
Thanks.
The messages property should be on the client. getTwilioClient returns the Twilio helper library for Node.js.
I just created a Function with your code, and it worked as expected, meaning that I got the SMS, however, the function did time out because the callback was never invoked. To end the function invocation and respond to the caller, make sure you always invoke the callback function, like this:
exports.handler = function(context, event, callback) {
var client = context.getTwilioClient();
client.messages.create({
to: '+1xxxxxxxxxx',
from: '+1xxxxxxxxxxx',
body: "hello world!"})
.then((message) => {
console.log('SMS successfully sent');
console.log(message.sid);
// Make sure to only call `callback` once everything is finished, and to pass
// null as the first parameter to signal successful execution.
return callback(null, `Success! Message SID: ${message.sid}`);
})
.catch((error) => {
console.error(error);
return callback(error);
});
};
You can learn more about the callback function here.
If you still encounter this issue, can you tell use what Node Version you're using and which module dependencies and their versions?
You can find these details at Settings & More > Dependencies in your Twilio Functions Service.

Why is my slack app posting only ephemeral messages? [duplicate]

Using Serverless and NodeJS, I have a Slack command set up like:
/myCommand doStuff
When I type /myCommand doStuff, the Slack output does this:
/myCommand doStuff
The content of the actual response I want shown goes here.
What I want to do is only have this:
The content of the actual response I want shown goes here.
without the /myCommand doStuff getting echoed.
How do I prevent that from happening?
Update - adding some code
Here's the actual command:
module.exports = () => {
return new Promise(function(fulfill) {
fulfill({
response_type: 'in_channel',
text: 'some testing text
});
});
};
Here's the handler:
module.exports.handler = (event, context, callback) => {
var response = {
statusCode: 200,
body: JSON.stringify(myCommand()),
};
callback(null, response);
};
When you are replying with
"response_type": "in_channel"
the reply is visible to all users in a channel and it will always copy the command back into the channel. This can not be turned off.
When you are replying with
"response_type": "ephemeral"
it is only visible to the user and the command will not be copied back. That is also the default, so you must be using in_channel in your script.
See here for the official documentation on that topic.

Twilio PCI Compliant <Gather> in Function Widget with Studio

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).

Twilio Runtime <Say> and <Play> Verbs Ending Call

I am trying to write a simple function to play a recorded message and then say a dynamic message, but I'm running into some trouble... the function will play and say what I want it to, but then the call abruptly ends. Oddly, though, the flow log says that the call is still engaged... and when I go into the flow Steps, it tells me that the function event was a success and it transitioned to the next widget.
I tried testing the HelloVoice template function to see what would happen, and the same thing occurs. Does anyone have any ideas on how to make the call continue? Thanks!
My code:
exports.handler = function(context, event, callback) {
let twiml = new Twilio.twiml.VoiceResponse();
var play1 = event.play1; //recorded msg URL
var say1 = event.say1; //person-specific message
twiml.play(play1);
twiml.say(
{
voice: 'woman',
language: 'es',
},
say1);
callback(null, twiml);
For what its worth, there is this statement at the end in the troubleshooting section.
Studio User Guide
https://www.twilio.com/docs/studio/user-guide
Returning custom TwiML from an HTTP Request or Function widget isn't yet supported. It will be soon.
The reason your call ends is your TwiML ends

twilio javascript client set from number , also how I can get the call sid after connect?

twilio javascript client set from number , Also how I can get the call sid after connect?
I tried to set the from Number in the call options like the next lines before connect and still the same issue in the javascript
$(document).ready(function () {
Twilio.Device.setup(token);
var connection = null;
$("#call").click(function () {
var params = { "Phone": $('#Phone').val(), "from":$('#Phone').val() };
connection = Twilio.Device.connect(params);
return false;
});
});
-- and inside the server side code vbnet when I am generating the token I added the next code but this doesn't solve the from number issue
Dim options As New CallOptions()
options.Record = True
options.From = model.FromNumber
Dim cap = New TwilioCapability(_settings.AccountSID, _settings.AuthToken)
cap.AllowClientOutgoing(_settings.ClientCallApplicationSID, options)
dim token = cap.GenerateToken()
Twilio evangelist here.
The params collection that you pass into the connect function is just a dictionary of key/value pairs. Those key/values simply get passed as parameters to the Voice URL that Twilio requests when Client makes its connection to Twilio, and you can use those parameters to dynamically generate some TwiML markup. Twilio does not do anything with them.
For example, if this is a PHP application, in the Voice URL you could do something like:
<Response>
<Dial>$_REQUEST['From']</Dial>
</Response>
One note of caution, Twilio already adds a parameter called from (which in the case of Client will be the client identifier set when you made your capability token) to the parameters sent to the Voice URL, so you might want to choose a different key name for your dictionary entry. I normally use a name like target for the key that holds the number that I want to dial.
Hope that helps.
To get the call sid, you can get it in connect event.
Please note that I am using Twilio JS v1.9.7
device.on('connect', function (conn) {
log('Successfully established call!');
//Get the CallSid for this call
callUUID = conn.outboundConnectionId;
console.log('CallSid: ' + callUUID);
});

Resources