MSISDNHLR
1

MSISDN HLR API

The MSISDN HLR REST API lets you enrich Spanish (ES) and Mexican (MX) mobile phone numbers with MCC, MNC, operator name and portability status — updated from official portability databases.

Two modes are available: single-number real-time lookup and bulk batch enrichment (CSV/XLSX file upload). Both modes are credit-based. Credits are deducted at job submission and are non-refundable.

Supported countries: Spain (ES · prefix 34) and Mexico (MX · prefix 52). Numbers from other countries are returned with status: "unknown".

Base URL

https://msisdnhlr.com

All paths below are relative to this base URL. All requests and responses use JSON unless otherwise noted.

Authentication

All API endpoints require a Bearer token in the Authorization header.

Authorization: Bearer YOUR_API_TOKEN

Alternatively, pass the token as a query parameter:

GET /api/batch/abc-uuid?api_token=YOUR_API_TOKEN
Get your API token: Create a free account, then visit Dashboard → API Tokens to generate a token. Store it securely — it is shown only once.

Credits & Pricing

Credits are consumed per enriched number. Pricing is tiered and progressive — each band applies only to numbers within that range. Minimum charge is $25.00 USD.

Volume Rate per number
1 – 1,000,000$0.0025
1,000,001 – 5,000,000$0.0020
5,000,001 – 10,000,000$0.0015
10,000,001 – 20,000,000$0.0010
Over 20,000,000$0.0005

Minimum charge $25.00. Credits can be purchased from the Dashboard → Billing page.

POST /api/lookup

Enrich a single mobile number in real time. Consumes 1 credit per call (deducted immediately).

Request body (JSON)

Field Type Required Description
msisdn string Yes The phone number to look up. Accepts E.164 (+34612345678), with prefix without +, or local national format.

Example request

curl -X POST https://msisdnhlr.com/api/lookup \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"msisdn":"+34612345678"}'

Response 200 OK

{
  "original": "+34612345678",
  "normalized": "34612345678",
  "country_iso": "ES",
  "status": "ported",
  "mcc": "214",
  "mnc": "07",
  "operator_name": "Movistar"
}
POST /api/batch

Submit a CSV or XLSX file for bulk enrichment. Credits are deducted at submission. The job runs asynchronously — poll /api/batch/:uuid for progress.

Request multipart/form-data

Field Type Required Description
file file Yes CSV, XLSX or TXT file. Numbers must be in column A, one per row. Include country prefix (+34, +52…). Max 512 MB.

Example request

curl -X POST https://msisdnhlr.com/api/batch \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  -F "file=@/path/to/numbers.csv"

Response 202 Accepted

{
  "uuid": "550e8400-e29b-41d4-a716-446655440000",
  "status": "processing",
  "total_numbers": 150000,
  "price": 375.00
}
GET /api/batch/{uuid}

Poll the status of a batch job. Recommended polling interval: every 3 seconds.

Path parameter

Parameter Description
uuidThe UUID returned by POST /api/batch.

Response 200 OK

{
  "uuid": "550e8400-e29b-41d4-a716-446655440000",
  "status": "done",
  "progress_pct": 100,
  "total_numbers": 150000,
  "enriched_count": 148320,
  "failed_count": 1680,
  "expires_at": "2026-04-11T14:30:00+00:00"
}

Status lifecycle

Value Meaning
pendingJob is queued, not yet started.
processingEnrichment in progress. progress_pct increases from 0 to 100.
doneEnrichment complete. Download available until expires_at.
failedProcessing failed. Contact support with the job UUID.
GET /api/batch/{uuid}/download

Download the enriched CSV file for a completed job. Only available when status is done. Files expire 24 hours after completion.

Example request

curl -O -J \
  -H "Authorization: Bearer YOUR_API_TOKEN" \
  https://msisdnhlr.com/api/batch/550e8400-e29b-41d4-a716-446655440000/download

Response

Returns the enriched CSV file as a download with Content-Type: text/csv.

CSV Column Description
original_numberThe number as submitted in your input file.
normalizedE.164 digits without + (e.g. 34612345678).
country_isoISO 3166-1 alpha-2 country code (ES, MX), or empty if unknown.
statusSee status values.
mccMobile Country Code (e.g. 214 for ES).
mncMobile Network Code (e.g. 07 for Movistar ES).
operator_nameOperator name (e.g. Movistar, Telcel), or empty if unknown.

Result Object

Every enriched number (in single lookup responses and CSV rows) has the following fields:

Field Type Nullable Description
originalstringNoInput number as received.
normalizedstringNoDigits only, no country prefix sign.
country_isostringYesES or MX. null if not identified.
statusstringNoSee status values.
mccstringYes3-digit Mobile Country Code.
mncstringYes2–3 digit Mobile Network Code.
operator_namestringYesHuman-readable operator name.

Status Values

Value Meaning
portedNumber found in the official portability database. The returned operator is the current one (post-port).
rangeNumber matched to a number range. Operator is the original range holder (may have ported away).
unknownNumber could not be matched to any operator or country. MCC, MNC and operator will be null.
invalidInput could not be parsed as a phone number (e.g. too short, non-numeric).

HTTP Error Codes

Code Meaning
401Missing or invalid API token.
402Insufficient credit balance. Top up via the Dashboard → Billing page.
404Job not found or does not belong to your account.
409Download requested but job is not yet complete.
410Download file has expired (older than 24 hours).
422Validation error (missing field, unsupported file type, etc.). Error details in response body.
500Internal server error. Please retry or contact support.

Error response body

{
  "error": "Insufficient credit balance.",
  "balance": 12.50,
  "required": 25.00
}

Quick Start — Python Example

import requests, time

TOKEN = "YOUR_API_TOKEN"
BASE = "https://msisdnhlr.com"
HEADERS = {"Authorization": f"Bearer {TOKEN}"}

# 1. Submit batch
with open("numbers.csv", "rb") as f:
    r = requests.post(f"{BASE}/api/batch", headers=HEADERS, files={"file": f})
    r.raise_for_status()
uuid = r.json()["uuid"]

# 2. Poll until done
while True:
    s = requests.get(f"{BASE}/api/batch/{uuid}", headers=HEADERS).json()
    print(s["progress_pct"], "%")
    if s["status"] == "done": break
    if s["status"] == "failed": raise RuntimeError("Job failed")
    time.sleep(3)

# 3. Download results
r = requests.get(f"{BASE}/api/batch/{uuid}/download", headers=HEADERS)
with open("enriched_numbers.csv", "wb") as f:
    f.write(r.content)

Frequently Asked Questions