Phone Validation¶
2 endpoints for parsing and validating phone numbers in any format, with carrier and line-type detection.
| Endpoint | Purpose |
|---|---|
GET /v1/geo/phone-validate |
Validate a single phone number; returns E.164, carrier, line type |
POST /v1/geo/phone-validate-batch |
Validate up to 50 numbers in one request |
Python SDK Examples¶
Validate a single phone number¶
phone_validate parses a number in any national or international format and validates it against E.164 rules using the phonenumbers library (Google libphonenumber).
from toolkitapi import Geo
with Geo(api_key="tk_...") as geo:
result = geo.phone_validate("(212) 555-0100", country="US")
print(result["valid"]) # True
print(result["e164"]) # "+12125550100"
print(result["national"]) # "(212) 555-0100"
print(result["international"]) # "+1 212-555-0100"
print(result["country_code"]) # 1
print(result["country"]) # "US"
print(result["line_type"]) # "fixed_line"
print(result["carrier"]) # "Verizon" (or None if unknown)
Validate phone numbers from multiple countries¶
from toolkitapi import Geo
test_numbers = [
("+44 20 7946 0958", "GB"), # UK London number
("+49 30 1234567", "DE"), # German Berlin number
("+81 3-1234-5678", "JP"), # Japanese Tokyo number
("+61 2 9876 5432", "AU"), # Australian Sydney number
("07700 900123", "GB"), # UK mobile (no country prefix)
("not-a-number", "US"), # Invalid
]
with Geo(api_key="tk_...") as geo:
for number, country in test_numbers:
result = geo.phone_validate(number, country=country)
status = "✓" if result["valid"] else "✗"
e164 = result.get("e164", "—")
line = result.get("line_type", "—")
print(f"{status} {number:25} → {e164:18} [{line}]")
Output:
✓ +44 20 7946 0958 → +442079460958 [fixed_line]
✓ +49 30 1234567 → +493012345670 [fixed_line]
✓ +81 3-1234-5678 → +81312345678 [fixed_line]
✓ +61 2 9876 5432 → +61298765432 [fixed_line]
✓ 07700 900123 → +447700900123 [mobile]
✗ not-a-number → — [—]
Validate and normalise a phone field on form submission¶
from toolkitapi import Geo
def normalise_phone(raw_input: str, default_country: str = "US") -> str | None:
"""Return E.164 format or None if the number is invalid."""
with Geo(api_key="tk_...") as geo:
result = geo.phone_validate(raw_input, country=default_country)
return result["e164"] if result["valid"] else None
# Examples
print(normalise_phone("212-555-0100")) # "+12125550100"
print(normalise_phone("07700 900123", "GB")) # "+447700900123"
print(normalise_phone("abc")) # None
Batch validation¶
phone_validate_batch accepts up to 50 numbers and returns individual results plus a validation summary:
from toolkitapi import Geo
numbers = [
"+12125550100",
"+44 20 7946 0958",
"not-valid",
"+81 3-1234-5678",
"+61 2 9876 5432",
"000",
]
with Geo(api_key="tk_...") as geo:
response = geo.phone_validate_batch(numbers, default_country="US")
print(f"Total: {response['summary']['total']}")
print(f"Valid: {response['summary']['valid']}")
print(f"Invalid: {response['summary']['invalid']}")
print(f"Line types: {response['summary']['line_types']}")
for r in response["results"]:
status = "✓" if r["valid"] else "✗"
print(f" {status} {r['input']:20} → {r.get('e164', '—')}")
Clean a CSV of phone numbers¶
import csv
from toolkitapi import Geo
def clean_phone_csv(input_path: str, output_path: str, default_country: str = "US") -> None:
"""Read a CSV with a 'phone' column, validate, and write E.164 output."""
with open(input_path, newline="") as f:
rows = list(csv.DictReader(f))
numbers = [row["phone"] for row in rows]
# Process in chunks of 50 (API limit)
results = []
with Geo(api_key="tk_...") as geo:
for i in range(0, len(numbers), 50):
batch = numbers[i:i + 50]
response = geo.phone_validate_batch(batch, default_country=default_country)
results.extend(response["results"])
for row, result in zip(rows, results):
row["phone_e164"] = result.get("e164") or ""
row["phone_valid"] = result["valid"]
row["phone_line_type"] = result.get("line_type") or ""
fieldnames = list(rows[0].keys())
with open(output_path, "w", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(rows)
Filter out non-mobile numbers¶
from toolkitapi import Geo
leads = [
"+12125550100",
"+447700900123",
"+14155552671",
"+441632960961",
]
with Geo(api_key="tk_...") as geo:
response = geo.phone_validate_batch(leads)
mobile_only = [
r["e164"]
for r in response["results"]
if r["valid"] and r.get("line_type") in ("mobile", "fixed_line_or_mobile")
]
print("Mobile numbers:", mobile_only)
Response Fields¶
phone-validate response:
| Field | Type | Description |
|---|---|---|
input |
string | Original input |
valid |
bool | Whether the number is valid |
e164 |
string | null | E.164 formatted number (e.g. +12125550100) |
national |
string | null | National format (e.g. (212) 555-0100) |
international |
string | null | International format |
country_code |
int | null | Numeric country dialling code |
country |
string | null | ISO 3166-1 alpha-2 country code |
region |
string | null | Geographic description (city/state) |
carrier |
string | null | Carrier name if known |
line_type |
string | null | mobile, fixed_line, voip, toll_free, etc. |
phone-validate-batch response:
| Field | Type | Description |
|---|---|---|
total |
int | Number of numbers submitted |
results |
list | Per-number result objects (same fields as single validate) |
summary.valid |
int | Count of valid numbers |
summary.invalid |
int | Count of invalid numbers |
summary.line_types |
object | Counts grouped by line type |
Tip
Always store phone numbers in E.164 format (+12125550100) rather than whatever the user typed. E.164 is unambiguous, sortable, and works with SMS and voice APIs without additional formatting. Use phone_validate on input, store e164, and only convert back to national format for display.