One endpoint: send a phone number, get back whether it's real, which country and area it's from, what line type it is, and whether its prefix is currently associated with reported scams. JSON in, JSON out.
Every request needs an X-Api-Key header. Get a free key at /api/login - no credit card, no forms beyond an email address for the magic link.
X-Api-Key: dc_your_key
Requests without a valid key get 401 with {"error": "invalid_api_key"}.
GET /v1/phone/{number}
{number} is any phone number in international format. The leading + works as-is in the URL path - no encoding needed (%2B also accepted if your HTTP client encodes it). Numbers sent without the + (e.g. 13214991734) are parsed as international automatically. Numbers without enough digits, or that don't parse to a real dialing plan, return a valid: false result rather than an error.
$ curl https://dialcode.app/v1/phone/+639171234567 \
-H "X-Api-Key: dc_your_key"
{
"valid": true,
"e164": "+639171234567",
"country": { "code": "PH", "dial_code": "+63", "name": "Philippines" },
"line_type": "mobile",
"area": { "code": "917", "name": "Manila" },
"risk": {
"scam_risk": "high",
"scam_types": ["wangiri", "romance"],
"advice_url": "https://dialcode.app/scam/63-scam",
"complaints": null,
"signals": []
}
}
| Field | Type | Description |
|---|---|---|
valid | boolean | Whether the number parses as a real, dialable number. |
e164 | string | null | Normalized E.164 form. Null when valid is false. |
country.code | string | null | ISO 3166-1 alpha-2 country code (e.g. PH). |
country.dial_code | string | null | International dialing code (e.g. +63). |
country.name | string | null | Country name. |
line_type | string | null | Line type as detected by number parsing (e.g. mobile, fixed_line). |
area.code | string | null | Local area code, when the country has area-code data and one matches. |
area.name | string | null | City / region for the matched area code. |
risk.scam_risk | string | low, medium, or high - the country's overall scam risk rating. unknown when the number does not resolve to a country but a risk prefix matched (e.g. satellite ranges). |
risk.scam_types | array of strings | Scam patterns reported for this country (e.g. wangiri, romance). Empty array if none documented. |
risk.advice_url | string | null | Link to the full scam profile page for this country, when one exists. |
risk.complaints | object | null | FTC Do Not Call complaint history for this exact number. Present only for US numbers with at least one reported complaint; null for non-US numbers or numbers with no reports. Fields: total (int), robocalls (int, subset of total), first_reported_on / last_reported_on (date), source (string). |
risk.signals | array of objects | Risk signals detected for this specific number: {code, note} pairs from line-type, known scam prefix ranges, and FTC complaint history. Empty array if none detected. See signal codes below. |
Complaint data comes from the FTC's public Do Not Call registry CSVs, ingested daily (weekday publishing schedule - the FTC does not publish weekend files). US numbers only: the Do Not Call registry is a US program.
risk.signals entries come from two layers: line type (detected per-number) and known prefix ranges (detected from the dial code). A number can carry signals from both layers at once.
| Code | Layer | Meaning |
|---|---|---|
voip_line | line type | VoIP number: cheap to obtain anonymously, common in fraud and SMS-verification bypass. |
premium_rate_line | line type | Premium-rate number: calling it incurs elevated charges. |
shared_cost_line | line type | Shared-cost number: partial elevated charges apply. |
satellite_range | prefix | Satellite range (+870, +881): very high callback charges, classic wangiri bait. |
international_network_range | prefix | International network range (+882, +883): ITU non-geographic codes outside normal country dialing plans. |
premium_redirect_range | prefix | UK personal numbering range (+4470): missed-call redirect and premium forwarding. |
premium_rate_range | prefix | US 900 premium-rate range (+1900): calls billed at elevated per-minute rates. |
ftc_reported | complaints | US number reported to the FTC Do Not Call registry 3 or more times. |
| Status | error | Meaning |
|---|---|---|
| 401 | invalid_api_key | Missing or invalid X-Api-Key header. |
| 400 | unparseable_number | Input is too short (under 4 digits) to attempt a lookup. |
| 429 | quota_exceeded | Monthly quota used up for this key. |
| 429 | rate_limited | Per-minute rate limit exceeded, independent of the monthly quota. |
All errors return JSON: {"error": "invalid_api_key"}, {"error": "unparseable_number"}, {"error": "quota_exceeded"}, or {"error": "rate_limited"}.
curl https://dialcode.app/v1/phone/+639171234567 \ -H "X-Api-Key: dc_your_key"
const res = await fetch("https://dialcode.app/v1/phone/+639171234567", {
headers: { "X-Api-Key": "dc_your_key" }
});
const data = await res.json();
console.log(data.risk.scam_risk);
require "net/http"
require "json"
uri = URI("https://dialcode.app/v1/phone/+639171234567")
req = Net::HTTP::Get.new(uri)
req["X-Api-Key"] = "dc_your_key"
res = Net::HTTP.start(uri.host, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
puts data["risk"]["scam_risk"]