How to Send Voice OTP on a Phone Call in Python Using Flask and Plivo

Voice OTP is used to authenticate a phone number by delivering the One-time password (OTP) via a phone call. This verification is done by making a call to the mobile number & playing a sequence of digits. In order to verify the mobile number, the user needs to confirm the played sequence of digits.

Voice OTP is commonly used to verify new user registrations, online transactions, login sessions in an app or website. In this blog post, we walk you through a sample implementation of sending a Voice OTP using the Plivo SMS platform and PHLO, our visual workflow builder. Plivo’s direct carrier connectivity and intelligent routing engine guarantee the best call connectivity and quality.

Prerequisites

Before you get started, you’ll need:

  • A Plivo account — sign up for one for free if you don’t have one already.
  • A voice-enabled Plivo phone number if you want to receive incoming calls. To search for and buy a number, go to Phone Numbers > Buy Numbers on the Plivo console. Buy a New Plivo Number
  • Flask and Plivo Python packages — run pip install plivo flask to install them.
  • ngrok — a utility that exposes your local development server to the internet over secure tunnels.

Create a PHLO to send OTP via phone call

PHLO lets you construct your entire use case and build and deploy workflows visually. With PHLO, you pay only for calls you make and receive, and building with PHLO is free.

To get started, visit PHLO in the Plivo console and click on Create New PHLO. Click Create New PHLO to build a new PHLO. On the Choose your use-case window, click Build my own. The PHLO canvas will appear with the Start node. Click on the Start Node, under API request, fill in the Keys as from, to & otp and then click on Validate. From the list of components, on the left-hand side, drag and drop the Initial Call component onto the canvas and connect the Start node with the Initiate Call node, using the API Request trigger state.

Configure the Initiate Call node with the using the From field. in the To field. Once you have configured a node, click Validate to save the configurations. Similarly, create a node for the Play Audio component and connect it to the Initiate Call node using the Answered trigger state. Next, configure the Play Audio node to play a specific message to the user. For example, in this case, “Your verification code is <OTP>”. Under Speak Text, click on Amazon Polly and paste the following:

<Speak voice="Polly.Amy">
    <prosody rate="medium">
        Your verification code is
    <break/>
    <break/>
    <say-as interpret-as="spell-out">{{Start.http.params.otp}}</say-as>
    </prosody>
</Speak>

and click on Validate to save

Connect the Initiate Call node with the Play Audio node, using the Answered trigger state. After you complete the configurations, provide a friendly name for your PHLO and click Save.

Create a PHLO for Voice OTP

Use the PHLO in a Flask application

Now you can use the PHLO in a Python Flask application by following the below steps:

  • Create a project directory, run the following command:
      $ mkdir mypythonapp
    
  • Change the directory to our project directory in the command line:
      $ cd mypythonapp
    
  • Install the Plivo SDK using pip
      $ pip install plivo
    
  • Install other modules
      $ brew install redis
      $ pip install redis
      $ pip install flask
    

We recommend that you use virtualenv to manage and segregate your Python environments, instead of using sudo with your commands and overwriting dependencies.

Run the PHLO to send OTP via phone call

Now you can trigger the PHLO and test it out. Copy the PHLO ID from the end of the URL of the workflow you just created. You’re also going to need your Auth ID and Auth Token. Create a Python source code file — let’s call it trigger_phlo.py — and paste this code into it:

import plivo
import random
import redis

from flask import Flask, jsonify

app = Flask(__name__)

r = redis.StrictRedis()

def generate_code():
    code = random.choice(range(100000, 999999))  # generating 6 digit random code
    return code


# Make call to the destination number with OTP.
@app.route("/dispatch_otp/<destination_number>")
def dispatch_otp(destination_number):
    try:
        # generate OTP.
        code = generate_code()

        # Make a call
        auth_id = <auth_id>
        auth_token = <auth_token>
        phlo_id = 'Your PHLO ID' # https://console.plivo.com/phlo/list/
        payload = {"from" : "+15671234567","to" : destination_number, "otp":code}
        phlo_client = plivo.phlo.RestClient(auth_id=auth_id, auth_token=auth_token)
        phlo = phlo_client.phlo.get(phlo_id)
        response = phlo.run(**payload)
        print str(response)
        print(r.setex("number:%s:code" % destination_number, 60, code))
        return (
            jsonify({"status": "success", "message": "verification initiated"}),
            200,
        )
    except:
        return ("Error encountered", 400)

# verify the OTP enetered by the user.
@app.route("/verify_otp/<destination_number>/<code>")
def check_code(destination_number, code):
    """
    check_code(number, code) accepts a number and the code entered by the user and
    tells if the code entered for that number is correct or not.
    """
    # fetch the OTP set for the destination number
    original_code = r.get("number:%s:code" % destination_number)

    if int(original_code) == int(code):  # verification successful, delete the code
        r.delete("number:%s:code" % destination_number)
        return (
            jsonify({"status": "success", "message": "codes match! number verified"}),
            200,
        )
    elif original_code != code:
        return (
            jsonify(
                {
                    "status": "rejected",
                    "message": "codes do not match! number not verified",
                }
            ),
            404,
        )
    else:
        return (jsonify({"status": "failed", "message": "number not found!"}), 500)


if __name__ == "__main__":
    app.run(host="0.0.0.0", debug=True)

Substitute actual values for <auth_id>, <auth_token>, and <PHLO_ID>. Save the file and run it with the command

$ python trigger_phlo.py

Boom — you’ve made an outbound call with the OTP as a text-to-speech message.

Simple and reliable

And that’s all there is to send OTP via a phone call using Plivo’s Python SDK. Our simple APIs work in tandem with our comprehensive global network. You can also use Plivo’s premium direct routes that guarantee the highest possible delivery rates and the shortest possible delivery times for your 2FA SMS and voice messages. See for yourself — sign up for a free trial account.

comments powered by Disqus