Phone Validation
Validate phone numbers globally. Detect carrier, country, number type, and VOIP or virtual risk using only phone metadata. No external lookups.
Overview
Use Cases
- User registration forms that require a valid phone number
- VOIP and virtual number screening before sending SMS or OTPs
- Normalising phone numbers before storing in a database
- Displaying consistently formatted numbers in a UI
Features
Validates any E.164 phone number globally
Detects country (ISO 3166-1 alpha-2 code)
Identifies number type (mobile, landline, toll-free, VoIP, and more)
Returns the internationally formatted number
Detects carrier name from phone prefix metadata
Flags VOIP and virtual numbers for risk screening
Batch validation for up to 50 numbers per request
API Endpoints
Validate Phone Number
Validates a single phone number and returns its country, type, formatted representation, carrier, and VOIP/virtual risk flags.
GET
https://api.requiems.xyz/v1/tech/validate/phone
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| number | string |
Required | The phone number to validate. Must include the country calling code (e.g. +12015551234). |
Try it out
Live DemoRequest
The phone number to validate. Must include the country calling code (e.g. +12015551234).
Sending request...
Response Fields
| Field | Type | Description |
|---|---|---|
| number | string |
The original number as supplied in the request |
| valid | boolean |
Whether the number is a valid, dialable phone number |
| country | string |
ISO 3166-1 alpha-2 country code (omitted when valid is false) |
| type | string |
Number type: mobile, landline, landline_or_mobile, toll_free, voip, premium_rate, shared_cost, personal_number, pager, uan, voicemail, or unknown (omitted when valid is false) |
| formatted | string |
International format of the number, e.g. +44 7400 123456 (omitted when valid is false) |
| carrier.name | string |
Carrier name from phone prefix metadata (omitted when carrier cannot be determined) |
| carrier.source | string |
How the carrier was determined. Always "metadata" when present |
| risk.is_voip | boolean |
true when the number type is voip |
| risk.is_virtual | boolean |
true when the number is not tied to a physical SIM or fixed line: voip, personal_number, uan, pager, or voicemail |
Code Examples
curl "https://api.requiems.xyz/v1/tech/validate/phone?number=%2B447400123456" \
-H "requiems-api-key: YOUR_API_KEY"
import requests
url = "https://api.requiems.xyz/v1/tech/validate/phone"
headers = {"requiems-api-key": "YOUR_API_KEY"}
params = {"number": "+447400123456"}
response = requests.get(url, headers=headers, params=params)
print(response.json())
const number = encodeURIComponent('+447400123456');
const response = await fetch(
`https://api.requiems.xyz/v1/tech/validate/phone?number=${number}`,
{ headers: { 'requiems-api-key': 'YOUR_API_KEY' } }
);
const { data } = await response.json();
console.log(data.valid, data.carrier, data.risk);
require 'net/http'
require 'json'
uri = URI('https://api.requiems.xyz/v1/tech/validate/phone')
uri.query = URI.encode_www_form(number: '+447400123456')
request = Net::HTTP::Get.new(uri)
request['requiems-api-key'] = 'YOUR_API_KEY'
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
data = JSON.parse(response.body)
puts data['data']['valid']
Error Responses
bad_request
The number query parameter is missing.
Batch Validate Phone Numbers
Validates up to 50 phone numbers in a single request. Results are returned in the same order as the input.
POST
https://api.requiems.xyz/v1/tech/validate/phone/batch
Parameters
| Name | Type | Required | Description |
|---|---|---|---|
| numbers | array |
Required | Array of phone numbers to validate (min: 1, max: 50). Each must include the country calling code. |
Try it out
Live DemoRequest
Enter JSON array, e.g., ["+447400123456", "+12015551234"]
Array of phone numbers to validate (min: 1, max: 50). Each must include the country calling code.
Sending request...
Response Fields
| Field | Type | Description |
|---|---|---|
| results | array |
Validation result for each number in the same order as the input. Each item has the same fields as the single validate endpoint. |
| total | integer |
Number of results returned. Matches the length of the input array. |
Code Examples
curl -X POST "https://api.requiems.xyz/v1/tech/validate/phone/batch" \
-H "requiems-api-key: YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"numbers":["+447400123456","+12015551234"]}'
import requests
url = "https://api.requiems.xyz/v1/tech/validate/phone/batch"
headers = {
"requiems-api-key": "YOUR_API_KEY",
"Content-Type": "application/json"
}
payload = {"numbers": ["+447400123456", "+12015551234"]}
response = requests.post(url, headers=headers, json=payload)
for result in response.json()["data"]["results"]:
print(result["number"], result["valid"])
const response = await fetch(
'https://api.requiems.xyz/v1/tech/validate/phone/batch',
{
method: 'POST',
headers: {
'requiems-api-key': 'YOUR_API_KEY',
'Content-Type': 'application/json'
},
body: JSON.stringify({ numbers: ['+447400123456', '+12015551234'] })
}
);
const { data } = await response.json();
data.results.forEach(r => console.log(r.number, r.valid));
require 'net/http'
require 'json'
uri = URI('https://api.requiems.xyz/v1/tech/validate/phone/batch')
request = Net::HTTP::Post.new(uri)
request['requiems-api-key'] = 'YOUR_API_KEY'
request['Content-Type'] = 'application/json'
request.body = { numbers: ['+447400123456', '+12015551234'] }.to_json
response = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) do |http|
http.request(request)
end
JSON.parse(response.body)['data']['results'].each do |r|
puts "#{r['number']}: #{r['valid']}"
end
Error Responses
validation_failed
The numbers array is missing, empty, or contains more than 50 items.
Frequently Asked Questions
Always include the country calling code prefixed with a plus sign (E.164 format), for example +12015551234 or +447400123456. Numbers without a country code cannot be validated reliably.
Some numbering plans (notably the United States) do not distinguish between mobile and landline numbers at the format level. When the type cannot be determined more precisely, the API returns landline_or_mobile.
The API returns HTTP 200 with valid set to false. The country, type, formatted, carrier, and risk fields are all omitted from that result.
No. Carrier detection relies on prefix metadata and coverage varies by country. When the carrier cannot be determined, the carrier object is omitted entirely.
VOIP and virtual flags come from the phone number type in libphonenumber metadata. No external lookups are made. A number is flagged as VOIP when its type is voip, and as virtual when its type is voip, personal_number, uan, pager, or voicemail.