How to test Twilio Lookup in your Rails App

As I’ve been sharing the idea behind Cardstock with teachers and school leaders, one of the common edge-cases that comes up is “what happens if I attempt to send a text message to a landline?”

Previously, the best answer I could give was guiding teachers to rely on individual message status updates (“Queued”, “Delivered”, “Failed”) to gauge the success rate of their parent communication.

Not a great answer.

Twilio is the company I use behind-the-scenes at Cardstock to provision phone numbers, connect calls, and deliver messages. Recently, Twilio released their new Lookup API, which allows my app to check whether a number is a landline or mobile number before messages get sent.

Validating the Number with the Phony and the Twilio Lookup Client

Rails provides multiple ways to trigger behavior upon saving an object. In this case, I opted to use a custom validation as opposed to a callback, since semantically it seemed appropriate to treat any rejections from Twilio as invalid.


Phony is a gem for Rails that takes all of the various permutations of possible user input (parentheses, dashes, numbersallsmashedtogether), checks their plausibility as a phone number and formats them into standard, international E.164 notation (“+15551234567”).

However, Phony’s plausibility check is more about number of digits than actual, real-world existence. Twilio actually checks to see if the number is out there waiting for us to text message it.

To do this, my model runs the carrier_exists_for_number method. The validation is conditional on number_changed?, which is a method that Rails creates via ActiveModel::Dirty for each attribute of the model.

Finally, it’s worth noting that Twilio::REST::RequestError is raised not just on connection errors. When a number doesn’t actually exist, Twilio helpfully returns a 404. This allows me to shoot relevant errors back to users when they’re entering new numbers into forms.

With this I can now only present valid mobile numbers for teachers to message, avoiding the frustrating scenario of sending messages that never reach their intended destination.

Testing Twilio Lookup without Spending Lots of Pennies

The one caveat to using Twilio Lookup is that determining carrier type and name requires a credit-card-backed account, and charges a penny per lookup. Pennies can add up — especially when you’re bootstrapping your company! — which is why I limit those checks to instances where the number has explicitly been changed.

Twilio does provide test credentials, but they are limited to buying phone numbers, initiating calls, and sending SMS messages.

Since my test suite builds new numbers and tears them down frequently, running tests for each new build of Cardstock incurs unnecessary costs.

As I was seeking a way to test this feature, I found a great example at Giant Robots for building a fake Twilio SMS client that I modified to match the Lookups Client API.



I use the minitest-stub-const gem to redirect Lookups Client calls in my test suite to my fake client. I also use the minitest-hooks gem, which is necessary because the stub_const method want to be wrapped around super, instead of a set-up, tear-down, before-after process.

With that, you’ll be able to run your test suite knowing that your Twilio Lookups aren’t costing any of your precious pennies.

Thanks to my old Starter League buddy Paul Gonzalez, whose post on Slack integrations prompted me to get off my rear and write about some code.

I’d love your feedback on the examples above: @lperiodbose.