HLR
Home Location Register lookups through the gateway.
The HLR product performs phone‑number lookups — checking a number's status, operator, and portability — through the same gateway you already use. It covers three lookup categories: HLR, MNP (number portability), and NT (number type).
All HLR endpoints are /v1/hlr/* requests authenticated with your key id and secret — see Authentication.
Responses, pagination, errors and retry behaviour follow the shared Conventions and Errors rules — this page covers only what is specific to HLR.
Every endpoint, with its full request and response schema, is in the HLR API Reference.
A typical flow
Submit a lookup
Every lookup is a job. A single number is looked up immediately, so the answer comes back on this response — the steps below are for batches, which are queued and processed in the background.
const { data } = await api('POST', '/v1/hlr/lookups', {
body: { lookupType: 'hlr-single', productCode: 'hlr:V11', number: '21650000001' },
});
data.status; // 'completed'
data.result; // { connectivityStatus: 'CONNECTED', currentNetwork: 'Vodafone UK', ported: false, … }
data.price; // { amount: 1.0025, currency: 'EUR' }result is the same object the results endpoint publishes, and it is present
only when the lookup is already finished — a batch comes back queued with no
result, and is polled. A single that failed comes back failed with none
either; read its results for the reason.
The body has two shapes — one number or many — and lookupType picks the category:
lookupType | Body |
|---|---|
hlr-single, mnp-single, nt-single | { productCode, number } |
hlr-batch, mnp-batch, nt-batch | { productCode, numbers[] } |
Every number is validated before anything is queued or charged, so one malformed
entry rejects the whole request rather than billing for it. The batch maximum is
published as maxItems on the request schema in the reference.
Poll the job
Batches only — a single is already finished above.
await api('GET', `/v1/hlr/lookups/${lookupId}`);A lookup ends in completed, partially_completed, failed, or cancelled. Cancel a non‑terminal lookup with POST /v1/hlr/lookups/{lookupId}/cancel — a queued lookup refunds in full.
Read the results
await api('GET', `/v1/hlr/lookups/${lookupId}/results`, {
query: { page: 1, pageSize: 50 },
});Results are per‑number and paginated. Past lookups are listed by GET /v1/hlr/lookups.
Each row carries status, the result object holding the answer, and — on a row that did
not succeed — an error with a code and usually a message saying why. A failed or
invalid row without that is nothing to act on: retrying, correcting the number and
contacting support are different responses, and the code is what tells them apart.
Which fields result contains depends on the lookup category, and every one of them is
typed in the HLR API Reference — ported and reachable are booleans,
regions and timezones are string arrays, the rest are strings. A field the network had
no answer for may come back as null or be omitted entirely, so treat a missing key and a
null the same way — read with a default (e.g. result.ported ?? null) rather than assuming
the key is always present.
Export a finished job
const { data } = await api('POST', `/v1/hlr/lookups/${lookupId}/exports`, {
body: { format: 'csv' },
});
data.status; // 'ready' when the file already exists, else 'pending'
data.downloadUrl; // present as soon as it is ready — follow it for the file
// Not ready yet? Poll the export until it is:
const state = await api('GET', `/v1/hlr/lookups/${lookupId}/exports/csv`);
state.data.status; // 'pending' → 'ready'
state.data.sizeBytes; // 48213
state.data.checksum; // 'sha256:…'
state.data.downloadUrl; // the file, on this APIAn export is a child of its lookup: POST the collection with the format you want
(json, csv, or xlsx). Building is idempotent and asynchronous — re-posting the same
format returns the build already in progress rather than starting a second one.
An export is addressed by its format. A lookup has at most one export per format, so
csv is the address: /v1/hlr/lookups/{lookupId}/exports/csv. There is no separate id
to keep. Anything other than json, csv or xlsx is rejected as
400 VALIDATION_ERROR with fields: ["params.format"].
Once status reads ready the export carries a downloadUrl. Follow it rather than
building the path yourself — its presence is also the signal that the file exists.
GET …/exports/{format}/content — what downloadUrl points at — returns the file itself
as an attachment: text/csv, application/json or the xlsx media type, matching the
format you asked for. It is an ordinary endpoint, authenticated with your key like every
other call. Check sizeBytes and checksum first if you want to size the transfer or
verify what you received.
No storage URL is ever returned. The file is served through the API, which redeems
the storage credential server-side rather than handing it to a client — so there is no
link to expire and nothing about where the file lives. To read a lookup's results
without a file, use GET /v1/hlr/lookups/{lookupId}/results — the same data,
paginated.
Pricing
Lookups are billed per number against your effective pricing plan. Read the products available to you, each with the unit price that applies to your account, before submitting a lookup:
await api('GET', '/v1/hlr/products');
// or one product directly:
await api('GET', `/v1/hlr/products/${productCode}`);Pricing plans themselves are configured in your panel, not through this API.
Errors follow the standard gateway error format. The codes each endpoint can return are listed on that endpoint in the API Reference.
Job statuses
| Status | Meaning |
|---|---|
queued | Accepted, not started. |
running | In progress; counts are climbing. |
completed | Every number processed. |
partially_completed | Finished, some numbers failed. Check per-result statuses. |
failed | The job could not be processed. |
cancelled | You cancelled it. Unprocessed numbers were not charged. |
queued and running are the non-terminal pair — poll until neither applies. actions
tells you what is possible now: canCancel while running, canExport once terminal.
Result statuses
| Status | Meaning |
|---|---|
accepted | The lookup succeeded; result holds the data. |
rejected | The network answered, and the answer was negative. |
failed | The lookup could not be completed. Read error.code. |
invalid | The number was not usable for this lookup. Read error.code. |
When things go wrong
| You see | Meaning | Do |
|---|---|---|
400 VALIDATION_ERROR | An empty batch, a batch over the maximum, or a number that is not in international format. | Fix the batch. Numbers are checked before anything is queued or charged, so a rejected submission costs nothing. |
409 INSUFFICIENT_BALANCE | Not enough balance for the batch. | Top up, then submit the batch again. Nothing was queued or charged. |
409 PRODUCT_UNAVAILABLE | That product cannot be sold to you right now. | Check GET /v1/hlr/products for what is available. |
404 NOT_FOUND | No such lookup — or not yours. | Check the id. |
Full schemas are in the HLR API Reference.