Phone Number Validator API - E.164, Line Type & Risk Flags avatar

Phone Number Validator API - E.164, Line Type & Risk Flags

Pricing

Pay per usage

Go to Apify Store
Phone Number Validator API - E.164, Line Type & Risk Flags

Phone Number Validator API - E.164, Line Type & Risk Flags

Validate and normalize phone numbers. Returns E.164, national/international format, country, calling code, line type, tel URI, and risk flags. Invalid rows are free.

Pricing

Pay per usage

Rating

0.0

(0)

Developer

George Kioko

George Kioko

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

6 days ago

Last modified

Share

Validate and normalize phone numbers at scale. Give it a single number or a list of up to 100, and get back clean E.164, the country, the international and national formats, the line type, a tel: URI, and deterministic risk flags. Invalid and unparsable rows are returned for free; only valid keepers are billed.

Validation is fully offline and deterministic, backed by Google's libphonenumber metadata through libphonenumber-js. No accounts, no keys, no scraping.

How it works

flowchart LR
A[Standby API call<br/>or batch input] --> B[Normalize input<br/>strip spaces, parse with<br/>defaultCountry hint]
B --> C[Validate with<br/>libphonenumber-js]
C --> D{Valid?}
D -- no --> E[Return row<br/>valid=false + reason<br/>FREE, not charged]
D -- yes --> F[Derive E.164, formats,<br/>country, line type,<br/>risk flags]
F --> G[Actor.charge<br/>phone-number-validated]
E --> H[Dataset row<br/>or JSON response]
G --> H
sequenceDiagram
participant Client
participant Standby as Standby URL
participant Actor
participant Lib as libphonenumber-js
Client->>Standby: GET /lookup?phoneNumber=...
Standby->>Actor: route request
Actor->>Lib: parse + validate
Lib-->>Actor: valid / line type / formats
alt number is valid
Actor->>Actor: Actor.charge("phone-number-validated")
else invalid or unparsable
Note over Actor: no charge (free)
end
Actor-->>Client: JSON result

What it does

  • Normalizes any input to E.164 (+12133734253) when the number is valid
  • Returns national and international display formats
  • Detects country (ISO 3166 alpha-2) and country calling code
  • Reports line type when the metadata supports it (MOBILE, FIXED_LINE, TOLL_FREE, PREMIUM_RATE, VOIP, ...)
  • Emits a tel: URI for click-to-call
  • Adds deterministic risk flags inferred from validity, possibility, and line type
  • Cleans bulk lead lists: invalid and unparsable rows are returned for free

What it does NOT do (yet)

This is honest about its scope. v1 is a validation and normalization API. It does not:

  • Perform paid HLR / network carrier lookups
  • Scrape Truecaller or any consumer caller-ID app
  • Return the real carrier name or the number's timezone

For that reason carrier and timezone are always returned as null, each with an explicit status field (carrierLookupStatus: "not_configured", timezoneLookupStatus: "not_available_offline"). The output shape is stable, so a future optional paid-provider integration can fill those fields without breaking your code. We will not fake carrier data.

Modes

1. Standby API (real-time)

Leave the input empty and call the Actor as an HTTP service.

MethodPathDescription
GET/ or /healthService metadata and endpoint list
GET/lookup?phoneNumber=...&defaultCountry=USValidate one number
POST/lookupValidate one number (JSON body)
POST/lookup-batchValidate up to 100 numbers (JSON body)

CORS is enabled and every response is JSON. 400 for bad or missing input, 404 for unknown routes, 500 for unexpected errors.

Example: GET single lookup

$curl "https://<your-standby-url>/lookup?phoneNumber=%2B447400123456"

Example: POST single lookup

curl -X POST https://<your-standby-url>/lookup \
-H "Content-Type: application/json" \
-d '{"phoneNumber":"(213) 373-4253","defaultCountry":"US","includeRiskSignals":true}'

Example: POST batch (max 100)

curl -X POST https://<your-standby-url>/lookup-batch \
-H "Content-Type: application/json" \
-d '{"phoneNumbers":["+12133734253","07400 123456","not a phone"],"defaultCountry":"GB"}'

2. Batch Actor

Run it with input. Provide either a single phoneNumber or a phoneNumbers array (up to 100). One dataset row is pushed per number, in input order. Export as JSON, CSV, or Excel from the dataset.

{
"phoneNumbers": ["+12133734253", "07400 123456", "not a phone number"],
"defaultCountry": "GB",
"includeRiskSignals": true
}

Input

FieldTypeDefaultDescription
phoneNumberstring+12133734253Single number. E.164 or national format with a defaultCountry hint.
phoneNumbersstring[]noneBulk list, max 100. Takes precedence over phoneNumber.
defaultCountrystringUSISO 3166-1 alpha-2 code used to parse national-format numbers. Ignored for +E.164 input.
includeRiskSignalsbooleantrueAttach risk flags to each result.

Output

One object per number:

{
"input": "07400 123456",
"valid": true,
"isPossible": true,
"e164": "+447400123456",
"nationalFormat": "07400 123456",
"internationalFormat": "+44 7400 123456",
"uri": "tel:+447400123456",
"countryCode": "GB",
"countryCallingCode": "44",
"lineType": "MOBILE",
"carrier": null,
"carrierLookupStatus": "not_configured",
"timezone": null,
"timezoneLookupStatus": "not_available_offline",
"riskFlags": [],
"riskScore": 0,
"confidence": "high",
"reason": "Valid phone number",
"error": null
}

Risk flags

Risk flags are derived only from validation facts, so they are reproducible:

FlagMeaning
invalidThe number is not valid for any region.
not_possibleThe length or pattern can't be a real number.
possible_not_validRight length, but not a valid number for any region.
unparsableCould not be parsed at all (empty or non-numeric).
premium_ratePremium-rate line type (PREMIUM_RATE).
voipVoIP line type.
pagerPager line type.
shared_costShared-cost line type.

confidence is high for valid numbers, medium for possible-but-invalid, and low for not-possible or unparsable.

Pricing

Pay per event:

  • Current Apify scheduled price: phone-number-validated - $0.003 per valid number returned.
  • Recommended next price after Apify's pricing cooldown: $0.004 per valid number returned.

Only valid numbers are billed. Invalid, unparsable, and possible-but-invalid rows are returned for free, so cleaning a noisy lead list never costs more than the keepers it produces.

Apify currently blocks another pricing modification until 2026-07-16 because this Actor's first pricing record was just created. The table below shows the recommended next price once the cooldown allows it.

Valid numbersCost at $0.004
100$0.40
1,000$4.00
10,000$40.00

A batch of 100 with 80 valid numbers costs $0.32 (the 20 bad rows are free).

Competitor price positioning

Surveyed against the live Apify Store on 2026-06-17. The honest comparison set is split into two groups: cheap offline libphonenumber validators and higher-priced phone-intelligence APIs that add HLR, carrier, owner, fraud, or messaging signals. This Actor is a clean validation/normalization API, so the target price stays below the intelligence tier and below EasyAPI while charging only for valid rows.

ActorPer-number priceWhat you get
khadinakbar/phone-number-lookup-api$0.025Phone intelligence: HLR carrier, owner/CNAM, fraud score, breach data, WhatsApp/Telegram
easyapi/phone-number-validation~$0.00499 ($4.99 per 1,000)Validation, parse, type, location, formats
george.the.developer/phone-number-validatorcurrent $0.003; target $0.004 valid onlyE.164, formats, country, line type, deterministic risk flags. Invalid rows free.
zhorex/phone-number-validator~$0.002 ($2.00 per 1,000)Offline libphonenumber validation, timezone/location, carrier where metadata supports it
junipr/phone-number-validator~$0.0013 ($1.30 per 1,000)Validation, formats, line type, region, carrier/location claims

Why $0.004, not $0.0075:

  • $0.0075 would be too high for v1 because this Actor does not return live HLR, real carrier, owner, fraud, SIM, WhatsApp, or Telegram data.
  • $0.004 is still a 33% lift over the current $0.003 price while staying below EasyAPI and far below phone-intelligence APIs.
  • On a noisy list with 65% valid numbers, $0.004 per valid result works out to about $2.60 per 1,000 input rows because the invalid 35% is free.
  • The premium over cheaper offline peers is justified by valid-only billing, a real-time Standby API, batch mode, and deterministic risk flags.

Why pay more than the cheapest offline validator:

  • You pay only for valid rows, not every input row.
  • You can call it as a real-time HTTP Standby API or as a batch Actor.
  • The output is honest: no fake carrier, timezone, HLR, or owner data.
  • Risk flags are deterministic and reproducible for lead-list cleaning.
flowchart LR
subgraph INTEL["Intelligence tier: $0.015 to $0.025"]
A1[HLR carrier / owner<br/>fraud / messaging signals]
end
subgraph OURS["This actor: target $0.004"]
B1[Offline validation<br/>valid-only billing<br/>Standby API + risk flags]
end
subgraph OFFLINE["Offline peers: $0.0013 to $0.002"]
C1[Per-result validation<br/>usually all rows billed]
end
A1 -. richer data, higher price .-> B1
B1 -. pay only for keepers .-> C1

Notes on line type and country

lineType comes from the bundled metadata and may be null for some countries even when the number is valid. Country detection can also be null for numbers that are possible but not assigned to a specific region. Both are reported honestly rather than guessed.

Limitations

  • No real carrier name or timezone in v1 (see "What it does NOT do").
  • Line type availability varies by country.
  • Validation reflects numbering-plan rules, not whether a number is currently active on a network. That requires a paid HLR lookup, which is out of scope for v1.