Support Portal Sign-in
Start here

Quickstart — your first lookup in 5 minutes

Make a free test lookup right now. No account, no charges, no real phone networks touched.

  1. Use the test credentials

    Point at the testing endpoint with the shared test key. Test lookups are free.

    Endpoint:    https://testing.hlrlookup.com/apiv2/hlr
    api_key:     speedtest
    api_secret:  speedtest
  2. Make a request

    Pick your language:

  3. Read the result

    You'll get JSON back. The field that matters most is live_status:

    "live_status": "LIVE"

    That's it — the number is active and reachable. See what every live_status value means →

  4. Go to production

    Swap the URL to https://api.hlrlookup.com/apiv2/hlr and use your real key and secret from portal.hlrlookup.com. Nothing else changes.

💬 Stuck?Our UK-based team will review your integration code for free — support@hlrlookup.com (Mon–Fri, 9am–5pm UK).
Start here

Understanding the response

Every successful lookup returns JSON. Three fields do most of the work — here's the shape of a response and where to look.

{
  "body": {
    "results": [
      {
        "error": "NONE",
        "uuid": "4562ab7e-af26-4d42-87a0-b84bb4e5f96c",
        "credits_spent": 1,
        "detected_telephone_number": "447540822872",
        "live_status": "LIVE",                 // ← is it active & reachable?
        "telephone_number_type": "MOBILE",     // ← mobile, landline, VoIP…
        "current_network_details": {           // ← which network, right now
          "name": "EE Limited (T-Mobile)",
          "mccmnc": "23430",
          "country_iso3": "GBR"
        },
        "is_ported": "YES",
        "timestamp": "2022-10-07T13:06:15Z"
      }
    ]
  }
}

The three fields most customers use

live_status — is this number active and reachable? Most business logic hangs off this one field.

telephone_number_type — mobile, landline, VoIP, premium and more. Use it to route calls or exclude non-SMS numbers.

current_network_details — the network the number is on today, including after porting. Useful for routing and least-cost decisions.

Two rules that will save you an integration headache

1. JSON is unordered. Never rely on fields appearing in the same order — parse by field name.

2. We add fields, we never change them. New features arrive as new response fields, so upgrades never break your integration. Anything that costs extra is opt-in (like get_ported_date) — you must ask for it in your request.

Matching responses to requests

Sending multiple numbers in one request? Use request_parameters.telephone_number in each result to match it back to what you submitted. Every result also carries a unique uuid.

Full field-by-field reference →

Reference

live_status values

live_status tells you whether a phone number is real, active and reachable right now. It's always an UPPERCASE string — match it exactly.

LIVEActive and reachable — safe to call or SMSKeep it ✓

This telephone number is live and is assigned to a subscriber who has recently used their telephone.

What to do: treat this number as good data. Safe to call or send SMS.
DEADConfirmed inactive by the network — will not receive calls or SMSRemove it ✗

This telephone number has been confirmed to be a dead telephone number by the telephone network and will not receive telephone calls or text messages because the telephone number is not assigned to an existing SIM card or user.

What to do: remove it from your database or campaign list. Messaging dead numbers wastes money and damages sender reputation.
ABSENT_SUBSCRIBERReal number, but currently unreachableRetry later ↻

This telephone number is assigned to a mobile SIM card, but either:

  1. There has been a prolonged period of inactivity from the mobile handset
  2. The mobile phone has been turned off, or gone out of radio coverage, and someone has attempted to call or send an SMS to the telephone number
  3. The number is allocated to a new SIM card and the SIM card has not yet been registered to a user
What to do: don't delete it — this is usually a real number. Re-check after a few days. Numbers that stay ABSENT_SUBSCRIBER across several checks over weeks are less likely to come back.
NO_TELESERVICE_PROVISIONEDActive, but the subscription can't receive SMSCall, don't text ☎

If the mobile subscription identified by the given phone number does not include the short message service, the teleservice not provisioned error is returned. This means that the number is active in the HLR database for that network, but the user is not able to receive SMS messages.

What to do: treat as live for voice calls, but exclude from SMS campaigns — messages won't be delivered.
INCONCLUSIVECouldn't get a definitive answer this timeRetry later ↻

We were currently unable to ascertain the status for this number.

What to do: retry later. If a number is repeatedly INCONCLUSIVE, contact support@hlrlookup.com and we'll investigate the route.
NOT_AVAILABLE_NETWORK_ONLYThis network doesn't share live/dead status — porting info onlyUse network data

The telephone network who owns the telephone number does not provide Live/Dead type status, but will provide porting information if the telephone number has been ported to another network.

What to do: use current_network and is_ported from the same response — they're still accurate. The Coverage Checker shows which networks fall into this category.
NO_COVERAGEWe can't check this network — you are not chargedFree result

We do not currently have coverage to detect the live status for this telephone network. You are not charged for a NO_COVERAGE result.

What to do: check the Coverage Checker before running large batches for a country — our coverage changes regularly.
NOT_APPLICABLENo valid phone number detected in your inputFix the input

Used if there is no detected telephone number. You'll usually see telephone_number_type: "BAD_FORMAT" alongside this.

What to do: check the input format. See Number Formatting — Input.
💡 TipBuilding list-cleaning logic? A simple rule that works for most customers: keep LIVE, remove DEAD, re-queue ABSENT_SUBSCRIBER and INCONCLUSIVE for a second pass in 3–7 days.
Reference

telephone_number_type values

What kind of number is it? Use this field to route calls, exclude non-SMS numbers, or spot premium-rate traps. The example numbers are real test values — use them to test your handling of each type.

ValueExample / test numberWhat it means
MOBILE447540822872A phone number assigned to a Mobile Telephone Operator / Cell Phone Operator
LANDLINE441133910781A fixed wired telephone in a fixed location such as home or office
MOBILE_OR_LANDLINE917795519731Where the telephone number could belong to either a mobile or landline type phone
VOIP6531522665Assigned to a VoIP provider who delivers calls and text messages over the internet to the end user or service
TOLL_FREE818000804085Also called Freephone. The number can be called from within the home country at no cost. There may be a charge to call this number from outside the home country
PREMIUM448719429222There is a premium charge added to call this number, often there is a service provided on the number and by calling the number the user pays for the service using their telephone bill. The callee typically receives revenue from the call
SHARED_COST420844844850This telephone number will charge both the caller and callee at the same time. There will be an additional charge to call this type of number
PERSONAL_NUMBER543876478000A telephone number intended to be used by individuals which may route to multiple locations (home, office and cell phone). Some PERSONAL_NUMBERs are charged at a PREMIUM number rate
UNIVERSAL_ACCESS_NUMBER443332022222A single telephone number which can be used to route calls to multiple destinations depending on parameters such as time of day, where the caller resides, capacity or more. This is not linked to any specific locality within the country. Typically used by companies to provide a single telephone number instead of multiple telephone numbers
STAGE_AND_SCREENReserved by a regulatory body specifically for use with stage and screen for example used in films when speaking a telephone number. No real end user will be assigned to this number and often they are used as fictitious numbers.
PAGER447640123456Allocated to a device that receives and displays numeric or alphanumeric messages
VOICEMAIL_ONLY3538956000000Access number for voicemail only
MACHINE_TO_MACHINE337000011460640IoT style devices that have a sim card and need a phone number to connect to the mobile network. They're usually devices that report back sensor readings, or need to connect to the phone network for a data connection.
BAD_FORMAT7540The number you submitted to be checked could not be identified as a valid international telephone number
UNKNOWNAny number which does not fall into any of the above categories or error=INSUFFICIENT_CREDIT or error=INTERNAL_ERROR
Reference

All response fields

Every field in a lookup result, in one searchable table.

FieldTypeWhat it tells you
errorStringNONE, INSUFFICIENT_CREDIT or INTERNAL_ERROR. Match exactly.
uuidStringUnique ID for this individual result.
request_parameters.*ObjectEcho of your request with defaults filled in. Use .telephone_number to match results to your submitted numbers. If you don't send save_to_cache, it defaults to YES; omitted cache_days_private/cache_days_global default to your account settings.
credits_spentFloatCredits used for this lookup. Parse to 1 decimal place to allow for 0.5 / 1.5-credit services.
detected_telephone_numberStringThe number standardised to E164 — valid country code, area and digit count. Empty string if no valid number was detected.
formatted_telephone_numberStringThe detected number in your requested output_format. Empty if you didn't request one.
live_statusStringIs the number active and reachable? All values →
telephone_number_typeStringMobile, landline, VoIP, premium… All values →
original_networkStringAVAILABLE (details populated), NOT_AVAILABLE or NOT_APPLICABLE (details will be {}).
original_network_detailsObjectNetwork the number was first assigned to: name, mccmnc, country_name, country_iso3, area, country_prefix. Names can change over time (mergers, re-allocation).
current_networkStringAVAILABLE, NOT_AVAILABLE or NOT_APPLICABLE (e.g. BAD_FORMAT, NO_COVERAGE, DEAD, INCONCLUSIVE).
current_network_detailsObjectNetwork the number is on now — same keys as original, minus area. mccmnc is empty for non-mobile numbers.
is_portedStringYES, NO or UNKNOWN — has the number moved from its original network?
ported_dateStringOptional — only returned when requested. ISO 8601 date last ported, NOT_AVAILABLE or NOT_APPLICABLE.
landline_statusStringOptional — returned when requested and the number is a landline. Raw values map to LIVE / DEAD / INCONCLUSIVE — full mapping table →.
timestampISO 8601When this record was checked. If served from cache, this is the original check time.
sms_emailStringEmail-to-SMS gateway address for this number, where the network provides one (e.g. 07540822872@t-mobile.uk.net). Empty string if not available.
mms_emailStringEmail-to-MMS gateway address for this number, where the network provides one. Empty string if not available.
disposable_numberStringYES, NO or UNKNOWN — whether this is a disposable/virtual number. Not present on every result.
usa_status (top-level)StringOnly present when you requested the usa_status feature — confirms the feature was turned on for this lookup. Not to be confused with request_parameters.usa_status, which just echoes what you sent.
Reference

Errors & HTTP codes

Two layers: HTTP status codes on the whole request, and an error field on each individual result.

HTTP status codes

CodeMeaningWhat to do
200Request succeeded — check each result's error field.Parse the JSON body.
400Bad Request. Your request itself was malformed — for example: an invalid output_format, an invalid save_to_cache value, a cache_days_private/cache_days_global outside 0–30 or not an integer, a required parameter missing, a parameter we don't recognise, or an input_format that isn't a valid ISO3 code.Check your request body against the request parameters reference. You were not charged.
401Unauthorized — your api_key or api_secret is wrong.Double-check your credentials in the portal. You were not charged.
404Not Found — the request went to an endpoint we don't support.Check you're calling https://api.hlrlookup.com/apiv2/... and not a typo'd path.
429Too many requests. A telephone network is slowing down, so we backed off. Your number was not sent to the network.Resubmit the number. Slow your rate overall, or just for that network. Most clients under 50 req/s never see this — but handle it anyway.
500Internal Server Error — we hit something we didn't expect on our end.Retry. If it persists, contact support@hlrlookup.com. You were not charged.
⚠️ ImportantA badly-formatted phone number is not an HTTP 400. It still returns a normal 200 response, just with telephone_number_type: "BAD_FORMAT" in the body. Only build HTTP-level error handling for genuine request problems — not for bad numbers, which come back as ordinary results.

The error field (per result)

ValueMeaning
NONENo errors — the lookup ran normally.
INSUFFICIENT_CREDITNo credit left on the api_key you used. Top up, or check your balance via the balance endpoint.
INTERNAL_ERRORWe hit something unexpected. Retry; if it persists, contact support.

Rate limits at a glance

You're limited to 210 concurrent requests. Don't wait for a response before sending the next request — fire in parallel. If a slow network takes 10 seconds per lookup, 20 requests/second still gives you a steady throughput of 20/second after the initial lag.

Guides

Number formatting — input

Use the input_format parameter to submit locally-formatted numbers without converting them to E.164 yourself.

How it works

By default the API expects international E.164 format (digits only, no leading +). If you pass a local number like 07790606023 without an input_format, the API can't identify which country it belongs to and returns BAD_FORMAT.

Add "input_format": "GBR" (a 3-letter ISO country code) to your request and the API will prepend the correct country code automatically before processing.

Examples

ScenarioInputResult
No format specified07790606023 (UK local)BAD_FORMAT — unrecognisable without country context
With input_format: GBR07790606023 or 447790606023Converts to +447790606023 — identified as MOBILE
No format specified7148307000 (USA local)BAD_FORMAT
With input_format: USA7148307000 or 17148307000Converts to +17148307000 — identified as LANDLINE
Invalid ISO3 codeAny numberHTTP 400 Bad Request

Request example

curl -H "Content-Type: application/json" -X POST \
  -d '{"api_key":"your_api_key","api_secret":"your_api_secret",
       "requests":[{"telephone_number":"07790606023","input_format":"GBR"}]}' \
  https://api.hlrlookup.com/apiv2/hlr
ℹ️ TipThe input_format parameter is per-number — you can mix local and international numbers in the same batch request by setting it on individual entries only.
Guides

Number formatting — output

Use the output_format parameter to get the detected number back in a consistent format for your database or downstream system.

Available formats

ValueOutputExample
omitted or emptyNo formatted number returned — formatted_telephone_number is empty
E164Digits only, no leading +447790606023
PLUS_E164Standard international format with + prefix+447790606023
NATIONALFormatted as you'd dial it domestically, within the number's own countryvaries by country
USA or ISO3 codeFormatted for dialling from that country011447790606023 (from USA)
Unsupported valueHTTP 400 Bad Request

Request example

curl -H "Content-Type: application/json" -X POST \
  -d '{"api_key":"your_api_key","api_secret":"your_api_secret",
       "requests":[{"telephone_number":"447790606023","output_format":"PLUS_E164"}]}' \
  https://api.hlrlookup.com/apiv2/hlr

The formatted number appears in the formatted_telephone_number field of the response.

Guides

Cache system

The cache stores lookup results for up to 30 days, reducing latency and saving credits on repeated checks of the same number.

Two cache levels

Private cache — results from your own account's previous lookups. Retrieving from your private cache is free.

Global cache — results from other accounts that chose to share their results. Costs ½ credit per lookup.

How the cache is checked

  1. If cache_days_private is set, the private cache is checked first. A match is returned free.
  2. If no private match, and cache_days_global is set, the global cache is checked. A match costs ½ credit.
  3. If no cached result exists, a live network lookup is performed.

Cache parameters

ParameterValuesWhat it does
cache_days_private0–30How many days back to look in your private cache. 0 = skip private cache.
cache_days_global0–30How many days back to look in the global cache. 0 = skip global cache.
save_to_cacheYES / NO / PRIVATEYES = save to global cache and earn ¼ credit when others retrieve it. PRIVATE = save to private cache only. NO = don't cache this result.
ℹ️ Default behaviourIf you don't include save_to_cache in your request at all, it defaults to YES — your result is saved to the global cache automatically unless you explicitly opt out.
ℹ️ Earning creditsWhen you save to the global cache (save_to_cache: YES) and another account retrieves your result, you earn ¼ credit per retrieval.

Request example

curl -H "Content-Type: application/json" -X POST \
  -d '{"api_key":"your_api_key","api_secret":"your_api_secret",
       "requests":[{"telephone_number":"441133910781",
                    "cache_days_private":30,
                    "cache_days_global":15,
                    "save_to_cache":"YES"}]}' \
  https://api.hlrlookup.com/apiv2/hlr
⚠️ NoteThe cache is disabled automatically when the Ported Date feature is enabled, since ported date lookups specifically target recently-ported numbers.
Guides

Ported date feature

Retrieve the date a number was last ported to a different network. Useful for detecting port-out fraud and verifying recent number history.

Why it matters

Port-out fraud is a scheme where criminals hijack a phone number by transferring it to a new network in order to intercept one-time passwords for banking and email accounts. Knowing when a number was last ported lets you flag suspicious recent activity.

Limitations

If a number was ported away from its original network and then ported back, the last ported date cannot be retrieved.

The cache is automatically disabled when get_ported_date: YES is set, since the feature is specifically designed to catch numbers that have been recently ported.

Pricing

OutcomeCost
Ported date successfully retrieved2 credits
Requested but date not available1 credit

Coverage

65 countries, listed below with the date each was added. Most were added July 2020; a batch of newer countries (India, Bangladesh, Nigeria, Iran, Jamaica, Georgia and others) was added July 2025. Check the Coverage Checker for the latest.

CountryISO3Date added
AlbaniaALB2020-07-31
ArgentinaARG2020-08-17
AustraliaAUS2020-07-31
AustriaAUT2020-07-31
BahrainBHR2025-07-10
BangladeshBGD2025-07-10
BelarusBLR2020-07-31
BelgiumBEL2020-07-31
BeninBEN2020-07-31
BoliviaBOL2020-08-17
Bosnia / HerzegovinaBIH2020-07-31
BrazilBRA2020-07-31
BulgariaBGR2020-07-31
CanadaCAN2020-07-31
ChileCHL2020-07-31
ColombiaCOL2020-07-31
Costa RicaCRI2020-07-31
CroatiaHRV2020-07-31
Czech RepublicCZE2020-07-31
DenmarkDNK2020-07-31
EcuadorECU2020-08-17
El SalvadorSLV2020-07-31
EstoniaEST2020-07-31
FranceFRA2020-07-31
GeorgiaGEO2025-07-10
GermanyDEU2020-07-31
GhanaGHA2020-07-31
GreeceGRC2020-07-31
GuamGUM2025-07-10
Hong KongHKG2020-07-31
HungaryHUN2020-07-31
IndiaIND2025-07-10
IranIRN2025-07-10
IsraelISR2020-07-31
ItalyITA2020-07-31
JamaicaJAM2025-07-10
KazakhstanKAZ2020-07-31
LatviaLVA2020-07-31
LithuaniaLTU2020-07-31
MacedoniaMKD2020-07-31
MexicoMEX2020-07-31
MoldovaMDA2025-07-25
NetherlandsNLD2020-07-31
New ZealandNZL2020-07-31
NigeriaNGA2025-07-10
Northern Marina IslandsMNP2025-07-10
PalestinePSE2020-08-17
PeruPER2020-07-31
PolandPOL2020-07-31
Puerto RicoPRI2025-07-10
RomaniaROU2020-07-31
RussiaRUS2020-07-31
SerbiaSRB2020-07-31
SlovakiaSVK2020-07-31
South AfricaZAF2020-07-31
South KoreaKOR2020-08-17
SpainESP2020-08-17
SwedenSWE2020-07-31
SwitzerlandCHE2020-07-31
ThailandTHA2020-07-31
TurkeyTUR2020-07-31
United StatesUSA2020-07-31
UruguayURY2025-07-10
US Virgin IslandsVIR2025-07-10
VietnamVNM2025-07-10

Request example

curl -H "Content-Type: application/json" -X POST \
  -d '{"api_key":"your_api_key","api_secret":"your_api_secret",
       "requests":[{"telephone_number":"447540822872","get_ported_date":"YES"}]}' \
  https://api.hlrlookup.com/apiv2/hlr

The response includes a ported_date field with an ISO 8601 date, NOT_AVAILABLE, or NOT_APPLICABLE.

Guides

Landline status feature

Check whether a UK or Irish landline number is live, dead, or has a more specific status such as out-of-order or call-barred.

Coverage

Currently available for:

  • United Kingdom (GBR) — available since January 2020
  • Ireland (IRL) — available since July 2021

Pricing

There is a 1 credit surcharge for landline status checks, bringing the total to 2 credits when the number is a landline in coverage.

How it works

The result is mapped into the standard live_status field (LIVE / DEAD / INCONCLUSIVE) and an additional landline_status field with the raw, more granular status the network returned. Every raw value falls into one of three buckets — the table below is the complete mapping, so any raw value you see can be looked up here:

landline_status valueBucket
LIVELIVE
DEADDEAD
OUT_OF_ORDERDEAD
NUMBER_CHANGEDDEAD
CALL_BARREDLIVE
INCONCLUSIVEINCONCLUSIVE
UNKNOWN_NOT_AUTHINCONCLUSIVE
UNKNOWN_NOT_AVAILINCONCLUSIVE
UNKNOWN_NOT_IMPLINCONCLUSIVE
UNKNOWN_REJECTEDINCONCLUSIVE
UNKNOWN_INTERWORKINGINCONCLUSIVE
ERROR_UNKNOWN_RESPONSEINCONCLUSIVE
⚠️ NoteCALL_BARRED maps to LIVE, not dead — the line exists and is in service, it's just barred from certain calls. Don't treat it as a dead number.

Request example

curl -H "Content-Type: application/json" -X POST \
  -d '{"api_key":"your_api_key","api_secret":"your_api_secret",
       "requests":[{"telephone_number":"441133910781","get_landline_status":"YES"}]}' \
  https://api.hlrlookup.com/apiv2/hlr
Guides

USA status feature

Check the live status of US mobile numbers. Standard HLR lookups return NOT_AVAILABLE_NETWORK_ONLY for US numbers — this feature provides actual live/dead status.

Coverage limitations

The feature supports US mobile numbers only. The following US territories are not covered:

  • Puerto Rico
  • Guam
  • US Virgin Islands

Non-mobile US numbers return NOT_AVAILABLE_NETWORK_ONLY even with this feature enabled.

Pricing

Number typeCost
USA mobile numbers2 credits
USA non-mobile numbers1 credit
US territory mobile numbers1 credit
Non-USA numbers (feature ignored)1 credit

Request example

curl -H "Content-Type: application/json" -X POST \
  -d '{"api_key":"your_api_key","api_secret":"your_api_secret",
       "requests":[{"telephone_number":"17148307000","usa_status":"YES"}]}' \
  https://api.hlrlookup.com/apiv2/hlr

The response includes a usa_status field indicating that this optional feature was used.

Guides

Bulk uploads via API

Submit large lists of numbers via the batch API — upload a CSV, monitor progress, pause and resume, then download results.

ℹ️ Different login parametersThe batch API authenticates differently to the main lookup API. Use apikey and secret as URL query parameters (e.g. ?apikey=your_api_key&secret=your_api_secret) — not the api_key / api_secret JSON body fields used elsewhere in these docs.

Upload methods

Two approaches are supported:

  1. CSV file upload — upload a locally-stored CSV file.
  2. JSON body — submit numbers directly in the request body. Limited to 100,000 numbers or 2 MB.

If your CSV has multiple columns (e.g. your own reference ID alongside the number), tell us which column holds the phone numbers by adding &column= to the upload URL:

Numbers stored inMapping number
Column A0
Column B1
Column C2
Column D3

Omitting &column= always checks the first column. Example — numbers in column B: .../source?apikey=your_api_key&secret=your_api_secret&column=1

Batch operations

OperationMethodWhat it does
List all batchesGETRetrieve status and metadata for all your batches
Get a batchGETDetails and progress for a specific batch by ID
Create a batchPOSTUpload numbers and start or schedule processing
Update a batchPUTPause or resume processing
Delete a batchDELETERemove a completed batch and its results (not recoverable — download first)
⚠️ Set the batch typeAlways include "type": "HLR_V2" when creating a batch: {"filename":"mybatch.txt","type":"HLR_V2"}. Without it, your results file is formatted using the older, incomplete legacy format and will be missing newer response fields.

Optional parameters

Batch creation accepts the same optional parameters as single lookups: cache_days_private, cache_days_global, save_to_cache, output_format, input_format, get_ported_date, get_landline_status, and usa_status. Include them inside a batchArguments object when you create the batch.

Downloading results

Completed batches can be downloaded as CSV or JSON. Results include live_status, telephone_number_type, original_network, is_ported, and all other standard response fields.

Common errors

ErrorLikely cause
Bad RequestSomething's wrong with a parameter
Validation failedWrong request method (e.g. GET instead of POST), or check filename/type/scheduledStart are correct
Invalid batch argumentsOne or more values inside batchArguments is invalid
Invalid apikey or secretCheck your credentials
Batch not foundWrong batch ID
UnauthorizedThis batch doesn't belong to you, or apikey/secret is wrong
Internal Server Error (HTTP 400)Something's wrong with the formatting of your request — check all quotes and braces are correctly entered
Internal Server Error (HTTP 500, with an errorId)You've tried to upload data to a batch that already has data loaded into it
ℹ️ Full API referenceThe batch API runs on its own domain (batches.hlrlookup.com), separate from the single-lookup API. See the OpenAPI schema for the complete batch endpoint documentation.
Guides

Testing suite

Test your integration for free without touching a real phone network. The testing endpoint returns pre-populated responses that simulate every status and error.

Test credentials

Endpoint:    https://testing.hlrlookup.com/apiv2/hlr
api_key:     speedtest
api_secret:  speedtest

How it works

The testing suite is not connected to the telephone network. It contains a dataset of pre-populated example responses. Submit any number and it returns the closest match from the dataset — it won't return an exact match for every number.

Simulating 429 errors

The testing suite simulates rate limiting. Submit more than 200 requests per second to trigger 429 responses. Afghanistan numbers (country code 93) trigger 429 responses at lower rates to simulate congested network conditions — and also return slower response times.

If you know in advance which network a number is on, you can reduce requests to just that network rather than slowing down overall. Ask your account manager about our e164 validation service — it detects a number's network without performing a full HLR lookup.

Sample test numbers

CountryNumber
Afghanistan93749769622, 93770554876
South Africa27846073982, 27847152603, 27848591518
Greece306907339774, 306917695569, 306923469843
Spain34699000823, 34722245534
Portugal351911543003, 351964950422
Ukraine380950937486, 380980328342, 380996049969
Serbia381615582482, 381621601528

This is a small sample — a longer list is available on request from support@hlrlookup.com. You can also submit any number not in this list; you'll get back the closest match from the test dataset rather than an error.

ℹ️ Free to useAll testing suite requests are free — no credits are consumed.
Guides

Charging

Credits are only spent on HTTP 200 responses. Errors (400, 401, 429, 500, 404) are always free. See the pricing page for the per-credit cost.

Always free

  • HTTP 400, 401, 429, 500, 404 responses
  • error: INSUFFICIENT_CREDIT or error: INTERNAL_ERROR results
  • telephone_number_type: BAD_FORMAT
  • Non-mobile numbers with live_status: NO_COVERAGE

Base charges (HLR — no optional features)

ResultCredits
Live lookup (LIVE, DEAD, ABSENT_SUBSCRIBER, NO_TELESERVICE_PROVISIONED, NOT_AVAILABLE_NETWORK_ONLY, INCONCLUSIVE)1 credit
Retrieved from global cache½ credit
Retrieved from private cacheFree
NO_COVERAGEFree

Optional features (additional charges)

FeatureWhen availableTotal cost
Ported date — retrieved65 countries — see list2 credits
Ported date — not available65 countries — see list1 credit
Landline status (UK/Ireland)GBR, IRL2 credits
USA status — mobileUSA only2 credits
USA status — non-mobileUSA only1 credit

MNP endpoint

MNP lookups cost half the HLR rate. Base charge: ½ credit live, ¼ credit from global cache. With ported date: ½–1½ credits. Ported dates are never cached on MNP lookups.

ℹ️ Earning back creditsSave your results to the global cache (save_to_cache: YES) and earn ¼ credit every time another account retrieves your result.
Reference

Request parameters

All parameters you can send in a lookup request, including authentication, per-number options, and optional features.

Endpoints

Lookup typeURL
HLR (live status + network)https://api.hlrlookup.com/apiv2/hlr
MNP (network only, cheaper)https://api.hlrlookup.com/apiv2/mnp
Validator (format check only)https://api.hlrlookup.com/apiv2/validate
Balance checkhttps://api.hlrlookup.com/apiv2/balance
Testing (free, no real network)https://testing.hlrlookup.com/apiv2/hlr

Checking your balance

Check your remaining credits at any time — just your api_key and api_secret, no other parameters needed:

curl -s -H "Content-Type: application/json" -X POST \
  -d '{"api_key":"your_api_key","api_secret":"your_api_secret"}' \
  https://api.hlrlookup.com/apiv2/balance
{
  "body": {
    "Status": "OK",
    "Credits": 15000
  }
}

Authentication (required)

ParameterTypeDescription
api_keyStringYour account API key — found in the portal under account settings
api_secretStringYour account API secret — found alongside the key
requestsArrayArray of lookup objects. Up to 80 numbers per request. Results are returned in the same order as submitted.
requests[].telephone_numberStringThe number to look up. E.164 digits preferred (e.g. 447540822872). Non-digit characters (+, spaces, dashes, parentheses) are accepted.

Optional parameters (per number)

ParameterValuesDescription
cache_days_private0–30Look back in your private cache this many days. 0 = bypass. Free.
cache_days_global0–30Look back in the global cache this many days. 0 = bypass. Costs ½ credit.
save_to_cacheYES / NO / PRIVATEWhether to save this result to cache. YES = global (earn ¼ credit on retrieval). PRIVATE = your cache only.
output_formatE164 / PLUS_E164 / ISO3Format for formatted_telephone_number in the response. See Number formatting — output.
input_formatISO3 country codeTreat the submitted number as a local number from this country. See Number formatting — input.
get_ported_dateYES / NORetrieve the date the number was last ported. Additional charge applies. Disables cache.
get_landline_statusYES / NORetrieve detailed landline status (UK and Ireland only). Additional charge applies.
usa_statusYES / NORetrieve live status for US mobile numbers. Additional charge applies.
Reference

HTTP POST format

The API accepts requests in JSON (recommended) or form-encoded format. JSON supports batch requests; form-encoded is single numbers only.

JSON format

Set Content-Type: application/json and POST a JSON body.

Single number

{
  "api_key": "your_api_key_here",
  "api_secret": "your_api_secret_here",
  "requests": [
    { "telephone_number": "447540822872" }
  ]
}

Single number with parameters

{
  "api_key": "your_api_key_here",
  "api_secret": "your_api_secret_here",
  "requests": [
    {
      "telephone_number": "447540822872",
      "cache_days_private": 30,
      "output_format": "PLUS_E164",
      "save_to_cache": "YES"
    }
  ]
}

Multiple numbers

{
  "api_key": "your_api_key_here",
  "api_secret": "your_api_secret_here",
  "requests": [
    { "telephone_number": "447540822872", "cache_days_private": 30 },
    { "telephone_number": "441133910781", "output_format": "E164" },
    { "telephone_number": "07790606023",  "input_format": "GBR" }
  ]
}

Form-encoded format

Set Content-Type: application/x-www-form-urlencoded. Single numbers only — batching is not supported.

curl -X POST \
  -d "api_key=your_api_key&api_secret=your_api_secret&telephone_number=447540822872&cache_days_private=8&output_format=PLUS_E164&save_to_cache=YES" \
  https://api.hlrlookup.com/apiv2/hlr

Optional HTTP headers

HeaderDescription
ReferenceIDYour own reference ID — echoed back in the response for reconciliation
AccountIDYour account reference ID
Reference

Example requests & responses

Working examples of common lookup scenarios — single number, multiple numbers, optional features, and error responses.

Single number lookup

curl -H "Content-Type: application/json" -X POST \
  -d '{"api_key":"your_api_key","api_secret":"your_api_secret",
       "requests":[{"telephone_number":"447540822872"}]}' \
  https://api.hlrlookup.com/apiv2/hlr
{
  "body": {
    "results": [{
      "error": "NONE",
      "uuid": "4562ab7e-af26-4d42-87a0-b84bb4e5f96c",
      "credits_spent": 1,
      "detected_telephone_number": "447540822872",
      "live_status": "LIVE",
      "telephone_number_type": "MOBILE",
      "original_network": "AVAILABLE",
      "original_network_details": {
        "name": "O2 (UK)", "mccmnc": "23410",
        "country_name": "United Kingdom", "country_iso3": "GBR",
        "area": "United Kingdom", "country_prefix": "44"
      },
      "current_network": "AVAILABLE",
      "current_network_details": {
        "name": "EE Limited (T-Mobile)", "mccmnc": "23430",
        "country_name": "United Kingdom", "country_iso3": "GBR",
        "country_prefix": "44"
      },
      "is_ported": "YES",
      "timestamp": "2022-10-07T13:06:15Z"
    }]
  }
}

With optional parameters

Adding get_ported_date: YES and output_format: PLUS_E164:

{
  "error": "NONE",
  "credits_spent": 1,
  "detected_telephone_number": "447540822872",
  "formatted_telephone_number": "+447540822872",
  "live_status": "LIVE",
  "is_ported": "YES",
  "ported_date": "NOT_AVAILABLE",
  "timestamp": "2022-10-07T13:06:15Z"
}

Only 1 credit here — the ported date feature is charged at 1 credit when requested but not available, and 2 credits only when a date is actually returned.

Multiple numbers

Each number in the requests array gets its own result in the same position. Use request_parameters.telephone_number to match results back to your inputs.

Error responses

HTTP codeBodyCause
401{"error":"UNAUTHORIZED","message":"Invalid api_key or api_secret"}Wrong credentials
400{"error":"BAD_REQUEST","message":"Invalid output_format requested"}Invalid parameter value
429{"error":"TOO_MANY_REQUESTS","message":"Please try again later"}Resubmit this number
404no bodyWrong endpoint URL — check you're calling api.hlrlookup.com/apiv2/...
500no bodySomething went wrong our end — retry, then contact support if it persists
For machines

MCP Server

Give AI tools and coding agents — like Claude Code — direct access to HLR Lookup through the Model Context Protocol (MCP). No custom integration code required.

Server details

Production endpointhttps://api.hlrlookup.com/mcp
Server versionhlr-api-mcp v1.0.0
MCP protocol version2025-06-18
TransportStateless streamable HTTP. There's no session ID — responses come back as Server-Sent Events (SSE).

Available tools

The server exposes four tools:

ToolWhat it doesCredits
hlr_lookupLive HLR lookup for up to 80 numbers in one request.Yes
mnp_lookupMobile number portability lookup, same request/response shape as hlr_lookup.Yes
validateOffline format/network validation — no live lookup performed.No
balanceReturns the remaining credit balance for the authenticated account.No

hlr_lookup

Performs a live HLR lookup for up to 80 telephone numbers in a single request. The response can include telephone_number_type, live_status, original network, current network, mobile number portability information, and the sms_email/mms_email gateway addresses.

Optional additional fields: ported_date, landline_status, usa_status. Requesting usa_status performs an extra live US status check and consumes an additional credit.

mnp_lookup

Same general request and response structure as hlr_lookup.

⚠️ NANP numbersFor +1 country-code (NANP) numbers, the mnp_lookup response does not include telephone_number_type. [To confirm: our own MNP example elsewhere in these docs shows telephone_number_type missing for a UK number too — worth checking whether this is actually a NANP-specific limitation or true of MNP lookups generally, before this goes live.]

validate

Checks formatting and network information without performing a live HLR lookup — useful for pre-flight checks before spending credits on a real lookup. Free — consumes no credits.

balance

Returns the remaining credit balance for the authenticated account. Free — consumes no credits.

Authentication

Every tool call needs authentication — including validate and balance, which don't consume credits. "Free" means zero credits, not no login: you still need a valid API key and secret. Only MCP schema discovery works without authentication.

Send credentials as a Bearer token in the Authorization header:

Authorization: Bearer <api_key>:<api_secret>

Manage your API credentials in the HLR Lookup portal.

Shared lookup options

All lookup tools (hlr_lookup, mnp_lookup, validate) share the same input, output and cache options.

Input format

Submit numbers in national or E.164 format. For national format, add input_format with the relevant ISO 3166-1 alpha-3 country code — e.g. GBR.

Output format

ValueWhat you get
E164Digits only, no leading +
PLUS_E164Standard international format with + prefix
NATIONALFormatted as you'd dial it domestically, within the number's own country
ISO3 country codeFormatted for dialling from that country

Cache controls

ParameterValues
cache_days_global0–30
cache_days_private0–30
save_to_cacheYES / NO / PRIVATE

Error handling

Authentication and request errors come back as valid MCP error responses with isError: true. The structured content includes a link to the account settings page, the expected Authorization header format, and an explanation that valid credentials are required.

Connecting with Claude Code

Add the server with:

claude mcp add --transport http hlrlookup https://api.hlrlookup.com/mcp \
  --header "Authorization: Bearer <api_key>:<api_secret>"

Replace <api_key> and <api_secret> with your own credentials. Once added, Claude Code can discover and call the available HLR Lookup tools directly.

ℹ️ New featureThe MCP server is a new integration channel and isn't part of the existing REST API docs elsewhere in this knowledge base — it's a separate way in for AI tools and agents, sitting alongside the REST API rather than replacing it.