Why mobile number validation matters

A phone number field looks simple, but it sits on the front line of onboarding fraud, SMS cost control, and KYC compliance. Fake or malformed numbers waste OTP and SMS spend, break delivery-notification flows, and let bot signups through registration forms. Getting validation right is a layered problem — no single check catches everything, and the layer most guides lead with (a checksum) is not actually checking what most people assume it's checking.

Format and structure validation

Confirms a number conforms to the correct international format for its country — length, country code, and national numbering rules under the ITU E.164 standard. Free, instant, and catches most typos.

Carrier and line-type verification

Determines whether a number is mobile, landline, or VoIP, identifies the carrier, and checks whether it's currently active and reachable — this layer requires a live lookup, not just string parsing.

The Luhn/MOD10 checksum — and the misconception around it

Most "phone validation" tutorials open with the Luhn algorithm (also called MOD10) — the same checksum that protects credit card numbers. Here's the part they usually skip: telephone numbers don't carry a check digit. The ITU's E.164 numbering plan has no built-in checksum, so running a Luhn check against a phone number is checking a mathematical property the number was never designed to have.

What Luhn/MOD10 is genuinely used for: credit card numbers, IMEI device identifiers, SIM card ICCIDs, and a handful of national ID formats. If you see "Luhn-validate the phone number" in a spec, check whether what's actually being validated is the customer's IMEI or SIM ICCID captured alongside the number — that's a legitimate, common pairing in device-binding and fraud-scoring flows.

Understanding the mechanics is still useful — it's the same technique behind IMEI and card validation you'll likely need elsewhere in a fraud-prevention stack:

// Luhn / MOD10 checksum — validates IMEI numbers, credit cards,
// SIM ICCIDs. Does NOT validate telephone numbers (E.164 has no check digit).
function luhnValidate(digits) {
  let sum = 0;
  let alternate = false;
  for (let i = digits.length - 1; i >= 0; i--) {
    let digit = parseInt(digits.charAt(i), 10);
    if (alternate) {
      digit *= 2;
      if (digit > 9) digit -= 9;
    }
    sum += digit;
    alternate = !alternate;
  }
  return sum % 10 === 0;
}

Worked example: validating IMEI 490154203237518 — double every second digit from the right (9→18→9, 4→8, 2→4, 3→6, 2→4…), sum all digits, and the total must be a multiple of 10. This exact process is what phone manufacturers use to generate a valid IMEI's final check digit — it has nothing to do with the subscriber's phone number.

Even where Luhn genuinely applies (IMEI, cards), it only catches accidental transcription errors — a single mistyped or transposed digit. It cannot tell you whether a number is in service, who it belongs to, or whether it's been reassigned. That requires the next two layers.

Open source and library-based validation

Google libphonenumber

Google's own library for parsing, formatting, and validating international phone numbers, maintained for Java, C++, and JavaScript (via the libphonenumber-js port) and used inside Android itself.

validifydart (Flutter)

A Dart/Flutter package bundling phone number checks alongside Indian personal-identifier validators (PAN, Aadhaar, Voter ID), plus financial ID formats like GSTIN and IFSC.

ISO/IEC 7064 libraries

Open-source Java implementations (e.g. danieltwagner/iso7064) of the MOD 11-2 and MOD 97-10 check-character systems behind IBAN and other structured identifiers — a different family of checksums from Luhn, useful if your stack validates bank or document numbers too.

// npm install libphonenumber-js
import { parsePhoneNumberFromString } from 'libphonenumber-js';

function validatePhone(number, defaultCountry) {
  const parsed = parsePhoneNumberFromString(number, defaultCountry);
  if (!parsed) return { valid: false, error: 'Invalid format' };
  return {
    valid: parsed.isValid(),
    e164: parsed.number,          // e.g. +14155552671
    country: parsed.country,
    type: parsed.getType(),       // MOBILE, FIXED_LINE, VOIP, etc.
  };
}

Real-time API-based validation

Format checks and libraries confirm a number is well-formed. To know whether it's actually reachable, who carries it, or whether it's been recently reassigned, you need a live API:

Twilio Lookup (v2)

Real-time line-type, carrier, and fraud-signal data. Basic format validation is free; the Line Type Intelligence package runs around $0.008 per request, and SIM Swap detection is priced separately on request rather than a flat published rate.

Numverify (APILayer)

A REST/JSON API covering format, carrier, and location data across 232 countries. The free tier allows 100 requests a month; paid plans start around $14.99/month for 5,000 requests (roughly $0.003 per lookup).

curl -X GET "https://lookups.twilio.com/v2/PhoneNumbers/+14155552671?Fields=line_type_intelligence" \
  -u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN

GSMA Open Gateway: network-based verification without an OTP

The GSMA Open Gateway Number Verification API takes a different approach entirely: instead of sending an SMS code and asking the user to type it back, your backend asks the mobile network operator directly whether the phone number matches the SIM currently making the request. The carrier confirms possession over its own infrastructure — no OTP, no SMS delay, and no exposure to SIM-swap or OTP-interception fraud, since the check never leaves the carrier's trusted network path.

POST /number-verification/v1/verify
Authorization: Bearer {access_token}
{
  "phoneNumber": "+14155552671",
  "hashed": false
}

The trade-off: it only works when the request originates from the user's own mobile data connection (not WiFi, in most implementations), and coverage depends on which operators in a given country have joined the federation.

Comparing the validation layers

Method Format check Carrier / line type Real-time status Typical cost
E.164 format check Free
libphonenumber ⚠️ Type only, no live carrier data Free, open source
Numverify ⚠️ Limited Free tier (100/mo), from ~$0.003/request
Twilio Lookup ✅ (SIM swap add-on) ~$0.008/request + custom SIM-swap pricing
GSMA Open Gateway ✅ Network-verified possession Negotiated per operator/aggregator

Step-by-step: layering validation in practice

1

Format-check on the client. Reject obviously malformed input immediately with libphonenumber before it ever hits your API — this is free and cuts wasted requests to paid layers downstream.

2

Store in E.164. Always persist numbers as +14155552671, not a locally formatted string — every downstream system, API, and comparison depends on one consistent representation.

3

Add a live layer where the risk justifies it. High-risk flows (payment, KYC, account recovery) justify Twilio Lookup, Numverify, or GSMA Open Gateway's per-request cost. Low-risk internal forms often don't need one.

Best practices

  • Always store E.164 format. Consistency here prevents an entire class of matching and deduplication bugs later.
  • Don't rely on a checksum that doesn't exist. Skip Luhn/MOD10 for the phone number field itself — reserve it for IMEI, SIM ICCID, or card numbers where it actually applies.
  • Cache validated numbers. Live API tiers have rate limits; re-validating on every page load burns budget for no new signal.
  • Match the validation layer to the risk. A newsletter signup and a payment authorization don't need the same validation cost.
  • Combine, don't replace. Format checks, library-based checks, and live API checks answer different questions — use them together, not as alternatives to each other.

Common use cases

User onboarding

Verify phone numbers at signup to cut fake accounts and bot registrations before they reach your database.

SMS and OTP delivery

Validate before sending — invalid or dead numbers waste SMS budget and drag down delivery-rate metrics with carriers.

Payment and KYC checks

SIM-swap and network-verification signals help flag account-takeover risk before a high-value transaction clears.

India-specific context: Sanchar Saathi and Chakshu

India's Department of Telecommunications runs the Sanchar Saathi platform, a citizen-facing complement to enterprise-side validation. Its Chakshu feature lets citizens report suspected fraud calls, SMS, and WhatsApp messages; the platform has also been credited with recovering several hundred thousand lost or stolen handsets by working with telecom operators and police in real time. If you're building for the Indian market, it's worth knowing this exists as a citizen reporting channel — it isn't a developer API, but it shapes what "spam" and "fraud" mean in the regulatory conversation around telecom data.

Troubleshooting common issues

Invalid-number errors on real numbers

Cause: missing or wrong country code context. Fix: always pass the expected default country to libphonenumber rather than assuming the international prefix is present.

Luhn check rejecting valid numbers

Cause: applying a checksum algorithm to a number format that was never designed to carry one. Fix: drop the Luhn check on phone numbers entirely; use format + library validation instead.

Missing carrier data

Cause: free libraries don't ship live carrier lookups. Fix: add Twilio Lookup or Numverify only for the flows that actually need carrier/line-type data.

Hitting free-tier rate limits

Cause: re-validating the same numbers repeatedly. Fix: cache validation results and re-check only on a sensible interval, not on every request.

Key takeaways

  • The Luhn/MOD10 checksum does not apply to telephone numbers — E.164 has no check digit. It's the right tool for IMEI, SIM ICCID, and card numbers, not the phone number field.
  • Format validation (libphonenumber) is free and should be the first layer for every number your system accepts.
  • Carrier, line-type, and fraud signals require a live API — Twilio Lookup and Numverify are the two most established options, at different price points.
  • GSMA Open Gateway's network-based verification removes OTP friction entirely, at the cost of narrower device/network coverage.
  • Match validation cost to risk — not every form field needs the most expensive layer.
Building a signup, KYC, or fraud-prevention flow that needs this right the first time? A short technical review of your validation stack usually surfaces the gaps fastest.