Skip to contentSkip to navigationSkip to topbar
On this page

How to call Twilio Functions from a Flex plugin


This is a guide on how to securely call a Twilio Function from a Flex Plugin. This tutorial builds off of the Plugin from the Plugin Development Quickstart.

Flex provides some common SDK endpoints that you can use, but it doesn't make every Twilio API available to you. Fortunately, you can use Twilio Functions to decide exactly which Twilio APIs you need, make requests to them, and return the results to Flex.

This tutorial requires that you have an existing Flex Plugin. You'll write a Twilio Function that gets the cumulative statistics of all workers in a workspace and passes that data to your Flex Plugin.

(warning)

Warning

Currently, Flex Plugins can only make application/x-www-form-urlencoded requests to Twilio Functions. Nested objects are not supported.


Creating a Twilio Function

creating-a-twilio-function page anchor

First, you'll need to write a Twilio Function. The Function below returns cumulative statistics from a TaskRouter Workspace using the NodeJS Helper Library(link takes you to an external page).

Head over to Twilio Functions Console(link takes you to an external page) page. You can create a new Service, or use an existing Service that you already have. Add a Function, and paste the following code into it:

1
exports.handler = function(context, event, callback) {
2
// Add the NodeJS Helper Library by calling context.getTwilioClient()
3
const client = context.getTwilioClient();
4
5
// Create a custom Twilio Response
6
// Set the CORS headers to allow Flex to make an HTTP request to the Twilio Function
7
const response = new Twilio.Response();
8
response.appendHeader('Access-Control-Allow-Origin', '*');
9
response.appendHeader('Access-Control-Allow-Methods', 'OPTIONS, POST, GET');
10
response.appendHeader('Access-Control-Allow-Headers', 'Content-Type');
11
12
// Use the NodeJS Helper Library to make an API call.
13
// Note how you are passing the workspace SID using a key from the event parameter.
14
client.taskrouter.v1
15
.workspaces(event.WorkspaceSid)
16
.workers()
17
.cumulativeStatistics()
18
.fetch()
19
.then(data => {
20
response.appendHeader('Content-Type', 'application/json');
21
response.setBody(data);
22
// Return a success response using the callback function.
23
callback(null, response);
24
})
25
.catch(err => {
26
response.appendHeader('Content-Type', 'plain/text');
27
response.setBody(err.message);
28
response.setStatusCode(500);
29
// If there's an error, send an error response
30
// Keep using the response object for CORS purposes
31
callback(null, response);
32
});
33
};
34

Name your Function something meaningful like Cumulative Report and give it the URI of /cumulative. Before saving, make sure the checkbox Check for valid Twilio signature is unchecked; we'll come back on how to secure your Function later on. Now save your Function and wait for it to deploy.

Cumulative function.

Configure and Test Your Function

configure-and-test-your-function page anchor

Visit the Functions Configuration Page(link takes you to an external page) and ensure that the Enable ACCOUNT_SID and AUTH_TOKEN option is checked. Enabling this checkbox allows context.getTwilioClient(); to generate a new Twilio client using your account credentials. Save the page.

Now, try testing your Function. Your domain will be a hyphenated string of random words and numbers and can be found at the top of the Function Editor. You can find your Workspace SID by visiting TaskRouter Workspaces(link takes you to an external page) page.

Visit the Function URL using the browser of your choice. Add the query parameter ?WorkspaceSid=WSxxx and the browser should make a GET request to your Function. For example, visiting

https://YOUR_DOMAIN.twil.io/cumulative?WorkspaceSid=WSxxx

should yield:

1
{
2
...
3
"activityDurations": [{
4
"avg": 900,
5
"min": 900,
6
"max": 900,
7
"friendly_name": "Available",
8
"sid": "WAxxx",
9
"total": 900
10
},
11
...
12
]
13
"reservationsCreated": 0,
14
"reservationsAccepted": 0,
15
"reservationsRejected": 0,
16
"reservationsTimedOut": 0,
17
"reservationsCanceled": 0,
18
"reservationsRescinded": 0
19
...
20
}

Call your Function from a Flex Plugin

call-your-function-from-a-flex-plugin page anchor

To get this data into Flex, you'll need to modify your Plugin code using the Plugin Builder(link takes you to an external page). In your text editor of choice, open the folder that contains your Plugin.

(information)

Info

Somewhere in your Plugin, you'll need to make a call to your Function. You can use the native fetch Web API(link takes you to an external page) to make a request to your function.

For our Plugin, we're going to change the GET request to a POST request. Even though we're ultimately going to retrieve data about our TaskRouter Workspace, the Plugin is invoking a Function, not retrieving the data directly. Given that we might want to send a lot of data at some point, using a POST request scales better, as well. Finally, POST request bodies are easier to work with than query parameters.

For a Plugin called YourPlugin, here's what YourPlugin.js might look like:

1
import { FlexPlugin } from 'flex-plugin';
2
import React from 'react';
3
4
const PLUGIN_NAME = 'YourPlugin';
5
6
export default class YourPlugin extends FlexPlugin {
7
constructor() {
8
super(PLUGIN_NAME);
9
}
10
11
/**
12
* This code is run when your plugin is being started
13
* Use this to modify any UI components or attach to the actions framework
14
*
15
* @param flex { typeof import('@twilio/flex-ui') }
16
* @param manager { import('@twilio/flex-ui').Manager }
17
*/
18
19
init(flex, manager) {
20
// Describe the body of your request
21
const body = { WorkspaceSid: 'WSxxx' };
22
23
// Set up the HTTP options for your request
24
const options = {
25
method: 'POST',
26
body: new URLSearchParams(body),
27
headers: {
28
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
29
}
30
};
31
32
// Make the network request using the Fetch API
33
fetch('https://YOUR_DOMAIN.twil.io/cumulative', options)
34
.then(resp => resp.json())
35
.then(data => console.log(data));
36
}
37
}
38

When you run your Plugin, you should see the API response logged to the browser console!


Securing your Twilio Function

securing-your-twilio-function page anchor

Your Function currently is publicly accessible, so anyone on the internet can invoke it! No need to fear, though: you can secure it by using the JSON Web Token(link takes you to an external page) (JWT) from your Flex instance and then validating the token inside your Function.

Update the fetch code to also include the JWT in the request body:

1
import { FlexPlugin } from 'flex-plugin';
2
import React from 'react';
3
4
const PLUGIN_NAME = 'YourPlugin';
5
6
export default class YourPlugin extends FlexPlugin {
7
constructor() {
8
super(PLUGIN_NAME);
9
}
10
11
/**
12
* This code is run when your plugin is being started
13
* Use this to modify any UI components or attach to the actions framework
14
*
15
* @param flex { typeof import('@twilio/flex-ui') }
16
* @param manager { import('@twilio/flex-ui').Manager }
17
*/
18
19
init(flex, manager) {
20
// Add the Token using the Flex manager
21
const body = {
22
WorkspaceSid: 'WSxxx',
23
Token: manager.store.getState().flex.session.ssoTokenPayload.token
24
};
25
26
const options = {
27
method: 'POST',
28
body: new URLSearchParams(body),
29
headers: {
30
'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8'
31
}
32
};
33
34
fetch('https://YOUR_DOMAIN.twil.io/cumulative', options)
35
.then(resp => resp.json())
36
.then(data => console.log(data));
37
}
38
}
39

Note the only thing changed here is the addition of the Token key to the body parameter.

Now, you can update your Function so that it can verify this token. Visit the Functions Configuration(link takes you to an external page) page, and scroll to the bottom of the page. Visit the twilio-flex-token-validator package(link takes you to an external page) page on the npm registry to find the current version of the package. Once you know the version, add twilio-flex-token-validator and its current version to your Dependencies. Save the page.

Return to your cumulative Function and import functionValidator from the twilio-flex-token-validator module. Then, wrap your Function with it:

1
const TokenValidator = require('twilio-flex-token-validator').functionValidator;
2
3
exports.handler = TokenValidator(function(context, event, callback) {
4
// Add the NodeJS Helper Library by calling context.getTwilioClient()
5
const client = context.getTwilioClient();
6
7
// Create a custom Twilio Response
8
// Set the CORS headers to allow Flex to make an HTTP request to the Twilio Function
9
const response = new Twilio.Response();
10
response.appendHeader('Access-Control-Allow-Origin', '*');
11
response.appendHeader('Access-Control-Allow-Methods', 'OPTIONS POST GET');
12
response.appendHeader('Access-Control-Allow-Headers', 'Content-Type');
13
14
// Use the NodeJS Helper Library to make an API call.
15
// Note how you are passing the workspace SID using a key from the event parameter.
16
client.taskrouter.v1
17
.workspaces(event.WorkspaceSid)
18
.workers()
19
.cumulativeStatistics()
20
.fetch()
21
.then(data => {
22
response.appendHeader('Content-Type', 'application/json');
23
response.setBody(data);
24
// Return a success response using the callback function.
25
callback(null, response);
26
})
27
.catch(err => {
28
response.appendHeader('Content-Type', 'plain/text');
29
response.setBody(err.message);
30
response.setStatusCode(500);
31
// If there's an error, send an error response
32
// Keep using the response object for CORS purposes
33
callback(null, response);
34
});
35
});

The TokenValidator reads the Token parameter and validates it. If the token is invalid, the validator will respond with a 403. If the token is valid, then your code will execute.

Congratulations, you now have a secure Function that you can invoke from your Flex Plugin!

Need some help?

Terms of service

Copyright © 2024 Twilio Inc.