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

Verifying the phone numbers of your users is a fast, effective way to tamp down on fraud and spam accounts. This post will help you build such a system using Twilio Voice, PHP 7, MySQL 5.x and jQuery.

Below we’ll walk through the code but if you have an existing MAMP environment or equivalent you can download the complete example here and get started. 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 installed via Composer.

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 Zero: MySQL Database setup

If you already have MySQL setup, skip this step. We’ll be managing our MySQL database with MAMP. Once you’ve installed and setup the GUI, you should be able to reach your server on localhost:8888 or whatever port MAMP has directed you to.

It looks something like this:

Keep the Host, User and Password values handy for later. You can then access the phpMyAdmin interface by clicking it from there where we will take the next steps.

On this page you will want to create a new database, I’ve called it verify and set the Collation to utf8_general_ci. We will then setup the database schema with one table called numbers.

We’ll be storing the phone number along with the generated verification code in a MySQL database so that we can update the verified user info an retrieve it later. For this example there is a simple table definition which you can store as dbschema.sql and can be added directly to the phpMyAdmin interface as well. Copy and paste the code below in the SQL tab as the following clip shows.

You will want to be sure to save all of the files we create for this post in the MAMP folder htdocs. The full path should look like Applications/MAMP/htdocs.

If you’ve chosen not to download the completed project, create a file called database.php and place the following code in it remembering to update it with your database info if it does not match the default values.

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>:

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 as referenced in the html above in main.js:

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

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 with the Twilio REST API using the PHP Helper Library. If you haven’t already, now would be a good time to run the following command in your project directory:

You will also want to replace the $accountSid , $authToken , $outgoingNumber , and $endPoint  variables with your own information.

Once we have the verification code we’ll send it back as JSON for the browser to parse and display.

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 <Gather>  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.

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

That’s all folks!

We did it. Simple phone verification mission accomplished. Many thanks to Jonathan Gottfried for his inspiration from this post in its original incarnation. And shoutout to my colleague Margaret Staples for lending her PHP expertise.

If you have any questions or ideas for your next project, please find us on twitter or email



    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

  • mark

    Nice tutorial thanks you there is another good and easy coded tutorial on to create email verification using php

  • GabbyVille

    Hello, is this still working?

    I try to install it on my server, but no luck, I can see the code created by the site, but no call is made on my phone.

    Here is my test site

    Many thanks

  • krystiyan

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

  • praveen

    i downloaded this but in my pc its not working well,i put this code in localhost so please can you peoples help me out form this

  • kishan Modi

    This is not working plz suggest me

  • benyates1

    I am more interested in the SMS version of this but that post doesn’t appear have been produced yet. Is there any possibilty of it being written or is there another resource you are aware of that I can use?

    • philnash

      Hey Ben,

      This is quite an old post now and the latest PHP library is a breaking version higher, so that may explain why this post isn’t working for you.

      However, we have a new and improved API for performing phone verification via SMS and phone call. Take a look at the Authy Phone Verification API here:

      • benyates1

        Hi Phil

        Thanks for the comment, yes I noticed the date – wasn’t expecting to hear anything back – so thanks.

        I’ve noticed the updated API and have had my head buried in the documentation over the weekend and still cannot get any verification to work.

        I’m not using composer and it appears that I’m struggling with actually setting up Twilio.

        When I noticed this particular script wasn’t working and tweaked it noticing ServicesTwilio.php didn’t exist. I tried to send a test message with hardcoded details as per an example by Twilio through a simple PHP script to test and even that failed to work.

        • philnash

          Hey Ben,

          Do you want to send me an email at and I’ll try to help out. If you can send me some details of what you’ve set up and tried so far I’ll try to get this working for you.

  • Mohammed Mashud

    Thanks for the post

  • divyesh

    It does not work. I used it but how to import database. Database not imported. Please reply with positive feedback.

    • Megan Speir

      Hey divyesh, this post has been updated! Give it a try with the new instructions and let me know how it goes.

      • Ganesh Kumar

        Hi, I tried it and the AJAX freezes without refreshing to the second screen. Any idea why?

        • Megan Speir

          Does it say anything in the console? Or in the logs?

          • Ganesh Kumar

            Hi Megan, It was because I entered the SID wrongly(missed the last character). Now I am getting the application error(in voice msg) and the /var/log/apache2/error.log says

            PHP Notice: Undefined variable: gather in /var/www/html/php-verify/twiml.php on line 23, referer:

            PHP Fatal error: Uncaught Error: Call to a member function say() on null in /var/www/html/php-verify/twiml.php:23nStack trace:n#0 {main}n thrown in /var/www/html/php-verify/twiml.php on line 23, referer:

            Though this file is very much available to access from outside, twilio logs say 11200 Error.

            Any idea?

            Ganesh Kumar

          • Megan Speir

            You’ve updated the $endpoint variable to that publicly available URL and it says gather is undefined. What does it say when you check the version of twilio php helper library you have installed?

          • Infinicalls Infinicalls

            The version is “twilio/sdk 5.14.1 A PHP wrapper for Twilio’s API” and the $endpoint is pointing to a publicly available http:// URL. There is no hurdle accessing the said URL via browser.

            But as you said, the twilio logs say URL is not accessible. “An attempt to retrieve content from returned the HTTP status code 500″. I am really unable to understand this stranger behavior.

          • Megan Speir

            Hello, you can email me – mspeir [at] twilio [dot] com and I’d be happy to help you debug.

  • Nhlakanipho “Blues” Nkokhelo


  • Infinicalls Infinicalls

    Anybody here solved the application error voice message?

  • auro

    really impressive, can you suggest me how to implement it in codeigniter.

  • Nikunj Trivedi

    Hi, i have implemented above code but not working. pls help
    1) call has been place using above code but on call never ask for vefication code it is saying that press any key you are using trial account.
    2) callback url not getting data which has been pressed by use during call not getting in response pls help thanks in advance.

  • Ethyn Jade O’Grady

    Hi! Unfortunately your code is not working!!!