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

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.

Related

How do I make my for await loop do everything within its body before moving on to the next line of code in twilio serverless functions?

I have been working on this problem for a couple of days now, and feel like I'm extremely close to solving the issue. I need to cycle through an object and send a text message to each record in the object before moving on to the next line of code. The code to send works when isolated locally. But I'm having trouble getting it to work in Twilio Functions. All my code appears to work, but the text messages are not sent.
for await (const contact of allItems) {
client.messages
.create({
body: "Hey " + contact.name + "!" + " " + message,
messagingServiceSid: messaging_service,
to: contact.key
});
};
// End Send Message to Each Contact
I've attached the portion of code I believe I'm having issues with.
What I want to do, is for this piece of code to run completely before moving on to the next few lines and invoking a callback.
Any idea how I could do something like this?
Twilio developer evangelist here.
The issue here is that you are not awaiting the actual result of the asynchronous call. Locally, that doesn't matter, but within Twilio Functions once you call the callback function all asynchronous calls that have started are terminated.
To create a loop that makes asynchronous requests and waits for them all to complete you will want to use Promise.all in conjunction with map. In your example, it should look like this:
function SendMessages(allItems, message, client, messagingService) {
const apiRequests = allItems.map((contact) => {
let usersName = contact.name;
return client.messages.create({
body: `Hey ${usersName}! ${message}`,
messagingServiceSid: messagingService,
to: contact.key,
});
})
return Promise.all(apiRequests);
}
In this function we map over the list contacts returning the promise that is created when we try to send a message. The variable apiRequests becomes an array of promises that represent the requests to the API. We can then use this array of promises in Promise.all. Promise.all will only resolve once all the promises it is passed have resolved (or if a promise rejects).
I recommend you read my answer to your previous question as that brings up some further issues that you might have with this.

Forward the "Send and Wait for Reply" to a different phone number

We have a studio flow called "Google LA" that's triggered via Rest API. This flow has a Send and Wait for Reply so we hook this flow to "When a message comes in" so it will follow the rest of the flow when customer rates the service 1 to 5 stars. Now, within the Send and Wait for Reply, we want the customer's reply be forwarded to our main business phone number for tracking/recording purposes and so we can address their issues for rating us 1 to 3 stars. Here's our setup:
This is what we want:
Edited for philnash suggestion:
I created a function in Twilio with this code:
exports.handler = function(context, event, callback) {
const accountSid = context.ACCOUNT_SID;
const authToken = context.AUTH_TOKEN;
const client = require('twilio')(accountSid, authToken);
client.messages
.create({
body: widgets.negative1_3.inbound.Body,
from: '+12132779513',
to: '+12133885256'
})
.then(message => console.log(message.sid));
};
However, it did not send anything or the customer response. I renamed the negative1-3 widget to negative1_3 and published the studio flow.
I tried changing the body: 'Hello' to make sure that my function works, and yes. I received the 'Hello' sms to my verified caller ID phone number after it reaches the first_question -> check_response -> negative1_3.
Twilio developer evangelist here.
You don't necessarily need to forward the message here. You can make an API call to your own service with all the data you need from the message, so you can store and react to the information that way.
To do so you will want to add either an HTTP Request widget or a Run Function widget after the Send and Wait For Reply widget. Within those widgets, you can access the reply from the Send And Wait For Reply widget using liquid tags. You can see how to call on the variables in the docs for the Send and Wait For Reply widget. In the case of your widget, you should be able to get the body of the reply by referring to:
widgets.negative1-3.inbound.Body
(Although I am not sure how the name "negative1-3" will work, so you might try widgets["negative1-3"] instead, or rename the widget with underscores.)
Using the body of the inbound message, as well as the from number, you can send the data to your own application with the HTTP request widget or with a Run Function widget.
Edit
Your function can only access parameters that you set in the function widget config. You can then access those parameters in the event object. You also need to return once the message is sent successfully using the callback function. One other tip, you don't need to instantiate your own client, you can get it from the context. Like so:
exports.handler = function(context, event, callback) {
const client = context.getTwilioClient();
client.messages
.create({
body: event.Body,
from: '+12132779513',
to: '+12133885256'
})
.then(message => {
console.log(message.sid);
callback(null, "OK");
})
.catch(error => callback(error));
};

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 Studio: Forward SMS conversation log to email

I'm using SMS studio do have a quick chat bot conversation with inbound SMS messages, and would like to forward the conversation log to email after it's complete. I've written a function that uses the SendGrid API to forward SMSes to email. It works independently - ie, if I configure the phone number to run the function immediately as a text comes in, it will email that single SMS input.
However, I'd like to add the function to the end of of Twilio Studio flow, so that it emails the entire log of the conversation to me, once it's over. Once I append the function to the end of the studio flow, it stops working, and I get a failure notice.
Here's the code in the function:
const got = require('got');
exports.handler = function(context, event, callback)
{
const requestBody = {
personalizations: [{ to: [{ email: context.TO_EMAIL_ADDRESS }] }],
from: { email: context.FROM_EMAIL_ADDRESS },
subject: `New SMS message from: ${event.From}`,
content: [
{
type: 'text/plain',
value: event.Body
}
]
}
got.post('https://api.sendgrid.com/v3/mail/send', {
headers: {
Authorization: `Bearer ${context.SENDGRID_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify(requestBody)
})
.then(response => {
let twiml = new Twilio.twiml.MessagingResponse();
callback(null, twiml);
})
.catch(err => {
callback(err);
});
};`
Here's the error the debugger returns, if I make this function the last step in a Twilio studio flow:
Error - 81017
Error on Twilio Function response
There was an error in the response back from a Twilio Function attached to the Studio flow.
Possible Causes
Your Function timed out before responding
Your Function returned an error response
Possible Solutions
Your Function must contain a callback.
Make sure you place the Function callback callback(err, response) is placed correctly in your Function code.
If you are using a JavaScript promise, make sure the callback is called in both success and catch blocks.
Your Function responded with an error.
I'm having a hard time figuring out what the error is. Does anyone have any tips?
Thanks!
Jarod from Twilio. I actually wrote an app very similar to this. Code looks good to me. Often when people encounter an error of this nature it is coming from the SendGrid promise. Here are two tips:
You can actually log errors and view responses from the function if you leave the function open while testing it. The logs will be at the bottom. These usually have more information.
Check that you are using an outbound email address that has been whitelisted on your SendGrid account Whitelabel - Sendgrid
Make sure you have added your environment variables to your Functions config. Twilio Functions Configuration - Console
Hope that helps! If not feel free to email support#twilio.com with more questions.

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

Resources