UK phone number validation looks simple until you try to do it properly. A naive regex catches obvious garbage but passes 070 personal numbers as mobile, accepts 056 VoIP ranges your OTP provider cannot reach, and silently accepts numbers that are structurally valid but unallocated. This guide explains the UK numbering plan, provides production-ready regex patterns, and shows how to use an API to validate real-world usability.

The UK phone numbering plan — a developer field guide

This is the most important section.

PrefixTypeDigitsDescriptionDeveloper Notes
01, 02Geographic landline10–11Area-based numbersVarying area codes
03Non-geographic11Same cost as landlineSafe for OTP
055Corporate VoIP11Enterprise blocksRare
056VoIP11Internet-based No SMS
070Personal numbers11Call forwarding⚠️ Scam risk
071–075, 077–079Mobile11Standard mobileSMS supported
076Pager11Legacy pagingIgnore
0800, 0808Freephone11Free to call No OTP
084, 087Special rate11Paid serviceReject
09Premium11High costReject

Critical rule (MOST IMPORTANT)

070 is NOT a mobile prefix.
It looks like 07 but:

  • cannot reliably receive SMS
  • often used in fraud

👉 Always validate sub-ranges, not just “starts with 07”.

UK phone number format rules — the things regex gets wrong

E.164 international format vs national format

FormatExample
National07700 900123
E.164+447700900123

Always store in E.164

Python: Convert to E.164

import re

def to_e164_uk(number: str) -> str | None:
    digits = re.sub(r"\D", "", number)

    if digits.startswith("44") and len(digits) == 12:
        return "+" + digits

    if digits.startswith("0") and len(digits) == 11:
        return "+44" + digits[1:]

    return None

Length rules by number type

TypeTotal DigitsExample
London11020 7946 0958
Mobile1107700 900123
Landline1101632 960123
Non-geographic110300 123 4567

👉 Rule: 99% of UK numbers = 11 digits

Format validation — regex patterns by number type

Python Implementation

import re

def clean(n: str) -> str:
    return re.sub(r"[\s\-\(\)\.]", "", n)

PATTERNS = {
    "mobile": re.compile(r"^(\+44|0)7([1-9]\d{2}|624)\d{6}$"),
    "personal_070": re.compile(r"^(\+44|0)70\d{8}$"),
    "landline": re.compile(r"^(\+44|0)[12]\d{9}$"),
    "national_03": re.compile(r"^(\+44|0)3\d{9}$"),
    "voip": re.compile(r"^(\+44|0)56\d{8}$"),
    "freephone": re.compile(r"^(\+44|0)80[08]\d{7}$"),
    "special": re.compile(r"^(\+44|0)8[47]\d{8}$"),
    "premium": re.compile(r"^(\+44|0)9\d{9}$"),
}

def classify(number):
    n = clean(number)
    for t, p in PATTERNS.items():
        if p.match(n):
            return {"valid": True, "type": t}
    return {"valid": False}

⚠️ Important

Regex validates format only — NOT real-world validity.
➡️ For live status, use API (next section)

CTA (Mid Article)

👉 Start validating UK numbers in production:

Free tier: 500 requests/month (no card required)

Live validation via API — beyond format checking

Regex cannot tell:

  • if number exists
  • if SIM is active
  • if it can receive SMS

Python API Example

import requests

API_KEY = "your_api_key"

def validate_phone(number):
    resp = requests.get(
        "https://phone.apitier.com/v1/phone/validate",
        params={
            "phoneNumber": number,
            "countryCode": "GB",
            "x-api-key": API_KEY
        }
    )
    return resp.json()

Node.js Example

const axios = require("axios");

async function validate(number) {
  const res = await axios.get(
    "https://phone.apitier.com/v1/phone/validate",
    {
      params: {
        phoneNumber: number,
        countryCode: "GB",
        "x-api-key": "your_key"
      }
    }
  );
  return res.data;
}

curl Example

curl "https://phone.apitier.com/v1/phone/validate?phoneNumber=%2B447700900123&countryCode=GB&x-api-key=your_key"

API response fields explained

FieldMeaningAction
validFormat + allocationReject if false
lineTypemobile, voip, etcFilter
carrierNetworkRouting
liveStatusactive/inactiveOTP decision
internationalFormat+44 formatStore
localFormat07 formatDisplay

Four real-world use cases

1. Signup form

  • Accept: mobile, landline
  • Reject: premium, voip, 070

2. OTP verification

  • Only mobile
  • Must be active

3. CRM cleaning

  • Normalize to E.164
  • Remove inactive

4. Fraud detection

Red flags:

  • VoIP
  • 070 numbers
  • inactive SIM

Five gotchas that break UK validation

  1. 070 ≠ mobile
  2. 056 = VoIP
  3. London = 3-digit code (020)
  4. Always store E.164
  5. Carrier ≠ original network

Frequently Asked Questions

How many digits does a UK mobile number have?

11 digits (national) or +44 + 10 digits (E.164)

What is difference between 07 and 070?

07 = mobile
070 = personal forwarding (NOT mobile)

Can I validate without API?

Yes (regex), but no live status

What format should I store?

E.164 (+447700900123)

Are 0800 numbers valid?

Yes, but NOT for OTP

JSON-LD FAQ Schema

{
"@context": "https://schema.org",
"@type": "FAQPage",
"mainEntity": [
{
"@type": "Question",
"name": "How many digits does a UK mobile number have?",
"acceptedAnswer": {
"@type": "Answer",
"text": "UK mobile numbers have 11 digits in national format and 12 characters in E.164 format."
}
},
{
"@type": "Question",
"name": "What is the difference between 07 and 070 numbers?",
"acceptedAnswer": {
"@type": "Answer",
"text": "07 is mobile, 070 is personal forwarding and not suitable for SMS."
}
}
]
}

Final Thoughts

Ready to validate UK phone numbers properly?

👉 Get started now:

500 free API calls/month
No credit card
Supports mobile, landline, VoIP detection