Twilio logo What is Twilio?

Twilio is a service platform for integrated and embedded VoIP and SMS services...and more. I've mentioned Twilio on public lists a few times and have been asked how I'm using it. I've jotted down some notes about SMS and talking call integration in 4D apps below.

SMS Made Easy

I've always loved the idea of SMS integration for several reasons:

The hard part with SMS is on the developer side, particularly dealing with sorting out individual carrier gateways. (What's a carrier gateway? Exactly.) With Twilio, these problems all seem to go away. Instead of dealing with individual cell/mobile phone carriers individually, all of your work is with the Twilio API.

Getting back to Twilio and SMS, the API docs for sending SMS can be found here. Sending an SMS message is as easy as calling a routine with some parameters. In this case, the routine is called over HTTP and the method parameters are passed in as HTML form arguments. The stripped-down 4D code below demonstrates the basic steps.

C_TEXT($request_url)   // https:  //api.twilio.com/2010-04-01/Accounts/{AccountSid}/SMS/Messages.json
$request_url:="https:  //api.twilio.com/2010-04-01/Accounts/"+$account_sid
$request_url:=$request_url+"/SMS/Messages.json "   // You can ask for XML or JSON. For JSON, I needed to put a space on the end or else I got XML.

HTTP_NewRequest ($request_url)   // Using NTK here, but 4DIC or 4D's built-in Web request commands should also work.

C_TEXT($base64_text)
  // Account:AuthToken converted to Base64. The encoder in 4D doesn't always work so these are calculated and stored in the record.
HTTP_SetHTTPHeader ("Authorization";"Basic "+$base64_text)   // Base64 the Username:Password

  // Inputs sent up won't parse correctly on the Twilio side without this.
  // That's normal for this kind of request.
HTTP_SetHTTPHeader ("Content-Type";"application/x-www-form-urlencoded")
HTTP_SetHTTPHeader ("Accept-Type";"application/json")

  // Obviously the variables below require meaningful values...
C_TEXT($from_number)   // The number at Twilio the message comes from
C_TEXT($to_number)   // The recipient's number
C_TEXT($to_country)   // 2-char abbreviation used to look up country dialing code, like AU for Australia.
C_TEXT($to_country_dialing_code_text)   // Like 61 for Australia
C_TEXT($body_text)   // Keep this content XML safe and down to 160 characters
C_TEXT($account_sid)   // The Twilio account ID.

  // The + indicates that the number has the country code...a convention to observe in here.
$from_number:="+"+$from_number   // Should have country code already.
$to_number:="+"+$to_country_dialing_code_text+$to_number

HTTP_AddRequestParameter ("From";$from_number)
HTTP_AddRequestParameter ("To";$to_number)
HTTP_AddRequestParameter ("Body";$body_text)

  // Perform the HTTP request
C_LONGINT($error_l)
C_BLOB($response_blob)
C_TEXT($http_status_text)
C_TEXT($response_text)

$error_l:=HTTP_Post (->$response_blob;1)
$http_status_text:=HTTP_GetStatus
$response_text:=BLOB to text($response_blob;UTF8 text without length)

If (HTTP_GetStatus ="20@")   // 200 or 201
  // Twilio sends back a JSON or XML message receipt including a unique ID
  // you can pass into the API to test the status of a queued message.
  Message_SaveSentResponse ($from_number;$to_number;$body_text;False;$response_text)
Else
  // Error handling here.
End if

HTTP_ClearRequestData

The code shown above can be made longer or shorter, depending on your tastes and requirements. Regardless, all of the heavy lifting on carrier routing and message deliver is left to Twilio. Below is a picture of a sample screen for sending one-off SMS messages:

Send SMS Message Screen

Taking SMS distribution one step further, it's easy to modify the screen above to send the same SMS to a selection of contacts:

Send Batch SMS Screen

The screen shown above can be modified to support "mail merge" features if, for example, you want to customize the text to include the person's name, a specific meeting time, etc. (Keep in mind that a single SMS message is limited to 160 characters.)

Message Receipts & the API

The example code listed above ends with a call to a custom method that saves the Twilio response. HTTP is a request-response protocol and you always get a response, although the response may include nothing of any interest. With Twilio, responses are packed with data. Instead of making your system wait while an SMS message is dispatched, Twilio immediately queues your request and returns a receipt. The receipt contains a unique message ID that you can pass back into the API to get the message's status, cost details, call transcriptions, call recordings, and so on. Below is an example response with fake IDs (a few elements are highlighted for emphasis):

{
   "account_sid": "AC61482xxxxxxxxxe375f1ee67xxxx",
   "to": "+61400359110",
   "to_formatted": "+61400359110",
   "answered_by": null,
   "sid": "CAc31f08e90a0f4xxxxxxxd750ed75xxxxxx",
   "price_unit": "USD",
   "from_formatted": "(415) 877-1977",
   "group_sid": null,
   "end_time": null,
   "uri": "/2010-04-01/Accounts/AC61482ee2e83eace58485e375f1ee6776/Calls/CAc31f08exxxxxx42e4e1ad750edxxxxx.json",
   "forwarded_from": null,
   "date_updated": "Wed, 03 Jul 2013 06:53:28 +0000",
   "api_version": "2010-04-01",
   "phone_number_sid": "PN20deacadxxxxxxxxx961fa597ac0fa",
   "date_created": "Wed, 03 Jul 2013 06:53:28 +0000",
   "start_time": null,
   "status": "queued",
   "parent_call_sid": null,
   "direction": "outbound-api",
   "from": "+14158771977",
   "duration": null,
   "price": null,
   "annotation": null,
   "caller_name": null,
   "subresource_uris": {
      "notifications": "/2010-04-01/Accounts/AC61482xxxxxxxxxe375f1ee67xxxx/Calls/CAc31f08e90a0f4xxxxxxxd750ed75xxxxxx/Notifications.json",
      "recordings": "/2010-04-01/Accounts/AC61482xxxxxxxxxe375f1ee67xxxx/Calls/CAc31f08e90a0f4xxxxxxxd750ed75xxxxxx/Recordings.json"
   }
}

Notice that the status element is set to "queued" and that the price element is null. These are the sort of values you can call back to the Twilio API later for updated details, if necessary. Below is an illustration of a message receipt viewing screen with key receipt elements parsed out:

Message Receipt Screen

You only need to call JSON Release for:

JSON Parse Text/Blob/Document
JSON New Object/Array (only if it is the root object, so not for child objects)
JSON Retain (an advanced command for advanced uses, see the documentation)

JSON Get Object/Array do not need to be matched with a release. You are only obtaining a reference to an object that is a child of another object.

Talking Calls

SMS is a core Twilio feature but there's a lot more to it. You can do conference calls, record and distribute a custom voice message, embed dialing into an app or Web site, get call transcriptions and more. One feature I enjoy is the talking call Twimlet. You pass in a formatted block of XML using TwiML syntax describing what to say, how to say it, and who to say it to. Here's a sample message in plain text:

http://twimlets.com/echo?Twiml=<Response><Say voice="Alice" language="en-AU">Throw another shrimp on the barbee!</Say></Response>

Twilio calls the recipient and reads out the message in the voice and accent you've specified. I'm not sure that creepy talking robots make for a good user experience, but they make for a fun demo. Note that there are a few steps involved in encoding messages for use with this service not shown above. Below is a screenshot of the kind of UI needed to control talking messages:

Send Talking Call Screen

Practical Applications and Screenshots

Sending SMS and even talking messages out of 4D can be a great way to interact with users. As a developer, this is a feature with Maximum Visual Impact (MVI). You might slave away for weeks on a new feature but not get much notice but when robots call, people pay attention. (Keep in mind that it's better to get people's express consent before pinging their phones.) The screen shots below show a few ideas for working with Twilio in 4D.

Twilio Alternatives

Twilio is hardly the only option for integrating SMS and other call-related services into your application. This is bound to be a hot subject during the last half of 2013 since Microsoft is shutting down the Skype API. If you've used something else from 4D that you can recommend, please email me your thoughts and I can add a comment here. First up, a comment about clickatell from Wayne Stewart:

I've done something similar with SMS & clickatell It works really, really well and some of my users love it. Others refuse to use it on principle!

A Quick Note on Countries

Twilio requires SMS numbers to be in E.164 format, as note in their docs. The long and the short of this is that you need international country codes. Fortunately, this information is available on-line from a wide range of sources. I've found it handy to download the valid country names and their flags to simplify including the correct country code and to drive a pop-up menu:

Country Pop-up Menu

The popup is displayed using 4D's (pretty wonderful) Dynamic pop up menu command. The code below shows how the menu is populated based on attributes in the [Country] table.

  // Message_BuildCountryPickerMenu

C_TEXT($0;$menu_reference)
C_TEXT($1;$service_name)   // "SMS" or "Talking Call"

$service_name:=$1   // "SMS" or "Talking Call", no error returned if you pass a bad value.

$menu_reference:=""

Case of
  : ($service_name="SMS")
    QUERY([Country];[Country]Allow_Outbound_SMS=True)

  : ($service_name="Talking Call")
    QUERY([Country];[Country]Allow_Outbound_Talking_Calls=True)

Else
  // Record error here
End case

ARRAY TEXT($abbreviations_at;0)
ARRAY TEXT($names_at;0)
ARRAY TEXT($codes_at;0)

ORDER BY([Country];[Country]Name)
SELECTION TO ARRAY([Country]ISO_2_Letter_Abbreviation;$abbreviations_at;[Country]Name;$names_at;[Country]Dialing_Code;$codes_at)

$menu_reference:=Create menu

C_LONGINT($country_index)
For ($country_index;1;Size of array($codes_at))
  C_TEXT($menu_text)
  C_TEXT($flag_file_reference)

  $menu_text:=$names_at{$country_index}+" (+"+$codes_at{$country_index}+")"   // Australia (+61)
  $flag_file_reference:="File:Flags/"+$abbreviations_at{$country_index}+".png"   // Flags/AU.png

  APPEND MENU ITEM($menu_reference;$menu_text;*)   // The * tells 4D to treat meta-characters as regular text.
  SET MENU ITEM ICON($menu_reference;-1;$flag_file_reference)   // -1 for 'last added item'"
  SET MENU ITEM PARAMETER($menu_reference;-1;$abbreviations_at{$country_index})   // Returned by Dynamic pop up menu - works as a key.

End for

$0:=$menu_reference

The screenshot below shows a sample configuration screen for a country.

Country Edit Screen

Before you ask, here is a starter file of country codes and a ZIP archive with all of the little flags. If anyone completes the list with all of the various dialing details, please drop me a line. The min/max/formatting/etc. details for each country can be found on line. One of the more complete sites I located is www.wtng.info

Let me Know

I'd love to hear from other people integrating Twilio into their 4D apps. Feel free to send me questions and I'll reply, as my schedule allows. I'm also a coder for hire if you need something more extensive done.