Create interactive voice menu with Twilio and Azure

In the last post we looked at how we can trigger phone calls from events happening in SharePoint lists. We used [VerifiedRegistrations] list and when a new item was created in that list we used Twilio to make a call to a user and present them with some sort of voice response menu.

Today, we are going to take a look at how we can not only create that voice response menu, but also record the results back into the list into SharePoint using Twilio, so let’s get started.

I’m using the exactly same setup so check out the previous article if you haven't so you don't feel lost.

Azure

I’m going to start by opening my Azure Portal and my Azure function I created is last post. That’s the function that will be used in Twilio as a web hook and this is where Twilio will trigger a phone call from. In that function I talked about the URL handler highlighted on the side. That URL is the URL of the second Azure function I will be creating today. This is the actual function that will present users with a simple voice menu.

I'll create a new Function just as I did the last time with Twilio added as project reference. Here is the source code:

#r "System.Runtime"

using System.Net;
using System.Text;
using Twilio.TwiML;

public static async Task<HttpResponseMessage> Run(HttpRequestMessage req, TraceWriter log)
{
    log.Info("Function triggered");

    var data = await req.Content.ReadAsStringAsync();
    var formValues = data.Split('&')
        .Select(value => value.Split('='))
        .ToDictionary(pair => Uri.UnescapeDataString(pair[0]).Replace("+", " "), 
                      pair => Uri.UnescapeDataString(pair[1]).Replace("+", " "));

    var response = new VoiceResponse();

    string phNum = "";
    if (data.Contains("From"))
    {
        phNum = formValues["From"];
    } 

    string digits = "";
    if (data.Contains("Digits"))
    {
        digits = formValues["Digits"];
    } 

    if (!string.IsNullOrEmpty(digits))
        {
            switch (digits)
            {
                case "1":
                    response.Say("Thank you for confirming. See you there.", voice: "alice");
                    RecordAnswer("Verified:" +phNum);   
                    break;
                case "2":
                    response.Say("My bad", voice: "alice");
                    RecordAnswer("Declined:" +phNum);   
                    break;
                default:
                    response.Say("Sorry, try again!", voice: "alice").Pause();
                    RenderMainMenu(response);
                    break;
            }
        }
        else
        {
            RenderMainMenu(response);
        }

    var twiml = response.ToString();
    twiml = twiml.Replace("utf-16", "utf-8");

    return new HttpResponseMessage
    {
        Content = new StringContent(twiml, Encoding.UTF8, "application/xml")
    };
}

    private static void RecordAnswer(string answer)
    {
        using(var client = new HttpClient())
            {
                string bodyJson = "{'ItemId': 4," +
                "'ItemResponse': '"+answer+"'}";
                var content = new StringContent(bodyJson, Encoding.UTF8, "application/json");
                var result = client.PostAsync("[This URL will come from Microsoft Flow]", content).Result;
            }
    }

    private static void RenderMainMenu(VoiceResponse response)
    {
        response.Gather(
            new Gather(numDigits: 1)
            .Say("Do you confirm registration for SPS New York? To Confirm - Press 1", voice: "alice"));
    }

This function is super simple. We start with Async task which will fire and present the caller/recipient with a voice menu. From here we call [RenderMenu]. Let’s take a look at [RenderMainMenu]. It essentially uses Twilio’s method here to verbally say whatever we want to say and gather a certain number of digits.

Twilio will read out all the options and gather user input. Twilio can also accept voice input but in my example I'll make my callers just press dial-in numbers as response.

Once we gather their response we’re going back to this function and processing their response using [RecordAnswer] function. This is how we record values back to SharePoint. The magic here is that there is no code in Azure to do anything to save results back to SharePoint. It's all done with Flow.

Microsoft Flow

I’m going to switch back to my Flow and I’m going to create a new Flow. We've seen some basics of working with flow in my previous article so I'll just jump straight into it.

I'm going to find Request/Response template and add it to my flow. This template is super simple and it only asks for optional JSON Schema. Paste the following schema:

{
  "$schema": "http://json-schema.org/draft-04/schema#",
  "type": "object",
  "properties": {
    "ItemId": {
      "type": "integer"
    },
    "ItemResponse": {
      "type": "string"
    }
  },
  "required": [
    "ItemId",
    "ItemResponse"
  ]
}

This basically will be our remote method signature requiring ID of the list item we're updating and the response we want to record. The URL of the remote method will be created after we save the flow but we need to add an action before we do that.

The action step will be from a SharePoint template and I’m going to pick an action that says [update list item]. Parameters are pretty basic so I'll just show you the snapshot of the entire flow:

Lets go ahead create this Flow and obtain the URL of the remote method, and add it to our azure [RecordAnswer] function.

Let's run our flow, and see how this works in action.

Running and testing it

I’m going to switch back to my SharePoint list and create a new item in my list like I did before, click save, and I should be getting a phone call in a moment. Here it is, let's go ahead and refresh the list after I answered the automatic voice question ... it works! my phone number has been verified.

If things didn't work for you, you can troubleshoot the flow by reviewing the run history. If you click on details of the run, you will be able to see what happened. In our case, the request came in and there’s some parameters that came in here, our hardcoded item ID, our response, whatever the user has entered and of course that has been consumed by our update list item action and here is the parameters that were updated.

This is really how easy it is to configure your own interactive menu in Azure, gather some input from users and send it back to SharePoint and record all this information in SharePoint.

I hope you found it useful, and again if you have any specific scenarios you would like to see more, please leave a comment, like this post, and I hope to post more interesting stuff really soon!

Yaroslav Pentsarskyy has been a Microsoft MVP for 8 years and speaker at many local and worldwide tech events. Several of Yaroslav's books include: Rapid SharePoint 2013 development, Top 60 custom solutions built on SharePoint 2010, SharePoint 2010 branding in practice, and SharePoint and PowerShell Expert Cookbook.

@spentsarsky