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_…" } }
codeHTTP statusWhen
missing_api_key401No Authorization header was sent.
invalid_api_key401The key is unknown or revoked, the header is not in the form Bearer <key>, or the account is disabled.
insufficient_credits402The balance is below the cost of the check. The error object also carries credit_balance.
invalid_body422The body is not a JSON object, is too large, or a field has the wrong type.
missing_input422The number or ip field is missing or empty.
invalid_country422country is not a two-letter country code in capitals, such as US.
invalid_ip422ip is not an IPv4 or IPv6 address.
rate_limited429Too many requests. The Retry-After header gives the wait in whole seconds.
internal_error500Our 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

FieldTypeWhat it means
numberstring, requiredThe number, in any common format. Use E.164 (+14155550132) when you can.
countrystring, optionalThe country to assume for a number written without a country code, as a two-letter code in capitals. Default US.

Response

FieldTypeWhat it means
number_e164string | nullThe number in E.164 format. null when it could not be read.
validbooleanWhether the number can be a real one.
countrystring | nullThe two-letter country code.
regionstring | nullThe two-letter state or province code. null when we have none.
line_typestring | nullmobile, fixed_line, voip, toll_free, fixed_line_or_mobile, premium_rate, shared_cost, personal_number, uan, pager or voicemail. null when unknown.
carrierstring | nullThe carrier that holds the number, as the data source names it.
portedboolean | nullWhether the number was moved between carriers. null when the data source does not say.
voipbooleantrue for an internet (VoIP) number. Texting a VoIP number is unreliable.
verdictstringtextable, callable, invalid or unknown.
reasonstringWhy. 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.
partialbooleantrue 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_usednumber0 or 1.
credits_remainingnumberYour balance after this call.

Verdicts

textableValid · MobileA mobile number. It can be called and texted.
callableValid · LandlineA line that can be called: a landline, toll-free, VoIP and the other line types. A VoIP number also has voip set to true.
invalidInvalidNot a working number.
unknownUnknownWe 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

FieldTypeWhat it means
ipstring, requiredAn IPv4 or IPv6 address.

Response

FieldTypeWhat it means
ipstringThe address that was checked.
version4 | 6IPv4 or IPv6.
countrystring | nullThe two-letter country code. There is no city.
asnstring | nullThe autonomous system number.
as_namestring | nullThe network's name.
as_domainstring | nullThe network's domain.
torbooleantrue when the address is a Tor exit node.
datacenterbooleantrue when the address is in a published cloud or hosting range.
riskstringlow, medium or high.
reasonstringtor_exit, hosting_range, no_flags or reserved_range.
credits_usednumber0 or 1.
credits_remainingnumberYour balance after this call.

Risk levels

highHigh riskThe address is a Tor exit node.
mediumMedium riskThe address is in a published cloud or hosting range.
lowLow riskNeither 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 IPinfo
curl -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.