With Twilio's suite of tools, it's easy to create a fully functioning voicemail box for Flex. This guide walks you through creating a special voicemail-specific TaskRouter queue with no agents, and a workflow to send tasks to this queue after they've waited for 30 seconds. Using Twilio functions, we're able to create a customizable voicemail message, append the recording file's URL to the task, and cancel the task so as not to skew Flex Insights reports with additional abandoned calls.
Here are the steps required for building a fully functioning Flex Voicemail system:
- Create a Voicemail Queue in TaskRouter
- Create a Voicemail Workflow in TaskRouter
- Create a Task Router Event Stream Function
- Create a Voicemail Function
- Create a Voicemail Recording Handler Function
Create a Voicemail Queue in TaskRouter
- Access the TaskRouter page in Console.
- Select the default Flex Task Assignment workspace, or the appropriate workspace if you have modified this.
- Click TaskQueues.
- Click the red Plus sign + icon to add a new Queue.
- Name your TaskQueue
Voicemail
(or something similarly identifiable), and then change the QUEUE EXPRESSION to1==2
to prevent workers from entering this queue. Click Save when finished.
Set up a Voicemail Workflow in TaskRouter
- Access the TaskRouter page in Console.
- Select the default Flex Task Assignment workspace, or the appropriate workspace if you have modified this.
- Click Workflows.
- Select the default Assign to Anyone workflow, or the appropriate workflow if you have modified this.
- Click Add a Filter.
- Name your Filter
Voicemail
(or something similarly identifiable), and then change the TIMEOUT to30 seconds
. Click Add a Step when finished. - Click the QUEUE value, and then select the
Voicemail
queue you created in the previous section. Press Save when finished.
Create a Task Router Event Stream Function
- Access the Twilio Functions page in Console.
- Click the red Plus sign + icon to add a new Function.
- Select the "Blank" template, and then click Create.
- Add a FUNCTION NAME, PATH, and CODE, and then click Save.
- FUNCTION NAME: Name your Function
trEventStream
(or something similarly identifiable). - PATH: Use the function name
trEventStream
(or something similarly identifiable). - CODE: Copy and paste the code below:
exports.handler = function(context, event, callback) { // get configured twilio client const client = context.getTwilioClient(); // setup an empty success response let response = new Twilio.Response(); response.setStatusCode(204); // switch on the event type switch(event.EventType) { case 'task-queue.entered': // ignore events that are not entering the Voicemail TaskQueue if (event.TaskQueueName !== 'Voicemail') { return callback(null, response); } let taskSid = event.TaskSid; let taskAttributes = JSON.parse(event.TaskAttributes); let callSid = taskAttributes.call_sid; let url = `https://${context.DOMAIN_NAME}/voicemail?taskSid=${taskSid}`; // redirect call to voicemail client.calls(callSid).update({ method: 'POST', url: encodeURI(url) }).then(() => { return callback(null, response) }).catch(err => { response.setStatusCode(500); return callback(err, response) }); break; default: callback(null, response); break; } };
- FUNCTION NAME: Name your Function
Now we need to tell TaskRouter to push its events to our function we just set up. First, you'll need to copy the full trEventStream function path. This can be found on the function page, and should be in the following format:
https://color-noun-1234.twil.io/trEventStream
- Access the TaskRouter page in Console.
- Click the default Flex Task Assignment workspace, or the appropriate workspace if you have modified this.
- Click Settings.
- Enter the Task Router Event Stream Function URL you just copied into the EVENT CALLBACK URL field, and then select ALL EVENTS. Click Save when finished.
Create a Voicemail Function
- Access the Twilio Functions page in Console.
- Click the red Plus sign + icon to add a new Function.
- Select the "Blank" template, and then click Create.
- Add a FUNCTION NAME, PATH, and CODE, and then click Save.
- FUNCTION NAME: Name your Function "
voicemail
" (or something similarly identifiable). - PATH: The path must be "
voicemail
", as the Event Stream Function calls for this. - CODE: Copy and paste the code below:
exports.handler = function(context, event, callback) { let taskSid = event.taskSid; let actionUrl = `https://${context.DOMAIN_NAME}/voicemail-complete?taskSid=${taskSid}`; let twiml = new Twilio.twiml.VoiceResponse(); twiml.say("Sorry, no one is available to take your call. Please leave a message at the beep. When you're done, press pound or just hang-up."); twiml.record({ action: encodeURI(actionUrl), finishOnKey: '#', playBeep: true, transcribe: true }); callback(null, twiml); };
- FUNCTION NAME: Name your Function "
Create a Voicemail Recording Handler Function
- Access the Twilio Functions page in Console.
- Click the red Plus sign + icon to add a new Function.
- Select the "Blank" template, and then click Create.
- Add a FUNCTION NAME, PATH, and CODE, and then click Save.
- FUNCTION NAME: Name your Function "
Voicemail complete
" (or something similarly identifiable). - PATH: Use the function name
voicemail-complete
(or something similarly identifiable). - CODE: Copy and paste the code below:
exports.handler = function(context, event, callback) { const client = context.getTwilioClient(), taskSid = event.taskSid, segmentLink = event.RecordingUrl;
let twiml = new Twilio.twiml.VoiceResponse(); twiml.say("Thank you for your message. Good bye."); callback(null, twiml); // retrieve the task this voicemail recording corresponds to client.taskrouter.workspaces(context.TR_WORKSPACE_SID) .tasks(taskSid) .fetch() .then(task => { // parse the task attributes - lets append some Insights specific attributes // this will let Insights know this task was a voicemail and not an abandoned call let taskAttributes = JSON.parse(task.attributes); taskAttributes.conversations = taskAttributes.conversations || {}; taskAttributes.conversations = Object.assign(taskAttributes.conversations, { segment_link: segmentLink, abandoned: "Follow-Up", abandoned_phase: "Voicemail" }); // update the task attributes with the Insights specific information client.taskrouter.workspaces(context.TR_WORKSPACE_SID) .tasks(taskSid) .update({ attributes: JSON.stringify(taskAttributes) }).then(() => { // end return callback(null, null); }); }) };
- FUNCTION NAME: Name your Function "
Legal Implications of Call Recording
If you choose to record calls, you need to comply with certain laws and regulations, including those regarding obtaining consent to record (such as California’s Invasion of Privacy Act and similar laws in other jurisdictions). Additional information on the legal implications of call recording can be found here.
Notice: Twilio recommends that you consult your legal counsel to make sure that you are complying with all applicable laws in connection with communications you record or store using Twilio.