---
title: "Voice based phone verification using twilio"
description:
  "In this blog we discuss how to do voice based phone verification using
  Twilio."
canonical_url: "https://www.bigbinary.com/blog/voice-based-phone-verification-using-twilio"
markdown_url: "https://www.bigbinary.com/blog/voice-based-phone-verification-using-twilio.md"
---

# Voice based phone verification using twilio

In this blog we discuss how to do voice based phone verification using Twilio.

- Author: Santosh Wadghule
- Published: March 18, 2015
- Categories: Rails

In my previous [blog post](phone-verification-using-twilio), I talked about how
to do phone verification using **SMS** and now in this blog post I'm going to
talk about how to do **voice** based phone verification using
[Twilio](https://github.com/twilio/twilio-ruby).

## Requirement

Let's change the requirement a bit this time.

- After the user signs up, send an SMS verification. If SMS verification goes
  well then use that phone number for future use.
- But if the user's phone number doesn't support the SMS feature, then call on
  user's phone number for the verification.
- In the call, ask the user to press **1** from keypad to complete the
  verification. If that user presses the **1** key, then mark the phone number
  as verified.

## Step 1: Make a call for phone verification

We already handled SMS verification, so let's add call related changes in
`PhoneVerificationService` class.

```ruby
class PhoneVerificationService
  attr_reader :user, :verification_through

  VERIFICATION_THROUGH_SMS  = :sms
  VERIFICATION_THROUGH_CALL = :call

  def initialize options
    @user                 = User.find(options[:user_id])
    @verification_through = options[:verification_through] || VERIFICATION_THROUGH_SMS
  end

  def process
    if verification_through == VERIFICATION_THROUGH_SMS
      perform_sms_verification
    else
      make_call
    end
  end

  private

  def from
    #phone number given by twilio
    Settings.twilio_number_for_app
  end

  def to
    "+1#{user.phone_number}"
  end

  def body
    "Please reply with this code '#{user.phone_verification_code}'" <<
    "to verify your phone number"
  end

  def send_sms
    Rails.logger.info "SMS: From: #{from} To: #{to} Body: \"#{body}\""

    twilio_client.account.messages.create ( from: from, to: to, body: body)
  end

  def make_call
    Rails.logger.info "Call: From: #{from} To: #{to}"

    twilio_client.account.calls.create( from: from, to: to, url: callback_url)
  end

  def perform_sms_verification
    begin
      send_sms
    rescue Twilio::REST::RequestError => e
      return make_call if e.message.include?('is not a mobile number')
      raise e.message
    end
  end

  def callback_url
    Rails.application.routes.url_helpers
      .phone_verifications_voice_url(host: Settings.app_host,
                                     verification_code: user.phone_verification_code)
  end

  def twilio_client
    @twilio ||= Twilio::REST::Client.new(Settings.twilio_account_sid,
                                         Settings.twilio_auth_token)
  end
end
```

In `PhoneVerificationService` class we have added some major changes:

1. We have defined one more attribute reader `verification_through` and in
   `initialize` method we have set it.
2. We have created two new constants `VERIFICATION_THROUGH_SMS` &
   `VERIFICATION_THROUGH_CALL`.
3. We have changed `process` method and now we check which verification process
   should be taken place based on `verification_through` attribute.
4. We also have added new methods `perform_sms_verification`, `make_call` and
   `callback_url`.

Let's go through these newly added methods.

## perform_sms_verification:

In this method, first we try to send an SMS verification. If SMS verification
fails with error message like **_'is not a mobile number'_** then in the rescue
block, we make a phone verification call or we raise the error.

## make_call:

In this method, we create an actual phone call and pass the all required info to
twilio client object.

## callback_url:

In this method, we set the callback_url which is required for Twilio for making
a call. When we call the user for verification, our app needs to behave like a
human and should ask to the user to press 1 to complete the verification (i.e.
In the form of [TwiML](http://www.twilio.com/docs/api/twiml/)). This
`callback_url` needs be to set in our app.

## Step 2: Add voice action in phone verification controller

For `callback_url`, add route for `voice` action in `config/routes.rb`

```plaintext
post 'phone_verifications/voice' => 'phone_verifications#voice'
```

Add `voice` action and required code for it in `PhoneVerificationsController`.

```ruby
class PhoneVerificationsController < ApplicationController
  skip_before_filter :verify_authenticity_token
  after_filter :set_header

  HUMAN_VOICE = 'alice'

  def voice
    verification_code = params[:verification_code]

    response = Twilio::TwiML::Response.new do |r|
      r.Gather numDigits: '1',
               action: "/phone_verifications/verify_from_voice?verification_code=#{verification_code}",
               method: 'post' do |g|

        g.Say 'Press 1 to verify your phone number.', voice: HUMAN_VOICE
      end
    end

    render_twiml response
  end

  def verify_from_message
    user = get_user_for_phone_verification
    user.mark_phone_as_verified! if user

    render nothing: true
  end

  private

  def get_user_for_phone_verification
    phone_verification_code = params['Body'].try(:strip)
    phone_number            = params['From'].gsub('+1', '')

    condition = { phone_verification_code: phone_verification_code,
                  phone_number: phone_number }

    User.unverified_phones.where(condition).first
  end

  def set_header
    response.headers["Content-Type"] = "text/xml"
  end

  def render_twiml(response)
    render text: response.text
  end
end
```

In this `voice` method, we have set up the Twilio response. When a call is made
to the user, this response will get converted into robotic human voice.
`render_twiml` method which sets twilio response in text form is required for
Twilio APIs. Set up the response header in the `set_header` method which gets
called in `after_filter` method.

## Step 3: Set request URL for voice phone verification in Twilio

In `voice` action method, we have setup the request url in the `action` key of
Twilio response object, that also needs to be set in your Twilio account. So
when, user replies back to the call query, Twilio will make a request to our app
and adds its own some values as parameters to the request. Using those
parameters we handle the actual phone verification in the app.

Open twilio account and under **NUMBERS** section/tab, click on your Twilio
number. Then in Voice section, add request URL with HTTP POST method. Add URL
like this.

`http://your.ngrok.com/phone_verifications/verify_from_voice/`

We need [Ngrok](https://ngrok.com) to expose local url to external world. Read
more about it in my previous [blog post](phone-verification-using-twilio).

### Step 4: Add verify_from_voice action in phone verification controller

First add route for this action in `config/routes.rb`

```plaintext
post "phone_verifications/verify_from_voice" => "phone_verifications#verify_from_voice
```

Add this method, in your `PhoneVerificationsController`.

```ruby
  def verify_from_voice
    response = Twilio::TwiML::Response.new do |r|
      if params['Digits'] == "1"
        user = get_user_for_phone_verification
        user.mark_phone_as_verified!

        r.Say 'Thank you. Your phone number has been verified successfully.',
               voice: HUMAN_VOICE
      else
        r.Say 'Sorry. Your phone number has not verified.',
               voice: HUMAN_VOICE
      end
    end

    render_twiml response
  end
```

Modify private method `get_user_for_phone_verification` to support voice
verification in `PhoneVerificationsController`.

```ruby
  def get_user_for_phone_verification
    if params['Called'].present?
      phone_verification_code = params['verification_code']
      phone_number            = params['To']
    else
      phone_verification_code = params['Body'].try(:strip)
      phone_number            = params['From']
    end
    condition = { phone_verification_code: phone_verification_code,
                  phone_number: phone_number.gsub('+1', '') }

    User.unverified_phones.where(condition).first
  end
```

In the `verify_from_voice` method, we get parameters `Digits`, `To` &
`verification_code` from Twilio request. Using these parameters, we search for
user in the database. If we get the proper user then we mark user's phone number
as verified phone number.

## Links

- [Human page](https://www.bigbinary.com/blog/voice-based-phone-verification-using-twilio)
