How to filter out VoIP numbers before sending an SMS OTP

July 12, 2022
Written by
Reviewed by

How to filter out VoIP numbers before sending an SMS OTP

SMS one-time passwords (OTP) are a user-friendly solution for adding additional security to your application. One benefit of using phone numbers is that they're more likely to be associated with a unique user. However, VoIP numbers are often correlated with bots and don't have the same assurance that you're interacting with a real and unique user.

This blog post will show you how to detect VoIP phone numbers before sending an OTP using the Lookup API's new Line Type Intelligence package.

Line Type Intelligence is an improvement on an earlier version of carrier Lookup with more line type options and improved global support.

Prerequisites for detecting line type

Before you can detect a phone number's line type you'll need a Twilio account for using the Lookup API. Grab your Account SID and Auth Token (found in the Console) and use them in your API requests.

Determine the line type of a phone number

The line type intelligence package will return:

  • Carrier name, such as Twilio, O2 or Verizon
  • Mobile Network Code (MNC) and Mobile Country Code (MCC) three digit codes to identify the mobile network operator
  • The phone number line type

The line type can be one of the following:

  • landline
  • mobile
  • fixedVoip
  • nonFixedVoip
  • personal
  • tollFree
  • premium
  • sharedCost
  • uan
  • voicemail
  • pager
  • unknown

Check out the documentation for more information about what different line types mean.

Make a request to the Lookup API with your Account SID and Auth Token.


You can find the code sample in more languages in the documentation. The phone number we're testing here is Twilio's customer support number which is a Twilio-powered VoIP number.

  "phone_number": "+18448144627",
  "validation_errors": [],
  "call_forwarding": null,
  "url": "",
  "calling_country_code": "1",
  "live_activity": null,
  "sim_swap": null,
  "caller_name": null,
  "national_format": "(844) 814-4627",
  "country_code": "US",
  "line_type_intelligence": {
    "mobile_network_code": "950",
    "carrier_name": "Twilio - Toll-Free - SMS-Sybase365/MMS-SVR",
    "error_code": null,
    "mobile_country_code": "310",
    "type": "nonFixedVoip"
  "valid": true

You can get a sneak peak of some of the other new packages available like Live Activity and SIM Swap detection - request access now!

Difference between Fixed and Non-Fixed VoIP phone numbers

A fixed VoIP number requires a physical address so is generally associated with a specific user or company. You may decide not to filter this type of phone number.

A non-fixed VoIP number does not have the same address requirement so is often what you get with Google Voice or Twilio: a programmatically allocated phone number. This is the specific type of VoIP number our customers usually filter out.

Learn more about different line types in the documentation.

Combine Lookup with Verify to filter VoIP numbers

Now that you know how to query the Lookup API, you can combine it with the Verify API to filter out non-fixed VoIP numbers before sending an OTP.

First, create a Verify Service in the Twilio Console.

Console image showing an example verify service and SID

Then head over to Twilio's CodeExchange to deploy a one-time passcode verification project. We'll use this pre-built sample JavaScript app for doing serverless phone verification and add the Lookup validation on top of it.

Code exchange page with Verify Service SID pasted in

Paste in your Verify service SID and click "Deploy my application". After a minute or so you can navigate to the newly deployed example app. Once you're in the live application, click on "Edit this application", which will take you back to the Twilio Console. Open up the start-verify.js function.

Twilio functions console page with open code editor

Above const verification = …, add the following code. This is the same as the cURL request above but uses Twilio's Node SDK.

const lookup = await client.lookups.v2.phoneNumbers(to).fetch({ fields: "line_type_intelligence" })

Then add a check for the line type and throw an error if it's a non-fixed VoIP number.

if (lookup.lineTypeIntelligence.type === "nonFixedVoip") {
  throw new Error('Invalid phone number type. Please use a mobile number.');

Make sure you're using version 3.77.3+ of the Twilio Node.js helper library. You can see your current version by clicking "Dependencies" in the Settings section of the Twilio Functions console.

Save and deploy your changes. Test it out with your personal mobile number and then test it out again with Twilio's number (+18448144627) and you'll get an error.

What's next with Lookup

You can also use this logic to detect landlines and default to voice calls for 2FA or to block the rare pager number. Stay tuned for more exciting data packages from the Lookup API like detection for SIM swap, live activity, call forwarding and more.

Lookup is also a great way to clean up your database or validate phone number input with our free formatting API. Learn more in our blog post about best practices for phone number validation.