Phone validation that never leaves your servers.
Format, line type, carrier, region and time zone for any number in 240+ countries — checked in microseconds, with no number ever sent to a third party. Bundled free with Acuris address validation.
Try it right now
Paste any phone number below — in E.164 (+…) or national form — and we’ll show the full validation response in <1 second. No signup, no card, public widget endpoint.
Demo is IP rate-limited. For production, grab a 100-credit dev key and call /validate-phone with header X-Acuris-Key.
What each result means
Every field the check above returns, and what it tells you about the phone number you entered.
- verdict
- Our overall result. valid — the number matches a real, assigned range for its country and line type, safe to use. possible — the length and shape are plausible but the number isn’t in an allocated range yet, so treat as format-only. invalid — it can’t be a real number (too short/long, bad country code, garbage). unknown — input was empty or the validator was unavailable.
- score
- A 0–10 contactability score. 10 = a valid mobile; 8–9 = valid landline / fixed-or-mobile; 6–7 = valid but lower-trust line types (VoIP, toll-free, premium); 3 = possible only; 0–1 = invalid. Lets your code branch simply, e.g.
if score < 8: review. - valid
- Boolean — whether the number is valid for its region under the official numbering plan. The single most important field for gating.
- e164
- The number normalised to E.164 (
+<country><national>, e.g.+14155552671) — the canonical form to store and dial.internationalandnationalformats are returned too. - line_type
- What kind of line it is:
mobile,fixed_line,fixed_line_or_mobile,voip,toll_free,premium_rate,pager, and more. Drives whether SMS is even possible. - region
- The ISO‑3166 country the number belongs to (e.g.
US,DE) — derived from the number itself, not the caller’s guess. - carrier
- Best-effort original carrier from the numbering-plan block (e.g.
T-Mobile). Offline and block-level, so it’s the assigned carrier, not a live ported lookup — blank when unknown. - location
- A human-readable geographic description for the number (e.g.
San Francisco, CAorBerlin), where the plan supports it. - timezones
- The IANA time zone(s) the number maps to (e.g.
Europe/Berlin) — useful for send-time and call-window logic. - can_receive_sms
truewhen the line can receive SMS (mobile or fixed-or-mobile). Gate your OTP / text sends on this so you never burn a send on a landline.- tel_uri
- The number as an RFC 3966
tel:URI (tel:+1-415-555-2671) — drop straight into a click-to-call link. - is_premium_rate / is_toll_free
- Cost-class flags — a premium-rate or toll-free line where you might expect a normal mobile. Catches mis-entered or costly numbers.
- is_short_number / is_emergency
- The input is a short code (
112,999, …) or a known emergency number — usually junk in a contact field, so you can reject it with a clear reason. - national_number / area_code
- The national significant number (digits after the country code) and, where the plan has one, the area / destination code — handy for routing and analytics.
- is_vanity
- The input contained letters (e.g.
1-800-FLOWERS); we convert it to digits before validating. - valid_for_input_region / short_number_cost
- If you passed a region, whether the number is actually valid for that country (
false= it belongs elsewhere). For short codes, the cost class:toll_free/standard_rate/premium_rate. - dialling
- When you pass
dial_from, how to dial this number from that country (e.g. a US number from DE →00 1 415-555-2671). - is_possible
- Whether the number is even a plausible length/shape for its region — a cheaper pre-check than full validity.
- reasons
- Machine-readable codes behind the verdict (e.g.
too_short,invalid_country_code,not_in_assigned_range,no_default_region) — for your code to act on programmatically.
What this checks — and what it doesn’t
Honesty first: this is Tier 1 validation — everything is computed offline from the global numbering plan, with no network call and no per-lookup cost. It confirms a number is well-formed and valid; it does not place a call or check whether the handset is switched on right now. Here’s exactly where the line sits.
| What you get (offline, Tier 1) | What needs a live add-on (Tier 3) |
|---|---|
| ✅ Valid for region & numbering plan | ☎️ Live reachability / HLR (is it switched on now) |
| ✅ E.164 + international + national formats | 📲 Current carrier after a port (real-time MNP) |
| ✅ Line type (mobile / landline / VoIP / …) | 🪪 Caller name (CNAM) lookup |
| ✅ Region, geo description, time zone(s) | 🚩 Fraud / SIM-swap / disposable-number scoring |
| ✅ Assigned (block-level) carrier, 240+ countries | — |
Why offline-only? Tier 1 catches the overwhelming majority of bad data at point of entry — typos, wrong country, impossible lengths, landlines typed into a “mobile” field — with zero latency, zero per-call cost, and no PII leaving your stack. That’s what most address-validation buyers actually need, and unlike the big suites we don’t bill it as a separate SKU.
Need live reachability? HLR / active-line lookups require a telecom-data relationship and carry a real per-lookup cost, so they ship as a paid add-on rather than being baked into the free bundle. Talk to us if you need it.
Every check, every number, every time
E.164 normalisation
Any input — spaces, dashes, parentheses, national or international — comes back as a clean +<cc><nsn> string to store and dial.
Numbering-plan validity
Confirms the number is actually assigned for its region, not just plausible — checked against the official global numbering plan.
Line-type detection
mobile / fixed_line / VoIP / toll_free / premium — so you only SMS numbers that can actually receive one.
Carrier (offline)
Assigned, block-level carrier from the numbering plan (e.g. T-Mobile) — no network call, no per-lookup fee.
Region & geo
ISO country plus a human-readable location (San Francisco, CA · Berlin), derived from the number itself.
Time zones
IANA zone(s) for the number — drive send-time windows and respect quiet hours automatically.
240+ countries
One API, the whole world. Pass a default region for national-format numbers; E.164 inputs need nothing.
0–10 score
Single numeric contactability score so your code can if score < 8: review. Sortable, comparable.
Where teams put it to work
Checkout & signup forms
Catch a mistyped or wrong-country number the moment it’s entered, and store it normalised to E.164 — so the “out for delivery” SMS actually reaches the customer instead of bouncing.
OTP & 2FA send-gating
Before firing a one-time passcode, confirm the line is a mobile. Landlines and many VoIP numbers can’t receive SMS — skip them or fall back to voice instead of burning a send and stalling the login.
CRM & list hygiene
Bulk-validate an imported contact list: drop impossible numbers, normalise everyone to E.164, and flag landlines sitting in a “mobile” column — before you pay to message any of them.
Compliant outbound dialling
Use each number’s region and time zone to schedule calls inside the contact’s local business hours — respecting quiet-hours rules — and route every lead to the right regional team.
Cheap fraud first-filter
Reject obviously bogus numbers at registration — wrong country code, impossible length, a premium-rate line where you expected a mobile — a zero-cost first pass before you pay for a reachability or risk lookup.
WhatsApp & messaging onboarding
Messaging APIs demand clean E.164 mobile numbers. Validate and normalise before adding a contact to a WhatsApp Business, RCS or SMS audience, so the broadcast doesn’t silently drop recipients.
Three lines, any language
A one-line curl, or the same call straight from Node and Python — clean JSON, identical on every tier.
curl -X POST 'https://api.acuris-geo.com/validate-phone' \
-H 'X-Acuris-Key: YOUR_KEY' \
-H 'Content-Type: application/json' \
-d '{"phone": "+1 415 555 2671"}'
# → {
# "phone": "+1 415 555 2671",
# "verdict": "valid",
# "score": 9,
# "e164": "+14155552671",
# "line_type": "fixed_line_or_mobile",
# "region": "US",
# "location": "San Francisco, CA"
# }const res = await fetch("https://api.acuris-geo.com/validate-phone", {
method: "POST",
headers: { "X-Acuris-Key": process.env.ACURIS_API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ phone: "+1 415 555 2671" }),
});
const r = await res.json();
console.log(r.verdict, r.score, r.e164, r.line_type);
// → "valid" 9 "+14155552671" "fixed_line_or_mobile"import os, requests
r = requests.post(
"https://api.acuris-geo.com/validate-phone",
headers={"X-Acuris-Key": os.environ["ACURIS_API_KEY"]},
json={"phone": "+1 415 555 2671"},
).json()
print(r["verdict"], r["score"], r["e164"], r["line_type"])
# → valid 9 +14155552671 fixed_line_or_mobileBundled free into every Acuris plan
Phone validation has its own credit pool, sized to match your address-validation quota — buy an address plan, get phone validation at no extra charge. 1,000 free on the Dev trial; your monthly address volume, mirrored, on Growth and Pro. The big suites bill this as a separate SKU; we don’t.