Developers

How long is a phone check result valid? Caching HLR, MNP and messaging-app answers

Each phone signal goes stale at its own speed. How often to re-verify numbers, how to cache HLR, MNP and messaging-app answers, and how long to keep them.

By Published 8 min read

On this page

A phone check result is valid for as long as the thing it measured stays the same, and that differs by signal. Format validity lasts until the numbering plan changes. Carrier and porting data last until the number moves network. Live reachability from an HLR lookup can change within minutes. So re-verify each signal on its own schedule: fresh for one-time passcodes, on failure for routing, before each campaign for lists, and once at entry for sign-ups.

Why doesn't one answer last forever?

Every check answers a question about a moment. checked_at in each result says which moment. The question is how quickly the real world drifts away from that answer.

Some answers describe the number itself. "Is +44 7700 900001 a possible mobile number in the UK?" only changes when the regulator changes the numbering plan. Others describe the subscriber or the handset. "Is the phone reachable?" changes whenever someone switches their phone off, lands after a flight or loses signal.

If you cache everything for the same period, you get one of two failures. A long cache sends codes to phones that went dark hours ago. A short cache pays again and again for answers that hadn't changed. The fix is a per-signal policy.

Three hourglasses of growing size for network status, porting and number format, a cache card with a free repeat answer, a force-fresh switch, a re-check timeline and a 45-day calendar.Three hourglasses of growing size for network status, porting and number format, a cache card with a free repeat answer, a force-fresh switch, a re-check timeline and a 45-day calendar.
Network status goes stale in hours, porting in weeks and number format rarely: re-check at the right pace.

How fast does each signal change?

The table below is a practical guide, not a guarantee. The speeds describe what typically changes each answer, so you can reason about your own traffic.

SignalWhat changes itHow fast it can go staleSensible re-check trigger
Format and validity (number_status)Numbering-plan updatesRarely for a given number, but rules change somewhere every few weeksWhen you update your validation library
Line type and carrier (carrier lookup)Porting, disconnection, reassignmentWeeks to years for most numbersDelivery failure, before large sends
Current network and porting (MNP lookup)A port to another networkAny day, but rare per numberDelivery failure, routing reviews
Live reachability (HLR lookup)Phone off, out of coverage, roamingMinutes to hoursRight before a time-critical send
Messaging-app registration (e.g. WhatsApp)User joins, leaves or changes numberDays to monthsBefore choosing a channel for a campaign
Reassignment to a new personDisconnection, then aging, then reuseWeeks after disconnectionBefore contacting an old record
Spam reputationNew complaints, reports, list updatesDays to weeksWhen the number calls or signs up again

Two rows need more context.

Validity. A number doesn't become invalid on its own, but the rules around it do. Our research on numbering-plan changes found updates to validity rules arriving every couple of weeks somewhere in the world. That matters for your stored number_status: invalid_number rows: a number you rejected under old rules may be valid now. Re-run format validation on stored numbers after a library update. It costs nothing, because format checks aren't billed.

Porting. The carrier a number was first given to is often not the one serving it today. Our guide to why carrier lookups go wrong explains how porting breaks prefix-based guesses. For caching, the point is simpler: a port is a one-off event per number, so a carrier answer stays correct until it doesn't. A failed delivery is the cheapest signal that it may have changed.

What does number reassignment mean for stored results?

Reassignment is the slowest-moving and most dangerous change, because nothing in the number itself tells you it happened. A disconnected number goes back into the carrier's pool and is later given to someone else. Every answer you cached before that describes a different person.

In the US, FCC rules define "aging numbers" as disconnected numbers held back from reassignment for a set period. Numbers from residential customers may be aged for no less than 45 and no more than 90 days, and business numbers for 45 to 365 days [1]. So a US mobile number can belong to someone new within weeks of the old owner leaving. Other countries set their own periods.

No carrier, HLR or messaging-app check proves ownership. A change since your last snapshot, such as a different network or a messaging account that appeared, only suggests the number may have changed hands. For US numbers with a known consent date, the FCC's Reassigned Numbers Database is the tool built for that question.

When should you re-check? A starting policy by use case

Tie the re-check to the decision you're about to make, not to a calendar alone.

Use caseChecksWhen to re-checkWhy
OTP right before sending a codeHLR, optionally carrierAlways freshReachability changes by the minute; a stale "reachable" wastes a code
Sign-up or account creationCarrier, messaging appOnce, when the number is enteredYou need the answer at the decision point, not later
Change of phone number on an accountCarrier, HLRAt the change, then compare with the stored valueA sudden port or new network is a takeover signal
SMS routing (A2P)MNP or carrierCache, then re-check on a delivery failurePorts are rare per number, failures are the cue
CRM list before a campaign to opted-in contactsCarrier, the channel you send onBefore each campaignLists decay between sends
Dormant records (no contact in months)Carrier, messaging app, RND for USBefore any contactReassignment risk grows with time
Inbound call screeningSpam reputation (approved customers)Per call, with a short cacheReputation moves with new reports

Start here, then measure. Re-check a sample of numbers and count how many answers changed since the last check. If very few changed, stretch the interval. If many changed, shorten it. The SMS routing use case and CRM data hygiene pages show where these checks sit in each flow.

How does caching work in MobileValidate?

MobileValidate keeps a cache per account, keyed by the number (or e-mail address) and the service. You control how old an answer you'll accept with max_age, in seconds, on both real-time lookups and bulk jobs.

  • No max_age: the default is each service's own freshness window.
  • max_age: 600: accept a cached answer up to 10 minutes old; anything older is checked again.
  • max_age: 0: force a fresh check. It is billed when the answer is conclusive, and it counts against rate limits.

Every result tells you where it came from. cached: true means it was served from your cache. age_seconds gives its age and checked_at gives the time the answer was obtained. A cache hit has billed: false: repeat checks inside the window are free.

That changes the maths of a re-check policy. At the time of writing, the pricing page lists the HLR lookup at $0.005 per number and the MNP lookup at $0.001, in real time and bulk alike. The carrier lookup is $0.002 in real time and $0.001 in bulk. A loose max_age on a flow that re-checks the same number often, such as a resend button, costs nothing extra. A max_age: 0 on every page view costs a check each time. You're not charged for inconclusive results (unknown, unsupported country, timeout, invalid, duplicate), and numbers from sanctioned countries and regions are never checked.

How do you set max_age per decision?

Keep the policy in one place, next to the decision it serves. The values below are examples. Pick your own from what you measure.

JavaScript
// max_age in seconds, per decision (example values, tune to your data)
const MAX_AGE = {
  otp_send: 0,             // reachability right now: always fresh
  signup: 24 * 3600,       // a retry within a day reuses the first answer
  routing: 7 * 24 * 3600,  // carrier/MNP: re-check sooner on a failed delivery
  campaign: 30 * 24 * 3600 // list re-check before each campaign
};

async function check(numbers, checks, decision) {
  const res = await fetch("https://api.mobilevalidate.com/v1/lookup", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.MOBILEVALIDATE_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ numbers, checks, max_age: MAX_AGE[decision] }),
  });
  return res.json();
}

// Before sending a code:
const r = await check(["+447700900001"], ["hlr"], "otp_send");
const hlr = r.results[0].checks["number.hlr"];
// hlr.cached, hlr.age_seconds and hlr.checked_at show how fresh the answer is

When a delivery fails, don't wait for the scheduled refresh. Call the same function with max_age: 0 for that one number and the routing check, then update your stored value. Our comparison of delivery receipts and HLR lookups explains which failure codes are worth a re-check.

Which events should trigger a re-check?

A calendar policy misses changes that happen between runs. Events catch them sooner and only cost a check when something happened:

  • A delivery failure or a bounced message. The most direct sign that the stored answer no longer fits.
  • A change of contact details. Check the new number, and compare the old and new networks.
  • A sensitive action. Password reset, payout details or a large order. Check before, not after.
  • A long gap. A record untouched for months is a candidate for a fresh check before any contact.
  • A validation-library update. Re-run format checks on stored numbers. They are free.

How long should you keep results?

Caching is about how old an answer you'll trust. Retention is about how long you keep it at all. They are different questions.

A phone check result linked to a customer is personal data. The GDPR's storage-limitation principle says personal data must be kept in a form that identifies people for no longer than necessary for the purpose [2]. In practice: keep the latest answer you use for a decision, with its checked_at, and delete older snapshots once they no longer serve a purpose you can name. Our privacy checklist covers the rest.

On our side, real-time lookups are kept for 7 days. Bulk jobs are kept for 30 days by default, and each account can set this from 1 day to 24 months. DELETE /v1/jobs/{id} removes a finished job's data at any time, and logs hold masked identifiers only.

What are the common mistakes?

  • One TTL for everything. Reachability and format validity don't age at the same speed.
  • Treating an old "reachable" as live. An HLR answer from yesterday says nothing about the phone right now.
  • Forcing fresh checks by default. max_age: 0 on every call pays for answers that hadn't changed.
  • Reading a changed answer as proof of a new owner. It is a hint. Confirm before you act on it.
  • Keeping every historical snapshot forever. Storage limitation applies, and old snapshots rarely help a decision.
  • Blocking on unknown. An unknown answer isn't charged and isn't a negative. Fall back to your default rules.

What are the key takeaways?

  • A result is valid only as long as the signal it measured stays the same. Validity, carrier, porting, reachability, app registration and reputation all change at different speeds.
  • Use fresh HLR answers for time-critical sends, cached carrier and MNP answers for routing, and re-check lists before each campaign.
  • Trigger re-checks on events such as failed deliveries and contact changes, not only on a calendar.
  • In MobileValidate, max_age sets the oldest answer you'll accept. Cache hits are free, max_age: 0 forces a billed fresh check, and inconclusive results are never charged.
  • In the US, disconnected numbers can be reassigned after as little as 45 days, so old records need a fresh look before contact.
  • Keep only the results you need, for as long as you need them.

Sources

  1. 47 CFR 52.15: Central office code administration, paragraph (f)(1)(ii) (aging numbers) — eCFR / Federal Communications Commission
  2. Regulation (EU) 2016/679 (General Data Protection Regulation), Article 5(1)(e) — EUR-Lex, Official Journal of the European Union, 2016

Frequently asked questions

How often should I re-verify phone numbers?

It depends on the signal and the decision. Check reachability right before a one-time passcode, re-check the carrier when a delivery fails or before routing a large send, re-check a marketing list before each campaign, and check a sign-up number once when it enters your system. Treat these as starting points and tune them to the change rate you measure.

How long is an HLR lookup result valid?

Only briefly. An HLR answer describes the phone's state at the moment of the query, and a phone can be switched off or come back into coverage within minutes. Use a fresh HLR answer for decisions that happen right now, such as sending a code, and don't treat an old reachable answer as proof the phone is on today.

Are cached MobileValidate answers charged?

No. Repeat checks of the same number or address inside the freshness window come from your account's cache and are marked cached: true and billed: false. Sending max_age: 0 forces a fresh check, which is billed when the answer is conclusive. Inconclusive results are never charged.

Does a carrier lookup go out of date?

Yes, when the number is ported to another network or disconnected and reassigned. The line type and current network are stable for most numbers most of the time, so a cached answer is usually fine for routing, but re-check it when a message to that number fails.

How long should I store phone check results?

No longer than your purpose needs. Under the GDPR's storage-limitation principle, personal data may be kept in identifiable form only as long as necessary. MobileValidate keeps real-time lookups for 7 days and bulk jobs for 30 days by default, configurable from 1 day to 24 months.

All articles

Know before you send.

Tell us about your use case. We review every request and set you up with test and live keys.