Phone Number Portability: Tracking Numbers Across Carriers
Navigate the complexities of phone number portability and its impact on validation, carrier detection, and user experience.
Table of Contents
Table of Contents
Mobile Number Portability (MNP) allows users to change carriers without changing their MSISDN. For validation and carrier tracking, this means: HLR/NP databases are mandatory, and operator prefixes are often misleading.
Cleariflow Phone Validation API scope: Our Phone Validation API performs structural validation via Google libphonenumber, E.164 normalization, line type, and optional carrier/location metadata (mainly US/CA). It does not resolve MNP or perform HLR lookups. This article covers portability concepts for teams building a larger telco data stack.
MNP Basics
- Ported: number has been transferred — the original MCC/MNC prefix does not reflect the current operator.
- Non-ported: number remains with the original operator.
- Partial MNP: countries without centralized database — requires HLR query to the home network.
Prioritize: fast cache → local NP database → HLR/NP provider with status confirmation.
Data Sources and Standards
- NP Registry: centralized databases (e.g., EU/some APAC countries). Response provides current operator and porting date.
- HLR Lookup: actual subscriber status (active/inactive), current operator's MCC/MNC, possibly roaming status.
- CRDB/ENUM (in some countries): MSISDN→routing mapping.
Best practice: update local NP cache every 24h, HLR results every 1–4h; include data version in API response.
Validation Flow and Fallbacks
type MNPInfo = { isPorted: boolean; current: { mcc: string; mnc: string; carrier: string }; portedAt?: number }
async function resolveCarrier(msisdn: string): Promise<MNPInfo> {
const cached = await cache.get(msisdn)
if (cached) return cached
// 1) Fast NP database
const np = await npRegistry.lookup(msisdn).catch(() => null)
if (np) return save(msisdn, normalize(np))
// 2) HLR fallback
const hlr = await hlrProvider.lookup(msisdn, { timeoutMs: 3000 }).catch(() => null)
if (hlr) return save(msisdn, normalize(hlr))
// 3) Prefix as last resort (low confidence)
const inferred = inferByPrefix(msisdn)
return { ...inferred, isPorted: true } // mark as uncertain
}
Key point: explicitly mark confidence level and source (np|hlr|prefix) so business logic can respond appropriately.
Fraud Signals Around Porting
Porting is often used in fraud/ATO schemes:
- Fresh Port (< 7 days): elevated risk for SMS OTP/2FA — request additional verification.
- Frequent Ports (n transfers within 90 days): risk flag.
- Carrier Mismatch: discrepancy between geo/payment instrument and current operator.
Recommendation: mark such cases as risk=high, request alternative verification channel (push/email/WebAuthn).
Implementation Notes
- Number normalization: E.164, cleanup, auto-add country code on backend.
- TTL: MNP 24h, HLR 1–4h, prefix 1h. Update on events (SMS delivery errors, user complaints).
- Rate limits: HLR is expensive — set budget and degrade to NP/prefix.
- API response:
{ isPorted, current: { mcc,mnc,carrier }, portedAt, confidence, source }.
Monitoring and SLAs
- Metrics: % correct operators (by SMS delivery/DR), average latency, provider error rate, fresh port percentage.
- Alerts: spike in fresh ports, OTP delivery failure, increase in HLR timeouts.
- SLA: p95 < 400ms via cache; operator accuracy > 98% on validation deliveries.
Start with Cleariflow Phone Validation API for format and region detection. Add MNP/HLR providers separately when you need current operator or line-status data.