API reference
Verdicts describe reachability. They are not compliance checks.
Getting started
The API is JSON over HTTPS. Send a JSON body, read a JSON response.
Create an API key on the API keys page of your dashboard, then send it with every request as a bearer token. A new account comes with free credits and needs no card.
Base URL: https://numberlookup.io/v1
curl -X POST https://numberlookup.io/v1/phone \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"number": "+14155550132"}'Authentication
Send your key in the Authorization header: Authorization: Bearer nl_live_… . A key is shown once, when you create it. Revoke it from the API keys page and it stops working at once.
Keep keys on your server. The API sends no CORS headers, so a browser cannot call it with a key.
Send the number or address in the JSON body, never in the URL: URLs end up in proxy and platform logs.
Errors
Every error has the same shape:
{ "error": { "code": "missing_input", "message": "Send the number to check in the number field.", "request_id": "req_…" } }| code | HTTP status | When |
|---|---|---|
missing_api_key | 401 | No Authorization header was sent. |
invalid_api_key | 401 | The key is unknown or revoked, the header is not in the form Bearer <key>, or the account is disabled. |
insufficient_credits | 402 | The balance is below the cost of the check. The error object also carries credit_balance. |
invalid_body | 422 | The body is not a JSON object, is too large, or a field has the wrong type. |
missing_input | 422 | The number or ip field is missing or empty. |
invalid_country | 422 | country is not a two-letter country code in capitals, such as US. |
invalid_ip | 422 | ip is not an IPv4 or IPv6 address. |
rate_limited | 429 | Too many requests. The Retry-After header gives the wait in whole seconds. |
internal_error | 500 | Our fault. Quote the request_id when you contact us. |
No error is charged.
Rate limits
Each key has a limit in requests per second. GET /v1/account returns your plan's limit as plan.rate_limit_rps. An account without a plan has a default limit.
When the limit is reached you get a 429 with a Retry-After header. Wait that many seconds and send the request again.
Credits
A check costs 1 credit. These cost nothing: a result whose verdict is unknown, input that fails the format check (reason bad_format), a private or reserved IP address (reason reserved_range), and every error response.
A number whose exchange no carrier holds is invalid and costs 1 credit, because the answer comes from our own data.
Credits never expire. Every check response carries credits_used and credits_remaining.
Phone check
POST /v1/phone
Checks one phone number and returns whether it is valid, what kind of line it is, its carrier and a verdict.
Request body
| Field | Type | What it means |
|---|---|---|
number | string, required | The number, in any common format. Use E.164 (+14155550132) when you can. |
country | string, optional | The country to assume for a number written without a country code, as a two-letter code in capitals. Default US. |
Response
| Field | Type | What it means |
|---|---|---|
number_e164 | string | null | The number in E.164 format. null when it could not be read. |
valid | boolean | Whether the number can be a real one. |
country | string | null | The two-letter country code. |
region | string | null | The two-letter state or province code. null when we have none. |
line_type | string | null | mobile, fixed_line, voip, toll_free, fixed_line_or_mobile, premium_rate, shared_cost, personal_number, uan, pager or voicemail. null when unknown. |
carrier | string | null | The carrier that holds the number, as the data source names it. |
ported | boolean | null | Whether the number was moved between carriers. null when the data source does not say. |
voip | boolean | true for an internet (VoIP) number. Texting a VoIP number is unreliable. |
verdict | string | textable, callable, invalid or unknown. |
reason | string | Why. One of bad_format, outside_coverage, unassigned_exchange, upstream_unavailable, line_type_ambiguous, line_type_unknown or carrier_reports_invalid, or otherwise the line type. |
partial | boolean | true when our data source did not answer, so only the format and exchange checks were used. The verdict is then unknown and nothing is charged. |
credits_used | number | 0 or 1. |
credits_remaining | number | Your balance after this call. |
Verdicts
textableValid · Mobile | A mobile number. It can be called and texted. |
|---|---|
callableValid · Landline | A line that can be called: a landline, toll-free, VoIP and the other line types. A VoIP number also has voip set to true. |
invalidInvalid | Not a working number. |
unknownUnknown | We could not tell. Never charged. |
Verdicts describe reachability. They are not compliance checks.
curl -X POST https://numberlookup.io/v1/phone \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"number": "+14155550132"}'{
"number_e164": "+14155550132",
"valid": true,
"country": "US",
"region": "CA",
"line_type": "mobile",
"carrier": "Example Wireless",
"ported": false,
"voip": false,
"verdict": "textable",
"reason": "mobile",
"partial": false,
"credits_used": 1,
"credits_remaining": 999
}IP check
POST /v1/ip
Checks one IPv4 or IPv6 address and returns its country, its network and a risk level.
Request body
| Field | Type | What it means |
|---|---|---|
ip | string, required | An IPv4 or IPv6 address. |
Response
| Field | Type | What it means |
|---|---|---|
ip | string | The address that was checked. |
version | 4 | 6 | IPv4 or IPv6. |
country | string | null | The two-letter country code. There is no city. |
asn | string | null | The autonomous system number. |
as_name | string | null | The network's name. |
as_domain | string | null | The network's domain. |
tor | boolean | true when the address is a Tor exit node. |
datacenter | boolean | true when the address is in a published cloud or hosting range. |
risk | string | low, medium or high. |
reason | string | tor_exit, hosting_range, no_flags or reserved_range. |
credits_used | number | 0 or 1. |
credits_remaining | number | Your balance after this call. |
Risk levels
highHigh risk | The address is a Tor exit node. |
|---|---|
mediumMedium risk | The address is in a published cloud or hosting range. |
lowLow risk | Neither flag was found. A private or reserved address is low with the reason reserved_range, and is free. |
Verdicts describe reachability. They are not compliance checks.
IP address data is powered by IPinfocurl -X POST https://numberlookup.io/v1/ip \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"ip": "203.0.113.7"}'{
"ip": "203.0.113.7",
"version": 4,
"country": "US",
"asn": "AS64500",
"as_name": "Example Network",
"as_domain": "example.net",
"tor": false,
"datacenter": false,
"risk": "low",
"reason": "no_flags",
"credits_used": 1,
"credits_remaining": 998
}Account
GET /v1/account
Returns your balance and your plan. It costs nothing and takes no body.
plan is null when you have no plan.
curl https://numberlookup.io/v1/account \
-H "Authorization: Bearer YOUR_API_KEY"{ "credit_balance": 998, "plan": { "name": "Starter", "rate_limit_rps": 20 } }Coverage and limits
Phone
Live phone data covers the United States and Canada. A valid number anywhere else gets a format result with the verdict unknown and the reason outside_coverage. It costs nothing.
Carrier answers are cached, so a very recent change of carrier may not show yet.
We do not return who owns a number.
IP
IP data gives a country, never a city or a person.
The Tor and hosting flags come from published lists, not from what an address does.