July 29, 2015

“The Humpty Dance is your chance to do the hump

Do the Humpty Hump, come on and do the Humpty Hump

Do the Humpty Hump, just watch me do the Humpty Hump

Do ya know what I’m doing, doing the Humpty Hump

Do the Humpty Hump, do the Humpty Hump”

– Shock G aka Humpty Hump

I was told tech blog posts should start with rap lyrics, so there you go! I also wanted to announce that Twilio has closed a $130 million Series E round of funding, led by Fidelity and T Rowe Price, along with investments from Altimeter Capital Management and Arrowpoint Partners.

In addition, we’re privileged that Amazon.com and Salesforce were also significant participants in the round. We’ve had great relationships with Amazon and Salesforce, leaders in laaS and SaaS respectively, and now we have the opportunity to deepen the relationship between our companies.  I truly admire these companies and their leaders for what they’ve accomplished in changing the landscape of the tech industry for the better. I look forward to working more closely with them as we continue to build Twilio into a great company together.

Many people ask what changes with a new round of financing. Turns out, the new investors hated everything about our existing business and asked that we change it all in exchange for their investment. So no more developer products and no more communications APIs.

 

 

 

Just kidding, that’s not how it works.

Like the investors who’ve backed us from the beginning, including Mitch Kapor, Union Square Ventures, Bessemer Venture Partners, Redpoint Ventures, and DFJ — our new investors deeply grok the importance of developers and are excited by the business opportunity Twilio has built to serve developers  as our customers. We’re humbled by their support.

With this investment, we will increase our ability to give you the communications tools you need to build conversations anywhere, in the languages you’re familiar with, using technology you love. We’re investing heavily in the development of products you can use to create amazing customer experiences at global scale – such as the Twilio Real-time Communications Suite with Twilio Video and IP Messaging.

With over 700,000 developers on the Twilio platform today, we recognize the developer community’s investment in Twilio. The entire team here is constantly working to reciprocate that investment by providing the best SDKs, APIs, and developer tools you need to build the future of communications and serve your customers.
We can’t wait to see what you build!

Announcing New Investors and Our $130 Million Series E Round

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


July 28, 2015

There’s been a lot of buzz around the Meteor framework, and with their adoption of ES6 coming later this summer now is a better time than ever to try it out!

In this post, we are going to build a simplified GroupMe clone using Meteor, MongoDB, and Twilio. The app will serve as an SMS group messenger that will let us create groups of phone numbers and blast a text message to every member of that group. We will also expand its functionality to allow groups and individual numbers to be toggled on or off depending on who we want to receive a particular text.

If at any point you are receiving errors and feel lost, or you just want to run this application without building it, you can obtain the finished source code here.

Otherwise, prepare to explore the Meteor universe.

Building Your Space Ship

The first step of any space endeavor is to build a sturdy ship. We will start by installing Meteor. Open a terminal and run this command:

curl https://install.meteor.com/ | sh

To generate a new Meteor project, navigate to the directory where you keep your code and run this:

meteor create GroupMeteor

This will create a folder with three files inside of it. We will soon be modifying each of these files. But first, run your new app:

cd GroupMeteor
meteor

You’ll see the following output in your terminal:

=> Started proxy.
=> Started MongoDB.
=> Started your app.

=> App running at: http://localhost:3000/

Open a browser and navigate to http://localhost:3000/. You’ll see a basic web application like the one below. Congratulations! You’ve created your first Meteor application.

Next, we need to install some dependencies. Kill your Meteor server and run the following command:

meteor add http accounts-password accounts-ui grigio:babel msavin:mongol

  • http
     allows us to send HTTP requests to the Twilio API.
  • accounts-password
     and
    accounts-ui
     make it unbelievably easy to integrate user accounts and a login interface into our application.
  • grigio:babel
     allows us to write ES6. This package will not be necessary after the release of Meteor 1.2.
  • msavin:mongol
     is a helpful MongoDB tool to inspect our database from the browser.

Preparing For Launch

It’s time to suit up and jump into some code. We will start by getting our front-end work out of the way. Open GroupMeteor.html in your favorite text editor. This page will serve as our ship’s launchpad.

We’ll first add some code and then I’ll describe what it does. Replace everything inside the

<body>
 tags with the following:

<body>
  <div class="container">
    <header>
      {{> loginButtons}}
      {{#if currentUser}}
        <form class="new-text">
          <input type="text" name="message" placeholder="Enter the text to send..." />
        </form>

        <form class="new-group">
          <input type="text" name="group" placeholder="Enter a name to create a new group..." />
        </form>
      {{/if}}
    </header>
    <ul>
      {{#each groups}}
        {{> group}}
      {{/each}}
    </ul>
  </div>
</body>

One thing you’ll notice are the

{{
 and
}}
 tags. This is our first encounter with Spacebars, Meteor’s templating language. If you’ve ever worked with Handlebars, this concept will be familiar to you. Anything within a pair of double braces is part of a template. The templates will allow us to generate HTML based on the Javascript we will write in our GroupMeteor.js file.

  • {{> loginButtons}}
     will insert a login and user creation interface from the
    accounts-password
     and
    accounts-ui
     dependencies we added earlier.
  • The
    {{#if currentUser}}
     block will check to see if a user is logged in before displaying the elements inside of it.
  • Outside of our
    <header>
     we have a
    {{#each groups}}
     block. This unordered list will display all of the groups that a user adds to his/her collection. The
    {{> group}}
     tag tells the page that we will be inserting a specific template named group. We do not need this list inside of the 
    {{#if currentUser}}
     block because our database will be configured to only display the groups belonging to the user that is logged in.

Next, we need to create the group template that will define how each group in our

{{#each groups}}
 block is displayed. Add the following code to your GroupMeteor.html file after the
</body>
 tag:

<template name="group">
  <li>
    <button class="delete-group">&times;</button>
    <input type="checkbox" checked="{{checked}}" class="toggle-group" />
    <span class="text bold">{{name}}</span>
    <ul>
      {{#each this.numbers}}
        <li>
          <button class="delete-number">&times;</button>
          <input type="checkbox" checked="{{checked}}" class="toggle-number" />
          <span class="text">{{number}}</span>
        </li>
      {{/each}}
    </ul>

    <form class="new-number">
      <input type="text" name="number" placeholder="Enter a number to add to this group..." />
    </form>
  </li>
</template>

Let’s go over what we just added. Everything inside of our

<template>
 tags defines a Meteor template.

  • The
    {{name}}
     and
    {{number}}
     fields will be generated from items in our MongoDB collection, which we will be creating soon.
  • The
    {{#each this.numbers}}
     is included because each group can contain multiple numbers and we need to display all of them.

Where this data is coming from will make more sense after we write our JavaScript in the next section.

Fire up your application again by running

meteor
 in your terminal. In your browser you should see a barren webpage that looks as such:

This spaceship needs a paint job. We can do that with CSS. Paste the contents of this file into GroupMeteor.css and save it. Much of the styling is borrowed from Meteor’s getting started tutorial. If your application is still running, you’ll notice that the page was updated without needing to refresh. That’s because Meteor automatically pushes the changes you make to every client currently using the application. Your app should be looking much better now.

You probably encountered this warning about Meteor’s

autopublish
 package being on:

** You've set up some data subscriptions with Meteor.publish(), but
** you still have autopublish turned on. Because autopublish is still
** on, your Meteor.publish() calls won't have much effect. All data
** will still be sent to all clients.
**
** Turn off autopublish by removing the autopublish package:
**
**   $ meteor remove autopublish
**
** .. and make sure you have Meteor.publish() and Meteor.subscribe() calls
** for each collection that you want clients to see.

Kill your server and enter this command:

meteor remove autopublish

autopublish
 is a default package that will automatically publish all database data to the client. As you will see in the next section, this is undesirable.

Countdown…

Now that our front-end is all laid out, our rocket needs some boosters. Open up your GroupMeteor.js file. You’ll see two conditional blocks:

if (Meteor.isServer)
 and
if (Meteor.isClient)
. These blocks are important for determining where code will run. Code within the
.isClient
 block will only run in the client’s browser and code within the
.isServer
 block will only run on the server side. In production, you should still avoid entering any sensitive information (account credentials, API keys, etc.) in your
.isServer
 block, as this code can still be seen by the client, it’s just not executed. See the documentation for more info about this topic.

At the top of your file, outside of the client and server blocks, define your

Groups
 collection with the following line:

Groups = new Mongo.Collection("groups");

Collections are used to store persistent data. This MongoDB collection can be accessed by both the server and the client. By default, the entire database is present on the client. This would be an issue if we wanted to store privacy-sensitive data. Since we removed the

autopublish
 package, we must fix this by adhering to Meteor’s publish and subscribe paradigm.

Replace the contents of your

Meteor.isServer
 block with the following code:

if (Meteor.isServer) {
    // Specify which collections are sent to the client
    Meteor.publish("groups", function () {
        return Groups.find({
            owner: this.userId
        });
    });
}

Inside your

Meteor.isClient
 block, replace the contents with the following:

if (Meteor.isClient) {
    // Specify which collections from the server the client subscribes to
    Meteor.subscribe("groups");
}

Groups.find({owner: this.userId})
 is a MongoDB query that will return a list of groups that contain the current user’s userId. Every group we create will have a user associated with it and we only want a user to see the groups that they created. The
Meteor.publish()
 method registers a new Meteor publication named
groups
. When the client subscribes to the
groups
 publication using  
Meteor.subscribe()
, it will receive any changes made to the data in that publication in real time. (This convention can be very confusing to a beginner. Feel free to take a break from this tutorial and read more about it here.)

T-Minus 10 Seconds

Our ship is ready for takeoff. Let’s add a flight crew.

We need to define some helper functions and event handlers so that our front-end can interact with our backend. These functions will be defined in the

.isClient
 block, and they will call functions in the
.isServer
 block.

First let’s add a helper to our page’s body that will generate the HTML in the

{{#each groups}}
 block. Inside of your
.isClient
 block, add the following code.

Template.body.helpers({
    groups: function () {
        // Find all groups and list the newest groups first
        return Groups.find({}, {sort: {createdAt: -1}});
    }
});

This helper will query our

Groups
 collection and return a list with the newest groups first. Remember that since our
.publish()
 method is only publishing groups with an id that matches the current user, the user will only see the groups that they created.

Next we need event handlers. Below the helper we just added, insert the following:

Template.body.events({
    "submit .new-group": function (event) {
        // Grab group name from text field
        var newGroup = event.target.group.value;
        // Check that text field is not blank before adding group
        if (newGroup !== '') {
            Meteor.call("addGroup", newGroup);
        }
        // Clear the text field for next entry
        event.target.group.value = "";
        // Prevent default form submit
        return false;
    },
    "submit .new-number": function (event) {
        // Grab phone number from text field
        var newNumber = event.target.number.value;
        // Check that text field is not blank before adding number
        if (newNumber !== '') {
            Meteor.call("addNumber", this._id, newNumber);
        }
        // Clear the text field for next entry
        event.target.number.value = "";
        // Prevent default form submit
        return false;
    },
    "submit .new-text": function (event) {
        // Grab text message from text field
        var newMessage = event.target.message.value;
        // Check that message field is not blank before sending texts
        if (newMessage !== '') {
            Meteor.call("sendMessage", newMessage);
        }
        // Clear the text field
        event.target.message.value = "";
        alert('Your message is being sent!');
        // Prevent default form submit
        return false;
    }
});

Let’s review what these methods are doing.

  • "submit .new-group"
     is listening for a submit event on the form named new-group. It will grab the text from the
    group
     textbox and send it to the
    addGroup
     function, which we will be writing next.
  • "submit .new-number"
     is the same as above but calls the
    addNumber
     function.
  • "submit .new-text"
     is also the same as above but calls the
    sendMessage
     function.

In our

.isServer
 block, we need to add the methods that our new event listeners are calling. Use this code to do that:

Meteor.methods({
    addGroup: function (name) {
        Groups.insert({
            name: name,
            createdAt: new Date(),
            owner: Meteor.userId(),
            checked: false,
            numbers: []
        });
    },
    addNumber: function (groupId, number) {
        Groups.update(
            {_id: groupId},
            {$addToSet: {numbers: {"number": number, "checked": true }}}
        );
    }
});

  • addGroup
     will insert a new group into our
    Groups
     collection. By default, new groups will be empty and will not be selected.
  • addNumber
     will insert a new number into a group’s
    numbers
     array. By default, new numbers will be selected.

Let’s add the rest of our event handlers. These ones are contained in a Template.group object instead of Template.body because they are listening to events coming from within the group template we wrote in our HTML file. The following should also be placed in our

.isClient
 block:

Template.group.events({
    "click .toggle-group": function () {
        // Set the checked property to the opposite of its current value
        Meteor.call("toggleGroup", this._id, !this.checked);
    },
    "click .toggle-number": function () {
        // Get the number's group data
        var data = Template.instance().data;
        // Set the checked property to the opposite of its current value
        Meteor.call("toggleNumber", data._id, this.number, !this.checked);
    },
    "click .delete-group": function () {
        // Remove a group from our collection
        Meteor.call("deleteGroup", this._id);
    },
    "click .delete-number": function () {
        // Get the number's group data
        var group = Template.instance().data;
        // Remove a number from a particular group
        Meteor.call("deleteNumber", group._id, this.number);
    }
});

These four methods make up the toggling functionality that will allow a user to select/deselect individual groups or numbers when blasting out a text. We need to add their corresponding methods into the

.isServer
 block before we forget. Inside of the
Meteor.methods
 block add the following:

deleteGroup: function (groupId) {
    Groups.remove(
        {_id: groupId}
    );
},
deleteNumber: function (groupId, number) {
    Groups.update(
        {_id: groupId}, 
        { $pull: { numbers: {"number": number}}}
    );
},
toggleGroup: function (groupId, toggle) {
    Groups.update(
        {_id: groupId}, 
        { $set: { checked: toggle}}
    );
    // Find every number that differs from Group's "checked" boolean
    var numbers = 
        Groups.find(
            {numbers: { $elemMatch: {"checked": !toggle}}}
        );
    // Set all numbers to match Group's "checked" boolean
    numbers.forEach(function (setter) {
        for (var index in setter.numbers) {
            Groups.update(
                { _id: groupId, "numbers.number": setter.numbers[index].number }, 
                { $set: {"numbers.$.checked": toggle} }
            );
        }
    });
},
toggleNumber: function (groupId, number, toggle) {
    Groups.update(
        { _id: groupId, "numbers.number": number }, 
        { $set: {"numbers.$.checked": toggle} }
    );
},

What is all of this code doing? We are using MongoDB queries to manipulate our database, which will change what the user sees.

  • deleteGroup
     removes a group from our
    Groups
     collection.
  • deleteNumber
     removes a number from a particular group by updating its
    numbers
     array and removing the selected entry.
  • toggleGroup
     selects/deselects a group from our collection and selects/deselects every number in that group. This method is perhaps the most complex in the entire application, due to a MongoDB query that has not yet been added. Instead of a simple
    .update
     query, we are looping through every number in a group’s
    numbers
     array and making a new query to update its
    checked
     value to match that of its group.
  • toggleNumber
     selects/deselects an individual number in a particular group.

T-Minus 5 Seconds

We’ve made it so far, and intergalactic travel is within our reach. If you need a break, now is a good time to create a Twilio account if you don’t already have one. You’ll need to upgrade your account to harness the full power of this application, otherwise you’ll only be able to send texts to phone numbers you’ve verified with Twilio. You will also need to purchase a Twilio phone number.

The next section requires you to set your Twilio credentials as environment variables. Since Meteor is built on top of NodeJS,

process.env
 is used to access environment variables. To obtain your credentials, login to your Twilio account and click the Show API Credentials dropdown on your account dashboard. You’ll need to set
TWILIO_NUMBER
,
TWILIO_ACCOUNT_SID
, and
TWILIO_AUTH_TOKEN
 in your working environment. To do this, use the following commands in your terminal, replacing the variables with your actual credentials and a Twilio phone number you purchased:

export TWILIO_ACCOUNT_SID='AC1234...'
export TWILIO_AUTH_TOKEN='abc12...'
export TWILIO_NUMBER='+55555555555'

All we have left to do is make our call to the Twilio REST API. Place the following code at the bottom of your

Meteor.methods
 block.

sendMessage: function (outgoingMessage) {
    var phonebook = [];
    // Find all checked numbers across all groups
    var recipients = 
        Groups.find(
            {numbers: { $elemMatch: {"checked": true}}}
        );
    // Add each number from our query to our phonebook
    recipients.forEach(function (recipient) {
        for (var index in recipient.numbers) {
            phonebook.push(recipient.numbers[index].number);
        }
    });
    // Place all numbers in a Set so no number is texted more than once
    var uniquePhoneBook = new Set(phonebook);
    // Use Twilio REST API to text each number in the unique phonebook
    uniquePhoneBook.forEach(function (number) {
        HTTP.call(
            "POST",
            'https://api.twilio.com/2010-04-01/Accounts/' + 
            process.env.TWILIO_ACCOUNT_SID + '/SMS/Messages.json', {
                params: {
                    From: process.env.TWILIO_NUMBER,
                    To: number,
                    Body: outgoingMessage
                },
                // Set your credentials as environment variables 
                // so that they are not loaded on the client
                auth:
                    process.env.TWILIO_ACCOUNT_SID + ':' +
                    process.env.TWILIO_AUTH_TOKEN
            },
            // Print error or success to console
            function (error) {
                if (error) {
                    console.log(error);
                }
                else {
                    console.log('SMS sent successfully.');
                }
            }
        );
    });
}

Here we are making HTTP requests to the Twilio REST API.

  • At the top of the method we are grabbing every phone number that is currently selected (meaning
    checked
     is set to
    true
    ). These numbers are being placed into a
    Set
     object so that every number we text is unique.
  • We are iterating through our set and making a POST request for every number in the set.
  • Our account credentials are set as environment variables to avoid sending them to the client when a user loads the application.

One final optional step:
At the bottom of our

Meteor.isServer
 block, outside of the
.events
 blocks and
.helpers
 block, add the following code:

// Configure Accounts to require username instead of email
Accounts.ui.config({
    passwordSignupFields: "USERNAME_ONLY"
});

This will make creating an account easier by requiring only a username and not an email address.

Blast Off!

All of our code is now in place and we are ready for launch! Start up your server if it isn’t already running and create a new account. Once you log in, you can start creating new contact groups and adding phone numbers to them. When you are ready, type a message into the textbox at the top and hit enter. Every number you have selected will receive your message via SMS. Congratulations, your ship has made it to orbit!

If you want to deploy your application, kill your Meteor server and run the following command:

meteor deploy my_app_name.meteor.com

Once it finishes uploading, you can navigate to http://my_app_name.meteor.com and see a live instance of your application running.

Back to Earth

As we wrap up this tutorial and head back down to Earth, there are some important points to keep in mind:

  • Be careful when testing this application if you have several phone numbers saved across your groups. There is no rate-limiting in place so many texts can be sent very quickly. Avoid spamming your friends when using this app, as it is annoying, and can use a lot of Twilio credit very quickly.
  • In a production environment, files are typically separated into /client and /server directories instead of using
    .isClient
     and
    .isServer
     blocks. See this section of the Meteor documentation for more info on structuring Meteor applications.
  • There is no error handling to check for valid phone numbers or if groups exist before sending out texts. Feel free to add this in and send me a pull request!

Thanks for sticking with me through this journey into the great unknown. If you ran into any issues or have feedback on this tutorial, please don’t hesitate to leave a comment below or reach out to me via Twitter @br0dan. See you starside!

Building A Group Messaging App with Meteor, MongoDB and Twilio

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Share This: We are excited to introduce Plum Insight, a contact center VoC platform designed to improve the customer experience in the contact center, making […] …read more

The post The Next Generation of IVR Surveys Has Arrived appeared first on Plum Voice.

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


July 27, 2015

Earlier this morning, a vulnerability was disclosed for Android phones performing a remote code execution over MMS. Dubbed “Stagefright“, the vulnerability exploits SMS/MMS clients by sending a malformed media file to the user which is automatically downloaded by the default client.

If you’re using Google Hangouts as your default SMS client, here’s how to protect your device from Stagefright by disabling automatic downloading of media files sent via MMS:

protect android from stagefright exploit

Here’s how to protect your phone from the Stagefright bug if you’re using Google Messenger (the default SMS client for Android 5.0+):

messenger-disable-mms

The above screenshots were taken on a Nexus 5, but the steps are the same on any Android device using Hangouts or Messenger. To disable Auto Retrieve MMS in the default SMS client on the Samsung Galaxy S6, go to:

  • Messages app
  • More
  • Settings
  • More settings
  • Multimedia messages
  • Auto retrieve

The final Multimedia messages setting should look like this:

galaxy

More on the Stagefright Hack

From NPR’s Major Flaw In Android Phones Would Let Hackers In With Just A Text:

Here’s how the attack would work: The bad guy creates a short video, hides the malware inside it and texts it to your number. As soon as it’s received by the phone, Drake says, “it does its initial processing, which triggers the vulnerability…”

Once the attackers get in, Drake says, they’d be able do anything — copy data, delete it, take over your microphone and camera to monitor your every word and move. “It’s really up to their imagination what they do once they get in,” he says.

Disabling Auto Retrieve MMS will partially mitigate this vulnerability ahead of the official patch release. All MMS media files will require a click in order to be viewed, but disabling this feature will prevent an attack from automatically executing on your phone. Turning off this feature does not fix the exploit entirely. So long as the bug exists, your Android device remains vulnerable and can be hacked if a malformed media file is downloaded by clicking on it. This vulnerability will not be completely fixed until a patch is released for your device, but this intermediate step can help mitigate the threat in the meantime.

To learn more about the exploit, check out:

This guide is for the versions of Google Hangouts and Google Messenger that ship with the latest version of Android Lollipop (5.1.1). If the steps are different for your version or Android, or if your phone ships with a different default SMS client, please reach out to me at gb@twilio.com and we’ll update this post.

Thank you to Ricky, Rob, Christopher, Kyle, Sam and Jarod for their contributions to this post, to jimrandomh on HN for pointing us down this mitigation path, and to Greg Bulmash for providing the Galaxy instructions.

Update: added instructions for the Galaxy S6. 

How to Protect Your Android Phone From the Stagefright Bug

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Google claims to have cut errors produced by its Google Voice and Project Fi voicemail transcription service by 49 percent, helping the search giant put an end to its notoriously bad—and in some cases humorously unintelligible—voicemail-to-text conversions. Google pulled off this major accomplishment through a process it calls a “long short-term memory deep recurrent neural […]

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


July 24, 2015

tl;dr If you’d like to record a phone call, three-way call 888.909.1024 or +44 203 389 52 12 into the conversation and you’ll get a text with the recording when you hang up. 

About this time last year, Ryan Block’s “Comcast Call from Hell” made the social network rounds. It was an infuriating eight minute clip of him trying to cancel his service but getting stonewalled by the customer service rep repeatedly asking questions like, “Why is it that you aren’t wanting to have the number one Internet service available?”

Fortunately, Ryan recorded the phone call for, let’s say, “quality assurance purposes.” When it went viral, Comcast stepped in, apologized and made things right.

But what if he hadn’t had that recording?

Next time you find yourself in Ryan’s shoes, ask the rep to hold for a few seconds and three-way call 888.909.1024 (or+44 203 389 52 12 in the UK) into the conversation (and for the sake of staying on the right side of wiretapping laws, tell them that they’re being recorded). When you hang up, you’ll get a text with a link to the recording.

call-recording

This hack lets you record a call on any iPhone or Android device without installing an app, and it was built using only thirty lines of Ruby:

require 'sinatra'
require 'twilio-ruby'

post '/call' do
  response = Twilio::TwiML::Response.new do |r|
    r.Say "This call will be recorded."
    r.Record action: ENV['BASE_URL'] + "/after-record"
  end

  content_type "text/xml"
  response.text
end

def twilio_client
  Twilio::REST::Client.new ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN']
end

post '/after-record' do
  user_phone_number = params['From']
  twilio_phone_number = params['To']
  url = params['RecordingUrl']

  twilio_client.messages.create(
    to: user_phone_number,
    from: twilio_phone_number,
    body: "Here's your recording: #{url}"
  )

 200
end

In the rest of this post, we’ll break down this code in hopes that it can serve as the foundation for your own recording project.

Getting Started

Before we start coding, we’ve got some setup to do.

First, buy a voice and SMS enabled phone number from your Twilio Dashboard (if you’re in the United States, all numbers fit this criteria).

Q1Jd_LSN1ffh6m6sZ_jwZp55e7VgSHUYEyO0G-W5Y2JT-mrLEZynfNqw7jrkVGE3SBneWYyLmkRgbdS18jU3TlRuZAu-mecD64UnSS1uKnkfrZewn_KJPtmSHpVEd0emZPYbj7w

Second, download ngrok which we’ll use to give your local machine a publicly accessible URL (for more details, check out Kevin Whinnery’s brief ngrok tutorial).

Once downloaded, you’ll start ngrok from the command line by passing in the port your server uses. Since Sinatra’s default port is 4567, run it like this (and make sure you leave it running for the rest of this tutorial):

./ngrok 4567

UNaLTwnwbaCUgo_4Cgi8G2BjZcoFygTL2945S1XkDrgdb3kBajrQbVb1uOTiz3w6kACoNiM50W4lzOyixQ294aH4q7cPwhDsPYax-rVOXqZEgC7655VG2bGqBAA0VZV5sON2gk0

ngrok has created a tunnel through which Twilio can send HTTP requests to our local development machine. We’re going to do two things with that ngrok URL:

  • Set it as an environment variable called BASE_URL. There are about eighteen ways to set environment variables for Ruby. I’ll defer to Phil Nash’s excellent post on environment variables to explain those. Here we’ll do it the simplest way by running this in a shell:
    BASE_URL=http://YOURNGROKSUBDOMAIN.ngrok.com
  • Paste that URL into the Voice request field on your Twilio number page, then append
    /call
      to it, then save it (we will write the code to handle this request in the next section). Final product should look like this:

6442tg5tqbzCw_YCWdwaUH0Ce4M5Rqhzgst7v-YTESvsx5pXRrgjvtDu7-Y1VSGd2FDIU2A7tr9UkOj0vdnEB0-xi9wG327rkOj-GZLTSVbYqpmQGIUo9sppNKeJ3iYdSPdMII0Third, we need to set up our Ruby project. Create a new directory wherever you keep your code, then change into it:

mkdir call-recorder
cd call-recorder

If you use an environment manager like rvm or rbenv (and you should), set that up here:

echo "2.2.2" > .ruby-version
echo "call-recorder" > .ruby-gemset

Back out and back into your directory for those settings to take effect:

cd ../call-recorder

Create a new

Gemfile
 and add Sinatra and the Twilio Ruby gems:

source 'https://rubygems.org'
ruby '2.2.2'

gem 'sinatra'
gem 'twilio-ruby'

Back in the shell, install bundler, then your gems:

gem install bundler
bundle install

Create a file called

app.rb
  and require our two gems at the top of that file:

require 'sinatra'
require 'twilio-ruby'

With our plumbing in place, we can now move on to the code to power our call recording.

Record a Phone Call in Ruby

When someone calls our Twilio phone number, Twilio makes a POST request to that URL you just copied into your dashboard. Twilio expects a response in the form of Twilio-flavored XML called TwiML. We can use the Twilio Ruby gem to generate this XML instead of writing it out by hand.

Our TwiML does two things:

  • Greet the caller in a robot voice
  • Record the call

To generate the TwiML, add this code to the bottom of

app.rb
:

post '/call' do 
  response = Twilio::TwiML::Response.new do |r|
    r.Say 'This call will be recorded.'
    r.Record
  end

  content_type 'text/xml'
  response.text
end

Those last two lines set the response headers to return XML and then return the text of the generated response.

Back in your shell, start your server:

ruby app.rb

Then call your number and say something worthy of recording. Once you hang up, check out your Twilio recording logs and listen to your message.

That’s it! Eight lines to record a phone call. Pretty cool, huh?

Send an SMS in Ruby

Of course, that recording doesn’t do the caller much good if they have to sign into your Twilio dashboard to play to it. That’s okay though! Recordings are saved at publicly accessible, though highly obfuscated URLs, and it’s easy to text them a link to it.

To initiate an outbound SMS, we need the account credentials found on our account dashboard:

CpAcFy41Itc3IFJVxetW6SgvmA6t3rMy-0S-v9TlejKklitFe2z-XHBpmVp2_WR5feW_5U-Uzj8ABB7-vEniJlXu_sFBc0TD9jFRaY8NPKumBE92siY4JAeQYrqUFcwCW9aBgA\

Kill your Sinatra server, then set these values as environment variables:

export TWILIO_ACCOUNT_SID=YOURACCOUNTSID
export TWILIO_AUTH_TOKEN=YOURAUTHTOKEN

Back in

app.rb
, paste this code to create a method that will instantiate a Twilio REST client using your account credentials:

def twilio_client
  Twilio::REST::Client.new ENV['TWILIO_ACCOUNT_SID'], ENV['TWILIO_AUTH_TOKEN']
end

With this client we can connect to Twilio’s REST API and send an SMS. And when do we want to send an SMS? That’s right, when the recording is finished.

We can add a callback URL to our

<Record>
  verb that will be called when recording finishes.

In the

post '/call'
  method, and replace the
r.Record
  line with this:

r.Record action: ENV['BASE_URL'] + '/after-record'

Now when recording is finished, Twilio will make a POST request to the ‘/after-record’ route (which we will soon create). Included in the parameters of that request will be three pieces of information of particular interest to us:

  • params['From']
      – The phone number of the caller
  • params['To']
      – The Twilio number that was called
  • params['RecordingUrl']
      – the publicly accessible URL of the recording

These parameters match up nicely with the three pieces of information we need to send a text message:

  • What phone number gets the SMS? The number of the person who called.
  • What number sends the SMS? Our Twilio number.
  • What’s in the body of the message? The recording url.

At the end of

app.rb
 , paste this code to create the
/after-call
  handler:

post '/after-record' do
  user_phone_number = params['From']
  twilio_phone_number = params['To']
  url = params['RecordingUrl']

  twilio_client.messages.create(
    to: user_phone_number,
    from: twilio_phone_number,
    body: "Here's your recording: #{url}"
  )
 
  200
end

As for the

200
  return value at the end — that’s to be a good web citizen by responding to Twilio’s HTTP request with a success code.

Restart your Sinatra server, give your phone number a call, say something funny before hanging up, then wait for the text message to roll in.

Next Steps

Thirty lines of code and you’ve got a service to protect consumers from the pains of bad customer service. But that’s just the beginning. Building on this foundation, you could:

  • Build a web interface where folks can share their good and bad customer experiences with the rest of the world. They could sign-in using their phone number as a user ID and a PIN sent to them via SMS (it’s super simple to do this using Authy).
  • Create a service for podcasters and journalists to interview folks. You could even turn on the transcription tag to help create show notes. That would look like:
    r.Record action: ENV['BASE_URL'] + "/after-record", transcribe: true
  • Use the <Gather> verb to build a phone tree (or “IVR” in telecom speak) with custom voicemails for everyone in your company.

Whatever you build, I’d love to see it. Let me know at @greggyb or gb@twilio.com.

Record Bad Customer Service Calls in 30 Lines of Ruby

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


July 21, 2015

Registering for college classes is a lot like shopping on Black Friday here in America. You’ve probably seen the videos of people stampeding through the doors of a superstore at 4am to get their hands on an Xbox. That’s what class registration is like in a virtual sense.

When thousands of students all hit the registration page at once, it can crash. The downtime couldn’t come at a worse time. One class can mean the difference between graduating on time and not graduating on time. When Joseph Tinsley’s niece texted him at midnight, saying her school’s registration page was down, he sprang into action. Using Twilio SMS, he built his niece an alert system so she could register for classes the second the site went back up.

“The problem is everyone is gunning to take Anatomy with this teacher. Registering for classes at this school is a first come first service type of process, hence the reason why we had so much panic,”Joseph says.

Joseph is an SEO specialist who has used Twilio a number of times before. When his niece was in need, he set up a cron job to ping the school’s website  every 5 minutes and text him when it was back up. “A lot can happen within five minutes,” he says.

The site had been down for hours and hours. While Joseph was getting gas, he got a text from Twilio, notifying him that the site was live. He immediately texted his niece who jumped to the computer and nabbed the class that so many students were vying for.

“If it wasn’t for Twilio and the ability it offers to quickly include SMS technology, we may have not been able to take advantage of that small window of opportunity.”

You can check out the conversation between Joseph and his niece below, and the code he used to build the Twilio app.

Joseph’s Set Up

JosephSetUp

Joseph’s Code

 0){
            $this->sendSMS('334-xxx-xxxx','334xxxxxxx', 'Check the http://suscc.edu/ registration site');
        }
    }
    

    private function sendSMS($smsFromNumber,$smsNumber, $msgStr){
        
        if( !empty($smsNumber) && !empty($msgStr) ){
            
            $smsNumber = $this->format_phone($smsNumber);

            /* Send a new outgoinging SMS by POST'ing to the SMS resource */
            $this->twilioClient = new TwilioRestClient($this->AccountSid, $this->AuthToken);
            $this->twilioClient->request("/$this->ApiVersion/Accounts/$this->AccountSid/SMS/Messages",
            "POST", array(
            "To" => $smsNumber,
            "From" => $smsFromNumber,
            "Body" => "$msgStr"
            ));

        }
    }

    private function format_phone($phone){
        $phone = preg_replace("/[^0-9]/", "", $phone);

        if(strlen($phone) == 7)
            return preg_replace("/([0-9]{3})([0-9]{4})/", "$1-$2", $phone);
        elseif(strlen($phone) == 10)
            return preg_replace("/([0-9]{3})([0-9]{3})([0-9]{4})/", "$1-$2-$3", $phone);
        else
        return $phone;
    } 
     
}//END CLASS

$url = 'http://domain.com/page.php';

$Run = new SiteLive();
$Run->curlIt($url);

Joseph Tinsley Solves A Class Registration Nightmare For His Niece With Twilio SMS

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


For the longest time, I held off getting a smartphone for fear of the technology taking over my life. I grasped onto my “dumb” phone as long as I could, until finally it became almost unusable. This weekend, I walked into my local AT&T Wireless store and sprang for a Microsoft Nokia Lumia smartphone. It’s Windows-based, […]

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


July 20, 2015

rockconnerycage

The Other Rock

Apartment List‘s Renters Operations Center (ROC), headquartered in San Francisco, is lovingly referred to as The Rock by employees.

It’s not the type of rock where you’ll find Nicolas Cage and Sean Connery saving the world from a nuclear weapon crisis. But, you will find Apartment List’s customer service staff doing equally heroic work: finding people apartments in San Francisco (and all over the world).

Humans Making It Really Easy To Talk To Other Humans

Real estate moves fast, so Apartment List has to move faster. They include Twilio powered phone numbers on all of the properties they list on their website so an interested renter can contact a real human at Apartment List immediately.

“If a human wants to get in contact with a human, let’s make that happen,” says Ian Medlock, Product Manager at Apartment List.

Of course, to make that happen, you need the right communications tools. To power call tracking, queueing, recording, and analytics for over half a million calls a year, Apartment List uses Twilio.

But, it wasn’t always that way.

If A Feature Breaks And A Contractor Isn’t There To Fix it, Is It Really Broken?(…Yes, For Sure It Is Most Definitely Broken)

Before switching to Twilio, Apartment List used Salesforce and InContact for everything call related. This solution was built by a team of contractors using proprietary code that Apartment List’s engineers couldn’t change themselves. If there’s anything that engineers need, it’s good documentation. If there’s anything that engineers don’t need, it’s clunky, proprietary code.

After fussing and fighting for feature changes, Apartment List decided to look for a platform that could allow the team at The Rock to make their own decisions about the technology they use to make their customers happy.

“When you have a solution with multiple vendors, responsibility becomes fragmented in terms of who is fixing what and it’s a lot of work, time and money to fix things. It’s nice to have a solution that our engineering is comfortable with and that gives us the flexibility to grow,” says Medlock.

Scaling Communications With Great Code

Now, ApartmentList is making an average of 676,000 calls a year and is fast at work on new features. With documentation that’s actually palatable to their engineers, and a scalable communication platform to work with, they’re full steam ahead.

“Our Twilio solution is less than half the cost of our previous solution,” says Medlock. “The biggest benefit we felt was that A, we could fix a problem in short order and B, we know that as our business grows, we can leverage Twilio’s feature set to allow us to grow.”

Behind Great Customer Service, There’s Great Code : How Apartment List Uses Twilio

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


July 16, 2015

I hate voicemail. That’s why I text my friends. Sorry, I should elaborate. I mean I text a Twilio number that interfaces with Arduino to translate my text message into morse code which is then tapped out by an old telegraph.

Is my means of communication uncommon? Yes.
Is it pretty rad? Yes.
Am I abusing sarcastic rhetorical questions? Most definitely.

Noam Zomerfeld, a design student at California College of the Arts, wanted to unpack how basic communication systems work. Instead of diving into communications apps and stacks, he went old school. He decided to build a rudimentary telegraph with just a piece of wood, batteries and wire. From there, brought the old school hardware (telegraphs still count as hardware) to the new school of APIs and Arduino interfaces.

Here’s how Noam’s telegraph works. Any passerby can text Noam’s Twilio number. The text string is parsed by an Arduino in to morse code and tapped out by the telegraph.

Take a look at Noam’s creation below and read more about it on Temboo here.

Here’s What An Arduino and Twilio Powered Telegraph Looks Like

Bookmark this post:
Ma.gnolia DiggIt! Del.icio.us Blinklist Yahoo Furl Technorati Simpy Spurl Reddit Google


Last updated: July 29, 2015 01:01 PM All times are UTC.
Powered by: Planet

Speech Connection and Logos are Trademark of Nu Echo Inc. Copyright 2006-2008.