Twilio Voicemail With Webscript

One very useful Twilio feature is the ability to record a phone message. Today, I will demonstrate just how easy it is to record a phone message and retrieve it by orchestrating Twilio actions with a couple of simple scripts hosted on Webscript.

Twilio's TwiML control language includes an instruction to record a message. The instruction specifies the webhook URL for handling the message after it is recorded. Of course, I'll use Webscript to handle that event.

To record a voicemail message, I will first create the script that will handle the Twilio event that is generated when Twilio answers the call. (This concept was covered in a previous post.) That script will deliver the TwiML that instructs Twilio to synthesize request to leave a message, record that message, and ultimately call another script to handle that message:

twiliodemo.webscript.io/voicemail

return
        [[<?xml version="1.0"?>
                <Response>
                        <Say>Please leave a short message at the tone.</Say>
                        <Record
                        action="https://twiliodemo.webscript.io/voicemail/receive"
                        timeout="10"
                        maxLength="60"/>
                </Response>]], {['Content-Type'] = 'text/xml'}

The script that handles the receipt of the message will simply send me an email using Webscript's built-in "alert" routine:

twiliodemo.webscript.io/voicemail/receive

local notice = string.format('Voicemail from %s: %s',
        request.form.From,
        request.form.RecordingUrl)

alert.email(notice)

Notice that the recording is stored by Twilio and the URL of that recording is delivered to the script as a parameter ("RecordingURL"). This script uses script alerts to send email to the script's owner.

(You can try this by calling 714-798-2663 and leaving a message.)

That's all for today. Today's demonstration showed that Twilio's services and a couple of simple scripts hosted on Webscript create a straightforward voicemail system. Soon, we'll use Webscript and Twilio to create a simple conference call.

Making a Call With Twilio and Webscript

A previous post demonstrated how how Twilio and Webscript work well together to receive SMS messages and voice calls. Today's post will demonstrate how to make an outgoing Twilio call with Webscript.

Making an outgoing call is a little bit more involved than receiving calls because of Twilio's webhook model. For a simple call, the process involves two steps: making an HTTP request from Webscript to Twilio to initiate the call, and then providing a webhook that Twilio will call to report all events that happen during that call. So, we'll be providing two scripts. The event that we will handle today is when the call is answered.

The demonstration will accept an incoming text and then initiate a voice call to the sender that replies with a synthesized "Hello, World!". The first script will accept the incoming text and initiate outgoing call with the appropriate Twilio credentials. The second script will respond to the events on that call, and, if answered, will <Say> "Hello, World!". The first script uses Webscript's Twilio library to make calling Twilio's REST API easier:

twiliodemo.webscript.io/receive-sms

local twilio = require 'twilio'

local ACCOUNTSID = '<twilio account SID>'
local AUTHTOKEN = '<twilio auth token>'

local scripturl = 'https://twiliodemo.webscript.io/say-helloworld'

twilio.call(ACCOUNTSID, AUTHTOKEN, '+18635786423', request.form.From, scripturl)

twiliodemo.webscript.io/say-helloworld

return
        [[<?xml version="1.0"?>
        <Response>
                <Say>Hello, World!</Say>
        </Response>]], {['Content-Type']='text/xml'}

The callback code above initiates the call from Twilio to the number of the phone that sent the SMS message. Part of placing that call is to specify the URL for the webhook that will handle that call's events. In this simplified version, that webhook—the second script above—just returns the TwiML to synthesize "Hello, World!".

To do more interesting things after voice calls are initiated, it's convenient to pass information from the initiating routine to the event webhook by encoding them into the webhook's URL as query parameters. This is a common Twilio pattern that enables stateless event handlers.

For this example, we will have the script that initiates the call pass back the original text message by including it as a query string parameter in the webhook URL that it specifies when initiating the call:

twiliodemo.webscript.io/receive-sms (full version)

local twilio = require 'twilio'

local ACCOUNTSID = '<twilio account SID>'
local AUTHTOKEN = '<twilio auth token>'

local message = request.form.Body

local scripturl = 'https://twiliodemo.webscript.io/echo-message?'
                .. http.qsencode { text = message }

twilio.call(ACCOUNTSID, AUTHTOKEN, '+18635786423', request.form.From, scripturl)

Now that the webhook URL has a query string that specifies what to say, it's a simple matter to have the webhook grab that query string, and generate TwiML to synthesize that message:

twiliodemo.webscript.io/echo-message

local twiml = string.format(
        [[<?xml version="1.0"?>
        <Response>
                <Say>%s</Say>
        </Response>]], request.query.text)

return twiml, {['Content-Type'] = 'text/xml'}

(You can try this by texting 863-578-6423.)

This demonstration showed that Twilio and Webscript work really well together to place voice calls that can do something interesting. In a future post, we'll use Webscript and Twilio to accept voicemail messages.

Simple Twilio Applications With Webscript

Wanting to write a simple Twilio app inspired us to create Webscript. We routinely marvel at how well Twilio and Webscript work together.

Today, I will demonstrate how to receive an SMS message and respond with an SMS message, and I will demonstrate how to receive a telephone call and respond with a synthesized voice message.

To start with, you will need a Twilio account. Fortunately, Twilio allows you to sign up for free. Once you sign up, you will get a phone number to use for your Twilio experiments.

Twilio has a very simple webhook-based model for handling an incoming SMS message or an incoming phone call. To handle the incoming event, Twilio will make an HTTP request to your web service. This, of course, is where Webscript comes in—it's trivial to handle these HTTP requests with a simple Lua script hosted on Webscript.

Of course, you must let Twilio know the URL for the webhook. To do this, you will need to click on "Configure your trial number" from the Dashboard. There, you can set the URLs for both voice calls and SMS messages. I've chosen https://twiliodemo.webscript.io/voice and https://twiliodemo.webscript.io/sms. You also get the choice of whether those HTTP calls will be POSTs or GETs. I chose POSTs.

To start, I will make a simple script for handling an incoming SMS message. In response to the incoming message, my script will echo the message back to the sender:

twiliodemo.webscript.io/sms

return request.form.Body

This script makes use of the Twilio convention that the return value to its SMS webhook call can be a simple string to send back to the sender. (request.form.Body contains the SMS message that Twilio received and forwarded to the webhook.)

(You can try this by texting 203-774-5286.)

Twilio and Webscript also make handling incoming voice calls quite simple. As a simple example, we can have Twilio and Webscript work together to answer a call and respond with a synthesized, "Greetings from Webscript!". Unfortunately, this isn't quite as simple as the SMS example, but it's not far off. Twilio has a command language (TwiML) which you use to control its operation. In this case, there's a little boilerplate around a simple <Say> command that will synthesize a voice from text:

twiliodemo.webscript.io/voice

return
        [[<?xml version="1.0"?>
        <Response>
                <Say>Greetings from Webscript!</Say>
        </Response>]], {['Content-Type']='text/xml'}

Note that the script returns two values: the TwiML string, and the appropriate Content-Type header so that this is interpreted as XML.

(You can try this by calling 203-774-5286.)

I hope you agree that it's easy to create SMS and telephone apps with just a little bit of Twilio knowledge and Webscript. In the future, we'll demonstrate some more Twilio+Webscript examples.

Superfeedr+Tumblr+Webscript

We love to see blog posts by people with examples of Webscript being used well. Last week, Julien Genestoux blogged about how he used Webscript to create Tumblr posts from a Superfeedr aggregation stream. The script simply acts as a Superfeedr webhook that calls Tumblr’s posting API with the appropriate credentials.

I think Jeff Lindsay summarized it well in a comment: “Great example of using lightweight glue code (thanks to Webscript) to integrate apps with webhooks. That's exactly the intended use! It's just taken this long for something like Webscript to come along...”

For the full details, including the code for the script, read the post on Julien's blog.

API Access to Webscript Request Logs

Earlier this week, we launched a beta of the Webscript API. As mentioned in that post, a few customers have asked to access their request logs via an API, so today we added that functionality.

Below is a simple curl example that fetches the logs for a script. The API returns the 20 most recent log entries in reverse chronological order. For the full API details, read the Webscript API documentation.

$ curl https://www.webscript.io/api/0.1/log/example/hello -u demo@example.com:b889a1c92c3a41758bcedc73b7355e49
[
 {
   "timestamp": "2012-12-05T16:42:27.656081+00:00",
   "request": {
     "url": "examples.webscript.io/hello",
     "headers": {
       "X-Forwarded-Port": "80",
       "X-Forwarded-For": "71.197.165.147",
       "Connection": "close",
       "Accept": "*/*",
       "User-Agent": "curl/7.21.4 (universal-apple-darwin11.0) libcurl/7.21.4 OpenSSL/0.9.8r zlib/1.2.5",
       "Host": "examples.webscript.io",
       "X-Forwarded-Proto": "http"
     },
     "method": "GET"
   },
   "messages": ["This is a log message."],
   "response": {
     "body": "Hello, World!",
     "status_code": 200,
     "headers": {
       "Content-Length": 13,
       "Content-Type": "text/plain",
       "Access-Control-Allow-Origin": "*",
       "Cache-Control": "no-store"
     }
   }
 },
 ...
]