Build a Simple Phone Verification System with Twilio, PHP, MySQL, and jQuery

About a year ago we wrote about phone verification as a preventative to spam or fraud, and a simple way to keep your users safe. Twilio customers continue to use two-factor authentication for the benefit of their customers. Read more about how you can build this out for your business here or how Intuit implemented identity verification with Twilio.

As more and more applications integrate with phones there is an increasing need to verify phone numbers to help prevent spam, fraud and other dubious activities. In these cases it’s common to use an automated phone verification system to present the user a verification code in their web browser while a call is initiated to their phone. When the call is answered they are prompted to enter the code, allowing them to confirm that they are the owner of that number.

In this post we cover how to build a simple phone number verification system using PHP, MySQL and jQuery. (update: we also have a tutorial on how to build SMS phone verification into a Rails 4 app.)

Below are highlights to the most important elements but you can download the complete example here. To run this example on your own server, update the database settings in database.php and your Twilio account settings in call.php. This example also makes use of our Twilio PHP Helper library which you can find on GitHub.

Basic steps

  1. User visits verification web page and enters phone number.
  2. Random verification code is generated and user is called and prompted to enter code.
  3. If code is entered incorrectly, re-prompt to enter code.
  4. If code is entered correctly, update database.
  5. Update web page with status message.

Step One: The verification web page

We’ll start with the HTML the user will see. Create a file called index.php and add the following code to the <body>:

Enter your phone number:

When the user visits the page they’ll be presented with the form asking them for their phone number. Please note that while we don’t verify the phone number in this example, in a production environment you would want to make sure the phone number is E.164 formatted. Once entered, we’ll hide the form and show them their verification code. Here’s the jQuery needed to make that transition:

Our initiateCall() function kicks off an AJAX request to generate the random code and initiate the phone call, which I’ll discuss in more detail in Step Two later. Once we’ve got the code, we’ll update the UI to show it to the user and then start polling our database for status updates. The code to poll the server looks like this:

Once we’ve got confirmation from the server that the number has been verified, we update the UI to let the user know.

Step Two: Generate and display random code

Step Two in our walkthrough overlaps with Step One since it is initiated when the user submits the form with their phone number. We’ll pick up in our initiateCall() function which makes the AJAX POST request to call.php. Inside call.php we generate the random 6-digit verification code and start the phone call by calling the Twilio REST API using the PHP Helper Library. Once we have the code, we’ll send it back as JSON for the browser to parse and display (as covered in Step One).

We’re storing the phone number along with the generated code in a MySQL database so that we can update the verified column from our TwiML script and then retrieve it later. For this example I’m using a simple table definition:

Steps Three and Four: Collect and verify code via phone call

When initiating the call we direct Twilio to use the twiml.php file which generates the necessary TwiML to prompt the caller to enter their code. The first time this file is requested we’ll ask the caller to enter their code. Once they’ve entered 6 digits, Twilio will make another post to the same URL with the Digits POST parameter now included. With this information we look up the caller’s phone number in the database and check for a match. If the code entered is incorrect, we’ll re-prompt them to enter it again. Once they’ve entered the correct code we update the database and thank them for calling.

Step Five: Update the web page when the number is verified

Back in Step One we created the jQuery needed to begin polling the server for status updates. Our checkStatus() function makes a POST to status.php which looks up the phone number in the database and sends back some JSON containing the verification status.

Coming soon: Verification via SMS

In an upcoming post I’ll be using this example as a starting point for creating a similar system to verify phones but using SMS instead of voice. Let me know in the comments below if there’s anything you’d like to see covered in that post.

Download the complete example

Download twilio-phone-verification.tar.gz

Read more about Phone Verification

Documentation: Authy for Two Factor Authentication

Blog post: SMS Phone Verification in Rails 4 with AJAX and Twilio 

Blog post: How to Build a Phone-Based Two-Factor Authentication

Blog post: Phone-Based Two-factor Authentication Is A Better Way to Stay Secure

Blog post: The Key to Phone Verification is a Good User Experience


    awesome and helpful post. You made my day

  • cloud sms

    Nice work! There is complex code but its really helpful.

    • Twilio

      Thank you. If you have any questions you can email and we can walk you through it.

  • Sevagba

    and btw the database table is filling correctly with phone_number and verification_code s but it doesn’t work (i think its jquery problem)

  • Brian

    REALLY interested in seeing the SMS version of this. We want to be able to send a randomly generated code via sms to our service provider upon purchase of his/her service/item on our website. once the service provider receives the code, enters it and returns the message by simply entering the verification code via sms our web app will be set to conduct a several server side actions to update numbers of items etc. We will also send a follow up text to confirm that verification has been received. Are you guys close on this? It’s very similar to the voice but step #1 is a purchase not the entry of a phone number.


  • Twilio

    Jane – the link is updated:

  • Frank

    Not working. There is a call require(“Services/Twilio.php”); in call.php file, but there is no Services folder or Twilio.php file.

  • Frank

    Ok figured that out. The folder twilio-twilio-php-3.9.1-1-gd4a45c5 in the second download link has a folder Services that needs to uploaded along with the rest of the code. Did that, still not working. Verification code is being inserted in the db, but before the verification process can be completed, the call gets disconnected each time. Anyone has ideas or anyone got this to work?

  • Frank

    My situation is the same as an earlier poster ‘sevagba’. Phone number and verification code are being inserted but verification process has a problem. Call is being disconnected after a a few seconds before verification can even take place.

    • Edison

      Same problem for me, Anybody knows the reason why?

    • Donovan Hubbard

      I’m having the same problem. After entering the 6 digit code, the call
      ends with no message and the verification never completes. Also, no
      errors are being reported for this in App Monitor.

    • Donovan Hubbard

      Hope this helps some. When tracing out my issue I found two issues.

      1) At first my second twiml.php call was returning a HTTP 301 (moved). This was because the calling page was using a “www” prefix, but the ‘’ line didn’t include the “www” prefix. After adding the “www” I was now getting HTTP 200 (success).
      2) Twilio was adding a “+1” to any phone number entered ($_POST[“Called”]), which was preventing my script from finding the database entry since I was using just the phone number(ex: 3213214321 instead of +13213214321).
      To fix that I chaged this line,

      // line 11 in twiml.php

      $result = db(sprintf(“select * from numbers where phone_number=’%s'”, $_POST[“Called”]));


      // Twilio likes to add +1 to the front of any phone number, use the last 10 digits for comparison
      $client_num = substr($_POST[“Called”], -10);
      $result = db(sprintf(“SELECT * FROM numbers WHERE phone_number LIKE ‘%s'”, $client_num));

      • Donovan Hubbard

        Sorry, forgot this. In the twiml.php I also edited the following line
        // line 14
        db(sprintf(“UPDATE numbers SET verified = 1 WHERE phone_number = ‘%s'”, $_POST[“Called”]));

        to be this,
        db(sprintf(“UPDATE numbers SET verified = 1 WHERE phone_number LIKE ‘%s'”, $client_num));

  • sivakumar

    Thanks for the post, You made my work simple. Thanks

    • Prove

      We released an API that makes this entire process much easier. Here’s our docs:

    • devilx

      do you know how to use this during signup ?? coz i cant understand this … if u can can you explain me clearly ?

      • jonmarkgo

        Hey Devilx,
        In a normal signup flow you would typically have the user enter a username and password. In this case, you would add an additional field for phone number. You would also want to add a hidden flag to determine if their phone number has been verified.

        Upon registration, you would send a verification code to the user (as demonstrated in this tutorial), once they go back to your website and enter the code properly, you would set the verified flag on their account to true so that your application can know that the user’s phone number is real and verified.

  • rahul

    Has anyone tried,
    Is it using Twilio? or an independent platform?

  • MikesUptown

    hey there… this is awesome post… thanks! so i installed this on my server and set up db correctly and finally got it to make a call out, but before i can insert the verification code i get a voice error: “an application error has occurred. goodbye” and then hang up… anyone know why this could be causing a fail?

    • jonmarkgo

      Hey Mike,

      Want to drop me an e-mail at jon@twilio:disqus .com so I can help you debug this? I want to make sure it’s not an error in the blog post!

      If you’d like to take a crack at debugging it yourself, you can check your Twilio App Monitor in your account Dashboard at

  • Junel

    Sir the code that i downloaded is not function when i clicked the verify button? What should I do about this Sir?

    • rickyrobinett

      Hi Junel –

      Are you seeing the AJAX request made to call.php? You may want to check your php error logs to see if there’s something that isn’t configured properly. If you drop me an e-mail at and I can help you debug.


      • mansur

        hi just insatlled first llink of download

        i imported sql and its just saying Enter your phone number: i entered phone no and clicked the verify button. but nothing happen. but phone number saved to data base.. anything i missed up? and where to create api for this app? any clear example here? im testing in localhost.. thanks

  • Mel

    hi i just want to know if the feature phone verification with twilio is free.. thanks!

  • Isaac Newton Aranas

    hi i just wanna ask if this simple phone verification with twilio is free. thanks!

  • yatin

    Hello.. I am able to verify user using above method. only problem is once user received call and he did not enter code quickly, call get disconnect after 5 seconds.. how can I increase this tie ?

    • rickyrobinett

      Hi Yatin –

      By default, has a 5 second timeout. You can change this by passing a timeout argument in the array when you first create your gather response.

      If you wanted a 10 second time out it would look like this:
      $gather = $response->gather(array(‘numDigits’ => 6, ‘timeout’ => 10));

      Let me know if that helps! You can read a bit more about some other helpful options you can set with gather here:

      • yatin

        Perfect !

        Thanks Ricky !

  • Atk

    thanks mate
    it really is very helpful

  • mohtasham hussain

    Can anyone help me out with this error:
    Deprecated: mysql_connect(): The mysql extension is deprecated and will be removed in the future: use mysqli or PDO instead in C:wampwww
    I tried using mysqli insteaad of mysql