Test mode
Every MobileValidate test number and test e-mail address, and the exact answer each one returns with a test key: registered, unknown, pending, errors.
Last updated
View as Markdown
Test keys (mv_test_…) give you free, predictable answers so you can build and test every branch of your integration. They never reach a real network and are never billed. They follow the same validation, request limits and request shapes as live keys; daily caps, spend caps and the daily e-mail-pattern rule apply only to live keys. The test numbers and addresses below always return the same result.
The public sandbox key used in the examples on this site is a test key that accepts only these documented values. Any other input returns 403 sandbox_magic_only. A personal test key accepts any number or address.
Which test numbers can I use?
The test numbers come from the +44 7700 900000–900999 range, which the UK regulator reserves for drama and is never assigned to anyone. Live keys refuse the whole +44 7700 9xxxxx block. These answers apply to every yes/no service (WhatsApp, Telegram, Viber, account checks and so on):
| Number | Result |
|---|---|
+447700900001 | registered: true, confidence high |
+447700900002 | registered: false |
+447700900003 | unknown (registered: null, reason: "UPSTREAM_TIMEOUT") |
+447700900004 | pending for about 5 s, then registered: true (real-time lookups only; in jobs it answers at once) |
+447700900005 | unsupported_country |
+447700900006 | registered: true; business: true for whatsapp.business |
+447700900429 | the whole request fails with 429 rate_limited |
+447700900402 | the whole request fails with 402 insufficient_balance |
| any other valid number | a stable answer derived from the number (and service), marked "test": true (personal test keys only) |
Services limited to some countries answer unsupported_country for other numbers. The test numbers above are exempt, so they work with every service. Bulk-only services are refused on POST /v1/lookup in test mode too, just as in live mode.
For sample data, demos and screenshots outside the API, take numbers from ranges regulators reserve for fiction with the free test phone number generator, never random valid numbers.
What do the carrier lookups return in test mode?
network.carrier and network.carrier_us return data rather than yes/no:
| Number | Result |
|---|---|
+447700900001 | {"line_type": "mobile", "carrier": "Test Carrier", "country": "GB"} (network.carrier_us has no country) |
+447700900002 | unknown, reason: "NO_DATA" |
+447700900003 | unknown, reason: "UPSTREAM_TIMEOUT" |
+447700900004 | pending, then the same data as …001 |
+447700900005 | unsupported_country |
| other numbers | the same fake data, with the number's country (network.carrier_us: numbers outside US/CA → unsupported_country) |
As in live mode, a conclusive data answer has registered: true ("data found"). A non-conclusive one has registered: null.
What does spam reputation return in test mode?
number.spam covers all countries except sanctioned ones. Access to it is limited (see the service page): the public sandbox key and accounts without access get 403 service_disabled. With access, the documented numbers return fixed answers:
| Number | number.spam result |
|---|---|
+447700900001 | risk_level: "high", risk_score: 95, reason_regulator: true, reason_community: true, top_category: "robocall", first_seen: "2025-11", last_seen: "2026-08", sources: 2 |
+447700900002 | risk_level: "no_reports", risk_score: 0, all reasons false, sources: 0 (conclusive) |
+447700900003 | unknown, reason: "UPSTREAM_TIMEOUT" |
+447700900004 | pending, then risk_level: "medium", risk_score: 55, reason_community: true, top_category: "warranty" |
+447700900005 | unsupported_country |
| any other number (personal test keys) | a stable level per number (high, medium, low or no_reports) with matching reasons |
All spam test data is invented. None of it comes from real reports.
What do HLR and MNP lookups return in test mode?
number.hlr (live network status) and number.mnp (number portability) share the same test numbers. The MNP answer is the porting part of the HLR answer:
| Number | number.hlr result | number.mnp result |
|---|---|---|
+447700900001 | status: "reachable", ported: false, roaming: false, network: "Test Mobile", mcc_mnc: "23415", country: "GB" | porting: "not_ported", mcc_mnc: "23415", country: "GB" |
+447700900002 | status: "unreachable", otherwise as …001 | porting: "not_ported" |
+447700900003 | unknown, reason: "UPSTREAM_TIMEOUT" | unknown, reason: "UPSTREAM_TIMEOUT" |
+447700900004 | pending, then as …001 | pending, then porting: "not_ported" |
+447700900005 | unsupported_country | unsupported_country |
+447700900006 | status: "reachable", ported: true, network: "Test Mobile Two", mcc_mnc: "23410" | porting: "ported", mcc_mnc: "23410", country: "GB" |
| any other number (personal test keys) | a stable answer per number, mostly reachable, with network: "Test Mobile" and mcc_mnc: "00101" | the porting part of that answer |
As in live mode, unknown and unsupported_country are never billed. Test answers never contain SIM or location identifiers.
Which test e-mail addresses can I use?
The domain is test.mobilevalidate.com. The part before the @ picks the answer for every e-mail service:
| Address | Result |
|---|---|
registered@test.mobilevalidate.com | registered: true |
not-registered@test.mobilevalidate.com | registered: false |
unknown@test.mobilevalidate.com | unknown, reason: "UPSTREAM_TIMEOUT" |
pending@test.mobilevalidate.com | pending for about 5 s, then true (real-time lookups only) |
unsupported@test.mobilevalidate.com | unknown, reason: "UNSUPPORTED_PROVIDER" |
rate-limited@test.mobilevalidate.com | the request fails with 429 rate_limited |
no-balance@test.mobilevalidate.com | the request fails with 402 insufficient_balance |
| any other address | a stable yes/no derived from the address and service |
Live keys may not use this domain (400 test_number_only, "Test e-mail addresses can only be used with test keys.").
What does a test error look like?
The error test numbers return the real error shape, so you can test your retry and top-up handling:
{
"error": {
"code": "rate_limited",
"message": "Too many requests (test mode).",
"status": 429,
"retryable": true,
"param": null,
"doc_url": "https://mobilevalidate.com/docs/errors#rate_limited",
"request_id": "req_0VWF4BOF195D5GjKfh0P"
}
}Test keys are rate limited like live keys (10 requests per second, burst 20). The public sandbox key has its own per-IP limits (30 requests per minute, 1,000 per day). A fast loop can therefore get a real rate_limited answer as well.
With a test key, a pending lookup sends its lookup.completed webhook when the lookup is read again after the 5 seconds (the request's own wait, or a later GET /v1/lookups/{id}). The payload has the same fields as a live one, with "livemode": false. Test jobs finish immediately and send no job webhooks.
Frequently asked questions
Are test numbers real phone numbers?
No. They come from the +44 7700 900000–900999 range, which the UK regulator reserves for drama and fiction and never assigns to subscribers.
What happens if I send a real number with a test key?
You get a fake but stable answer: a hash of the number (and service) decides it, so the same number always gives the same result. Nothing is sent to any network and nothing is billed.
Can I use test numbers with a live key?
No. A live key sending a test number or a test-domain address gets 400 test_number_only, so test data never ends up in real billing.

