← Back to Blog
Fraud Prevention Technical Guide · 11 min read

How to Detect VOIP Phone Numbers in Your Signup Flow

VOIP numbers are the single biggest fraud vector in phone-based authentication. A single attacker can generate hundreds of Google Voice or TextNow numbers for free and use them to create fake accounts, abuse free trials, and bypass SMS verification. Here is how to detect them at the API level.

Why VOIP Numbers Are a Fraud Vector

SMS-based phone verification was supposed to solve the fake account problem. The logic is simple: a real phone number is tied to a real identity, a physical SIM card, a credit check, a billing address. Requiring a phone number to sign up should filter out bots and throwaway accounts.

That assumption broke years ago. Today, anyone can create a VOIP (Voice over IP) phone number in under 30 seconds, for free, with no identity verification whatsoever. Services like Google Voice, TextNow, TextFree, Talkatone, and dozens of others hand out US phone numbers that can receive SMS messages, complete with area codes that look indistinguishable from real carrier numbers.

The numbers tell the story:

If your signup flow accepts any phone number that can receive an SMS, you are not verifying identity. You are verifying that someone has internet access.

The Real Cost

A mid-size SaaS company with 10,000 monthly signups typically sees 15-25% fake accounts when using SMS verification alone. At $0.0075 per SMS (Twilio pricing), that is $11-18/month in SMS costs wasted on fake numbers. But the real cost is downstream: inflated metrics, wasted support tickets, trial abuse, and Stripe card-testing fraud that can run into thousands per month.

How Carrier Lookup Works

Every phone number in the North American Numbering Plan (NANP) is assigned to a carrier through the Number Portability Administration Center (NPAC). When a number is provisioned, whether by AT&T, Verizon, Google Voice, or TextNow, that assignment is recorded in databases maintained by the Local Exchange Routing Guide (LERG) and the Operating Company Number (OCN) registry.

Carrier lookup APIs query these databases in real-time. When you submit a phone number, the API returns:

The critical distinction is between fixed VOIP and non-fixed VOIP. Fixed VOIP numbers are tied to a physical address (like a business landline running over IP). Non-fixed VOIP numbers have no address association and can be created from anywhere. Google Voice, TextNow, and the other fraud vectors are all non-fixed VOIP.

The NPAC Lookup Chain

When Auth1's API receives a phone number for verification, the lookup happens in this order:

  1. Number format validation — Verify E.164 format, valid country code, valid area code
  2. NPAC/LERG query — Determine the original carrier assignment and current carrier (if ported)
  3. Carrier classification — Map the carrier OCN to our internal database of 2,400+ carriers with line-type classifications
  4. Risk scoring — Combine carrier type, port history, area code reputation, and velocity signals into a 0-100 risk score

The entire lookup completes in under 50ms. There is no user-facing latency.

Types of VOIP Numbers and Their Risk Profiles

Not all VOIP is created equal. The risk varies dramatically by provider and use case. Here is how we classify them:

Provider Type Cost ID Required Risk Level
Google Voice Non-fixed VOIP Free Google account only High
TextNow Non-fixed VOIP Free None Critical
TextFree (Pinger) Non-fixed VOIP Free None Critical
Talkatone Non-fixed VOIP Free None Critical
Bandwidth.com Non-fixed VOIP Paid (resold) Varies by reseller Medium
Twilio Non-fixed VOIP $1.15/mo Account + payment Medium
Vonage Business Fixed VOIP $19.99+/mo Business verification Low
AT&T / Verizon / T-Mobile Mobile $25+/mo + device SSN / ID Low

Bandwidth.com is worth special attention. It is the underlying carrier for dozens of VOIP services, including TextNow, RingCentral, and many others. When you see "Bandwidth" as the carrier name, the number is almost certainly VOIP, but the specific risk depends on which Bandwidth reseller provisioned it. Auth1 maintains a sub-carrier mapping that identifies the actual service behind Bandwidth-provisioned numbers.

Implementation with Auth1's API

Auth1's phone verification endpoint performs carrier lookup automatically. When you send a verification request, the response includes VOIP detection data alongside the OTP delivery status. You do not need a separate API call.

The response includes three key fields:

Node.js Implementation

JavaScript verify-phone.js
const AUTH1_API_KEY = process.env.AUTH1_API_KEY;
const AUTH1_BASE = 'https://auth-api.z101.ai/api';

async function verifyPhoneNumber(phoneNumber) {
  const response = await fetch(`${AUTH1_BASE}/auth/sms/request`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'x-api-key': AUTH1_API_KEY,
    },
    body: JSON.stringify({
      phone: phoneNumber,
      // Optional: set your risk tolerance
      voipPolicy: 'block',  // 'block' | 'flag' | 'allow'
    }),
  });

  const data = await response.json();

  // Response shape:
  // {
  //   success: true,
  //   isVoip: false,
  //   riskScore: 12,
  //   carrierInfo: {
  //     name: "T-Mobile USA",
  //     lineType: "mobile",
  //     isPorted: false
  //   },
  //   otpSent: true
  // }

  if (data.isVoip) {
    // VOIP number detected
    console.log(`Blocked VOIP number: ${data.carrierInfo.name}`);
    return {
      allowed: false,
      reason: 'VOIP numbers are not accepted',
      carrier: data.carrierInfo.name,
    };
  }

  if (data.riskScore > 70) {
    // High risk even if not flagged as VOIP
    console.log(`High risk number: score ${data.riskScore}`);
    return {
      allowed: false,
      reason: 'Phone number flagged as high risk',
      riskScore: data.riskScore,
    };
  }

  // OTP was sent, verification in progress
  return { allowed: true, otpSent: data.otpSent };
}

// Usage in an Express route
app.post('/api/signup', async (req, res) => {
  const { phone, email, name } = req.body;

  const phoneCheck = await verifyPhoneNumber(phone);

  if (!phoneCheck.allowed) {
    return res.status(400).json({
      error: 'phone_rejected',
      message: phoneCheck.reason,
    });
  }

  // Phone is legitimate, proceed with signup
  // OTP has already been sent by Auth1
  res.json({ success: true, message: 'Verification code sent' });
});

Python Implementation

Python verify_phone.py
import os
import requests

AUTH1_API_KEY = os.environ["AUTH1_API_KEY"]
AUTH1_BASE = "https://auth-api.z101.ai/api"


def verify_phone_number(phone_number: str) -> dict:
    """Verify a phone number and check for VOIP."""
    response = requests.post(
        f"{AUTH1_BASE}/auth/sms/request",
        headers={
            "Content-Type": "application/json",
            "x-api-key": AUTH1_API_KEY,
        },
        json={
            "phone": phone_number,
            "voipPolicy": "block",
        },
    )
    data = response.json()

    if data.get("isVoip"):
        return {
            "allowed": False,
            "reason": f"VOIP detected: {data['carrierInfo']['name']}",
            "risk_score": data["riskScore"],
        }

    if data.get("riskScore", 0) > 70:
        return {
            "allowed": False,
            "reason": "High risk phone number",
            "risk_score": data["riskScore"],
        }

    return {"allowed": True, "otp_sent": data.get("otpSent")}


# Flask example
from flask import Flask, request, jsonify

app = Flask(__name__)


@app.route("/api/signup", methods=["POST"])
def signup():
    body = request.get_json()
    result = verify_phone_number(body["phone"])

    if not result["allowed"]:
        return jsonify({
            "error": "phone_rejected",
            "message": result["reason"],
        }), 400

    return jsonify({"success": True})

Understanding the Risk Score

The binary isVoip flag is useful, but it is not the whole picture. Auth1's risk score combines multiple signals into a single 0-100 integer that gives you granular control over your signup policy.

Risk Score Components

Signal Weight Description
Carrier type 40% Non-fixed VOIP = +40, Fixed VOIP = +15, Mobile = +0, Landline = +5
Port history 15% Recently ported numbers score higher (porting is a common fraud prep step)
Area code reputation 15% Certain area codes (e.g., 305, 347, 646) have higher VOIP density
Velocity 20% Multiple signups from the same number range in a short window
Known fraud carrier 10% Numbers from carriers with >80% fraud association (TextFree, Talkatone)

Recommended Thresholds

Pro Tip

Set your voipPolicy to "flag" instead of "block" during your first week of integration. This will send the OTP regardless but include the VOIP data in the response. Use this to analyze your traffic before enforcing a policy. Most teams find that 15-25% of their signups are VOIP when they first turn on detection.

Comparison of VOIP Detection Approaches

There are several ways to detect VOIP numbers. Here is how they compare:

Approach Accuracy Latency Cost Catches Bandwidth
Twilio Lookup API 85-90% 200-400ms $0.005/lookup Partial
Numverify / Abstract API 70-80% 300-600ms $0.001-0.01/lookup No
IPQualityScore Phone API 88-93% 150-300ms $0.002-0.005/lookup Yes
Auth1 (built-in) 94-97% <50ms Included in plan Yes (sub-carrier mapping)
Manual carrier regex 40-60% <1ms Free No

The key differentiator is sub-carrier mapping. Most lookup APIs tell you a number belongs to "Bandwidth.com" but cannot tell you whether it was provisioned by TextNow (high fraud) or RingCentral (business VOIP, lower fraud). Auth1 maintains a mapping of 200+ Bandwidth resellers and their fraud profiles, which is why the accuracy is higher.

Real-World Results

After deploying VOIP detection, Auth1 customers typically see the following changes within the first 30 days:

Case Study

A B2B SaaS company with 8,000 monthly signups was losing approximately $6,200/month to trial abuse and card-testing fraud originating from fake accounts. After enabling Auth1's VOIP detection with a riskScore threshold of 50, fake signups dropped from 1,840/month to 220/month. Trial abuse costs dropped to near zero. The entire integration took 45 minutes.

Edge Cases to Handle

VOIP detection is not perfect. There are legitimate users who use VOIP numbers:

For B2C products, blocking all VOIP is usually the right call. For B2B products, consider using the risk score instead of the binary flag, and set a higher threshold (60-70) to allow business VOIP while still catching the obvious fraud vectors.

Getting Started

VOIP detection is included in all Auth1 plans, including the free tier. To enable it:

  1. Sign up at auth1.ai/signup and get your API key
  2. Add the voipPolicy parameter to your verification requests
  3. Handle the isVoip and riskScore fields in the response
  4. Monitor your fraud dashboard to tune your thresholds

The entire integration takes less than an hour. If you are currently using Twilio or another SMS provider directly, you can replace the verification call with Auth1's endpoint and get VOIP detection for free.