Browsing the archives for the Uncategorized category.


Catchy Tune

Uncategorized

This song by Landon Pigg is warm and wonderful:

No Comments

Click To Call Example For Twilio

Uncategorized

Twilio is a local company that has developed some very spiffy telephony technology that takes 99% of the pain out of integrating telephone calling capabilities into your application.

I’ve previously demoed some easy examples of getting your feet wet with the Twilio API. In this post I’ll take on a more challenging example: implementing a web-based click-to-call function.

What is click-to-call (aka C2C)? This is a feature that lets your customer flag you and say (for example) “Hey, I’m interested in talking to somebody about this product I’m looking at. Here’s my phone number; have a specialist call me as soon as one becomes available.”

This is a big win for the customer because they don’t have to wait on hold; it’s a big win for you, the application vendor, because you get a happier, less stressed out customer. Also, as we will see, you can use the magic of server-side programming to send important information to your agents, prepping them for the call. You can even route calls to the most knowledgeable agents based on which web page(s) your customer is viewing when they initiate the request!

Here’s a diagram that shows the sequence of events (click for larger version):

twilio-click-to-call-example

Click here to view my public Twilio Click-to-Call demo website to follow along as you read through this post.

The first thing to do is to build a page that your customer interacts with. We’ll call this first page in the process default.aspx and make it the default startup page for our web project. In our sample, we’ve dummied up this page to show fictional product details for the Jawbone Bluetooth headset. Featured prominently on the page is a big “Click to Call” button. When the customer clicks that button, we want to fire off the request to Twilio and get the ball moving.

There are two main parts to the code-behind: actually interacting with the Twilio API to make the outbound call to the customer, and setting up the handler that we want Twilio to use once the customer is connected.

Let’s take those in reverse order and talk about the handler first. This is a web page that serves up TwiML, a domain-specific XML dialect, that Twilio interprets and uses to run additional actions when a phone call is connected.

In our case, we’ll want the customer to hear something like “We’re connecting you now”, and then we’ll want to dial our customer service representative to connect them to the customer. TwiML provides two handy verbs, <Say> and <Dial>, that exactly serve our purpose.

A simplified version of our handler would return something like this as an XML response document:

<Response>
<Say>We’re connecting you now.</Say>
<Dial>206.555.1212</Dial>

For the purposes of our initial product page, default.aspx, we only need the URL to point Twilio to. So there is some code-behind that builds the URL, and passes along the product name (“Jawbone”), which we will take advantage of later.

1
2
3
4
5
6
7
8
9
10
11
12
13
protected virtual string GetBaseUrlPath()
{
string baseUrl = Request.Url.Scheme + "://" + Request.Url.Authority + Request.ApplicationPath.TrimEnd('/');
return baseUrl;
}
protected virtual string GetDialHandlerUri(string product)
{
string baseUrl = this.GetBaseUrlPath();
string handlerPath = "/c2c/user.aspx";
string url = baseUrl + handlerPath;
string qs = String.Format("?product={0}", product);
return url + qs;
}

There’s some plumbing code to make sure we’re getting the right URL base path, and then we construct the actual URL to our handler page – in this case, http://twilio.xidey.com/c2c/user.aspx?product=Jawbone.

Now let’s talk about initiating the outbound phone call to the customer. Twilio does this for us when we make a special request to their REST API. Specifically, we make a POST request to our “Calls” resource, with three parameters:

  1. The number we want to call
  2. The number we are calling from (for Caller ID purposes)
  3. The URL of our handler document, as described above

We’ll use the Twilio REST Helper Library that is provided for you on their website (need URL here Anthony). This library provides a ready-made Account class that you can use to make this POST request.

Here’s the code-behind in our product page to make the call:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// calls the customer at the phone number passed in as a parameter
protected void CallPhoneNumber(string phoneNumber)
{
string product = "Jawbone";  // product on current page
// construct our handler URL
string handler = this.GetDialHandlerUri(product);
string caller = "2064098427"; // use your caller ID here
// set up the POST parameters
Hashtable vars = new Hashtable();
vars.Add("Url", handler);
vars.Add("Caller", caller);
vars.Add("Called", phoneNumber);
// construct the URI to your “Calls” resource
string url = string.Format("{0}/Accounts/{1}/Calls", API_VERSION, ACCOUNT_SID);
string method = "POST";
Twilio.Vb.Api.Account a = new Account(ACCOUNT_SID, AUTH_TOKEN);
string result = a.Request(url, ref method, vars);
}

This is all pretty simple, right? Figure out what the customer is viewing; get their phone number; and make a special request to Twilio to call that customer. Our handler document will take care of the 2nd part – connecting the customer to a customer service representative so they can chat.

Let’s revisit our handler document, and extend our previous simple example. Twilio provides a neat facility that allows you to dial multiple phone numbers when trying to make a connection. For example, let’s say you had three Jawbone product experts manning the phones. You can instruct Twilio to call all three, and the first one to pick up “wins” and the other two connection attempts are cancelled. We can get customer service phone numbers from a simple DB lookup, as follows:

1
2
3
4
5
6
7
8
9
10
11
protected virtual IList<string> GetCustomerServicePhoneNumbers()
{
IList items = null;
string connString = ConfigurationManager.ConnectionStrings["twilio_demoConnectionString"].ConnectionString;
using (click_to_callDataContext dc = new click_to_callDataContext(connString))
{
items = (from csp in dc.customer_service_persons
select csp.phone_number).ToList();
}
return items;
}

Here we’re using LINQ-to-SQL to establish a connection to a SQL Server database and get a list of all the customer service representatives’ phone numbers.

Further, just like in our product page, we can specify an action that we want Twilio to take when we call the customer service representatives. In our case, we’ll probably want to give them detailed information about the customer, or the product they are viewing, or other essential details that may help the conversation. For now, it’s enough to know that we can specify an action URL for each <Dial> request.

Here’s the code to generate the URL for the handler document; it looks suspiciously like the code we used to generate the handler URL for the original POST to our Calls resource.

1
2
3
4
5
6
7
8
protected virtual string GetCsrUri(string product)
{
string baseUrl = this.GetBaseUrlPath();
string handlerPath = "/c2c/csr.aspx";
string url = baseUrl + handlerPath;
string qs = String.Format("?product={0}", product);
return url + qs;
}

Only the page name has changed: in this case, our handler will be csr.aspx instead of user.aspx.

Our extended handler document now looks more like this:

<Response>
<Say>Please wait; we’re connecting you now…</Say>
<Dial action="http://twilio.xidey.com/c2c/user.aspx?product=Jawbone" method="GET">206.555.1212</Dial>
<Dial action="http://twilio.xidey.com/c2c/user.aspx?product=Jawbone" method="GET">206.555.8989</Dial>
<!--—more DIAL entries here, if you want –-->
</Response>

* Note: I’m showing the URLs as unencoded for clarity. In real life you want to UrlEncode your URLs. *

That action attribute of the Dial element tells Twilio, “When you connect the customer service representative, use this URL as your handler document to tell you what to do next.” Note that the action handlers are the same in our sample – this isn’t necessary, however. You could have custom actions for each CSR in your database if you wanted.

How do we actually write out the handler document? We’ll use a simple .NET XMLDocument, as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
protected virtual XmlDocument CreateHandlerDocument(string product, IEnumerable phoneNumbers)
{
XmlDocument doc = new XmlDocument();
XmlNode documentElement = doc.AppendChild(doc.CreateElement("Response"));
XmlNode sayElement = documentElement.AppendChild(doc.CreateElement("Say"));
sayElement.AppendChild(doc.CreateTextNode("Please wait while we connect you to a customer service representative."));
foreach (string phoneNumber in phoneNumbers)
{
XmlNode dialElement = documentElement.AppendChild(doc.CreateElement("Dial"));
XmlNode actionAttribute = dialElement.Attributes.Append(doc.CreateAttribute("action"));
actionAttribute.Value = Server.UrlEncode(this.GetCsrUri(product));
XmlNode methodAttribute = dialElement.Attributes.Append(doc.CreateAttribute("method"));
methodAttribute.Value = "GET";
dialElement.AppendChild(doc.CreateTextNode(phoneNumber));
}
return doc;
}

To recap where we’re at: Our first page (default.aspx) told Twilio to call the customer, and when they answer, Twilio should use the contents of this handler page (user.aspx) to determine next actions. In this case, we’ll tell the user to wait, and then we’ll ask Twilio to dial our customer service representatives. When the CSR answers the phone, we’ll use a third page (csr.aspx) to tell Twilio what to do when the CSR answers.

Let’s get to the details of the CSR handler document. In our sample project, this is a TwiML document that informs the CSR what product the customer is looking at, so they can say something really smart and contextual like “Hi there! My name is John Smith. I’d be happy to answer any questions you may have about the Jawbone – and did you know that today only we’re offering 15% off?”

<Response>
<Say>You have a customer calling about the product Jawbone.</Say>
</Response>

The code to write out this handler document (csr.aspx) is essentially the same model as the code we used to write out the first handler document (user.aspx), and we’ll omit it here for clarity, but check out the attached source code for details.

Now we have an end-to-end solution. Recapping our original process diagram:

  1. Customer views a product page on your website.
  2. Customer clicks a “Call me!” button on your page, asking for a phone call.
  3. Your web application makes a POST request to Twilio, requesting an outbound call to the customer.
  4. When the customer answers, Twilio inspects your first handler document (user.aspx), says something to the customer, and then dials your CSRs.
  5. When the first CSR answers, Twilio inspects your second handler document (csr.aspx), and tells the CSR which product the customer is calling about.
  6. Twilio then connects the customer with the CSR, and they are off and running.

There are a few takeaways from this example that are worth highlighting:

  1. Learning TwiML and the Twilio REST API is easy. Really easy.
  2. You can “chain” requests to Twilio via a succession of handler documents.
  3. You can pass dynamic information in to your handler documents via request parameters (GET or POST). In our case, information about the product that the customer was looking at was carried along through two handler documents, to finally be repeated to the CSR when they picked up the phone.

However, not everything always goes as planned, so you have a few tools at your disposal, aside from the normal Visual Studio compilation and debugging environment:

First, there is the Twilio documentation website that provides lots of essential detail about TwiML, the REST API, and has sample code and helper libraries. On your Account page, Twilio provides a call log that lets you see what calls were made in response to your API requests. There’s also a Twilio debugger that lets you see any problems that Twilio encountered while making the outbound calls. Then there are the Twilio Get Satisfaction forums that are manned by Twilio developers and community representatives. There’s a Twilio help e-mail alias. Last but not least, you can find Twilio on Twitter at @twilio.

So, what’s stopping you from integrating telephony into your apps? Not much, not anymore. Jump into Twilio and get your feet wet!

9 Comments

Daily Digest for March 5th

Uncategorized
twitter (feed #2) 10:41pm Posted a tweet on Twitter.
Decided that I’m going to head into work today – feeling like it’s time. [#]

No Comments

Daily Digest for March 5th

Uncategorized
twitter (feed #2) 9:16pm Posted a tweet on Twitter.
@dacort That’s 98,000 tears that baby Jesus will shed today. [#]

No Comments

Daily Digest for March 5th

Uncategorized
twitter (feed #2) 9:10pm Posted a tweet on Twitter.
@daveschappell I’ll spill the beans about FTW in exchange for one item of Etsy swag. Hope you’re having fun in NYC! [#]

No Comments

Daily Digest for March 4th

Uncategorized
twitter (feed #2) 1:11pm Posted a tweet on Twitter.
Taking a break from recent depressing fiction choices (Saramago, Chekhov, Lethem) to reread The Art of the Start by Guy Kawasaki. [#]

No Comments

Daily Digest for March 4th

Uncategorized
twitter (feed #2) 12:54pm Posted a tweet on Twitter.
Making a game-time decision tomorrow morning on whether or not to go to work. Odds > 50%, I think. I can always leave if I need to. [#]

No Comments

Daily Digest for March 4th

Uncategorized
twitter (feed #2) 11:07am Posted a tweet on Twitter.
http://twitpic.com/1uqnx – My little Liverpool fans [#]

No Comments

Daily Digest for March 4th

Uncategorized
twitter (feed #2) 10:54am Posted a tweet on Twitter.
Off pain meds since 8 AM as a test. Middling results :/ [#]

No Comments

Daily Digest for March 4th

Uncategorized
twitter (feed #2) 4:49am Posted a tweet on Twitter.
Congratulations Danielle! RT @SMCSeattle: Seattle 2.0 @seattle20 has a new Editor-in-Chief: @DanielleMORRILL. Congrats! [#]

No Comments
« Older Posts
Newer Posts »