# 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.

Canonical: https://mobilevalidate.com/docs/test-mode · Last updated: 2026-09-25

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.

## 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 the US, Canada and Germany. In test mode the whole `+44 7700 9xxxxx` range is also allowed, so the documented numbers work:

| 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` |
| other numbers in the test range, US, CA or DE | 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 about live network status (HLR)?

`number.hlr` is **coming soon**. While it is switched off, test keys get `403 service_disabled` just like live keys. When it launches, the test numbers will answer: `…001` reachable (`mcc_mnc: "23415"`, `country: "GB"`), `…002` unreachable, `…003` unknown, `…004` pending then reachable, `…005` unsupported country, `…006` reachable and `ported: true`.

## 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:

```json
{
  "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.
