# How to evaluate a phone number validation API: a buyer's checklist

> The criteria that matter when you choose a phone-intelligence API: coverage, conclusive rates, unknown billing, latency, freshness, privacy and test mode.

Canonical: https://mobilevalidate.com/blog/phone-number-validation-api-buyers-guide · Last updated: 2026-09-25

![Cover: How to evaluate a phone number validation API: a buyer's checklist](https://mobilevalidate.com/og/blog/phone-number-validation-api-buyers-guide.png)


By MobileValidate team (https://mobilevalidate.com/about) · Published: 2026-09-25 · Category: Guides · Tags: Phone validation, API, Buyers guide, Data quality, Privacy

To evaluate a phone number validation API, test it on your own numbers and measure how many checks come back conclusive, what unknown answers cost, how fast and how fresh the answers are, and how the provider protects the people behind the numbers. Marketing pages rarely answer these questions. A two-week trial with a structured checklist usually does. This guide gives you that checklist.

## What should a phone-intelligence API actually answer?

Start with your own questions, not the provider's feature list. "Phone validation" covers several different checks, and each answers a different question:

| Question | Check | Typical use |
|---|---|---|
| Is the number well formed and dialable? | Format validation and normalization | Form input, deduplication |
| What kind of line is it, and which network serves it? | Carrier and line type lookup | SMS cost control, sign-up risk |
| Is the phone reachable on its network right now? | Live network query (HLR) | Pre-send checks, list hygiene |
| Can the number receive messages on app X? | Messaging registration check | Channel selection |
| Has the number been reported for spam or fraud? | Reputation check | Call screening, fraud review |

Our comparison of [HLR, MNP and number validation](/blog/hlr-vs-mnp-vs-number-validation) explains the network checks in detail. Write down which questions you need answered, for which countries, and whether you need the answer in real time or in bulk. That list is your evaluation scope. A provider that answers ten questions you don't have isn't better than one that answers your three well.

## How do you judge coverage claims?

Ask for coverage **per service and per country**, in a form you can check. A single "global coverage" claim hides the fact that data depth varies a lot between markets and between check types.

Good signs:

- The catalog states which countries each service supports, and numbers outside them get an explicit status such as `unsupported_country` instead of a guess.
- Services with uneven data are labelled, for example as beta.
- The provider distinguishes "we checked and found nothing" from "we could not check".

MobileValidate publishes this in [`GET /v1/services`](/docs/services). Each entry lists `countries` (empty means any country), `modes` (real time, bulk or both) and a `beta` flag. The carrier lookup, for example, answers for every country but is marked `"beta": true` because coverage varies. The US/CA carrier lookup lists `"countries": ["US", "CA"]` and runs in bulk only.

## Why does the conclusive rate matter more than "accuracy"?

Because an answer you can't act on has no value, however accurate the other answers are. Every check has three possible outcomes: a definite yes, a definite no, and unknown. The **conclusive rate** is the share of checks that end in yes or no.

Ask the provider for conclusive rates by country and service, then verify them on your own sample:

1. Take a few hundred numbers you already hold with a lawful basis, such as recent customers, spread across the countries you care about.
2. Run every check you plan to buy.
3. Count yes, no and unknown per country.
4. Where you have ground truth, for example numbers that recently received and answered a message, compare it with the answers.

Be careful with providers that never return unknown. Timeouts and gaps exist everywhere. An API that always says yes or no is filling the gaps with guesses. Look for an explicit third state (for example `registered: null`) with a machine-readable `reason`, and a timestamp such as `checked_at` on every conclusive answer.

## How should unknown answers be handled and billed?

Unknown answers should be free, clearly marked and never silently converted into "no". Ask for the billing rule in writing, and check it on a usage report during your trial.

At MobileValidate the rule is simple. You're not charged for inconclusive results (unknown, unsupported country, timeout, invalid, duplicate). Billing works as reserve, settle and release. A request reserves its maximum possible cost, each check settles when its answer arrives, and inconclusive checks are released.

Three more cost controls are worth asking about:

- **A free estimate before bulk work.** Our `POST /v1/jobs/estimate` counts valid, invalid, duplicate, cached, unsupported and suppressed rows and returns the maximum cost without checking anything.
- **A hard cost ceiling per request.** Our `max_cost` field refuses a request whose maximum possible cost is higher, with `402 cost_limit_exceeded`.
- **Deduplication before billing.** Two spellings of the same number should count once.

Cost per check is only part of the picture. What matters is **cost per conclusive answer**: total spend divided by the number of yes and no answers you actually received.

## What latency and freshness should you expect?

Ask how long answers take, what happens when they take longer, and how old a returned answer can be.

**Latency.** Some checks answer in milliseconds from reference data. Others need a live query and take seconds. A good API tells you which is which and doesn't make you hold a connection open indefinitely. Ours waits up to `wait` seconds (default 10, maximum 30) and then returns `202` with `status: "pending"` and a `poll_url`. You can long-poll `GET /v1/lookups/{id}` or receive a signed `lookup.completed` webhook. In a sign-up form, you want a short wait and a default path for anything still pending.

**Freshness.** Every conclusive answer should carry the time it was obtained. Caching is fine, and it saves money, as long as it is visible. Ask:

- Is the cache per customer, or are answers shared across customers? Ours is per account.
- Does a cached answer say so? Ours returns `cached: true` and `age_seconds`, and cache hits aren't billed.
- Can you force a fresh check? Ours accepts `max_age: 0`, which is billed and rate limited.

## What should you ask about privacy and retention?

Phone numbers and e-mail addresses are usually personal data, so the provider processes personal data on your behalf. Under the [GDPR](https://eur-lex.europa.eu/eli/reg/2016/679/oj), that requires a contract meeting Article 28: the processor acts only on your documented instructions, keeps the data secure, tells you about sub-processors and lets you object to changes, and deletes or returns the data at the end (Article 28(2) and 28(3)). Consult your own counsel on what applies to you.

Questions to put in your provider questionnaire:

| Topic | What to ask |
|---|---|
| Contract | Is a data processing agreement available? How are sub-processors disclosed? |
| Retention | How long are inputs and results kept by default? Can you shorten it or delete on demand? |
| Minimization | Does the API return only what you asked for? Are profile fields such as names or photos ever returned? |
| Exposure | Are numbers kept out of URLs and logs? Are identifiers masked in dashboards and downloads? |
| Objections | Can the people whose numbers are checked object, and is that honoured? |

Our answers are on the [trust page](/trust): real-time lookups are kept for 7 days and bulk jobs for 30 days by default, identifiers are masked wherever people see them, and numbers are only accepted in request bodies. Checks never return names, photos or profiles. Our [privacy checklist for phone and e-mail checks](/blog/privacy-checklist-for-phone-and-email-checks) covers your side of the work.

## What anti-abuse controls should a responsible provider have?

A phone-intelligence API can be misused to find out who uses a messaging app, or to build contact lists from number ranges. A provider that doesn't guard against that is a risk to you as a customer, because your data sits on the same platform and your brand may be associated with it.

Look for:

- **Anti-enumeration rules.** We refuse requests with 20 or more consecutive numbers (`403 suspected_enumeration`) and generated e-mail lists.
- **Daily caps and spend caps** per account and per key, visible through an endpoint such as `GET /v1/limits`.
- **A suppression list** for people who object, applied before any check.
- **An acceptable use policy** that forbids unsolicited messaging and profiling, and is enforced.

The same thinking applies to your own integration. [OWASP's API Security Top 10](https://owasp.org/API-Security/editions/2023/en/0xa4-unrestricted-resource-consumption/) lists unrestricted resource consumption as a risk, including missing spending limits on paid third-party services such as SMS. Put a check behind your own rate limits, and set a spending ceiling on it.

## How good is the developer experience?

You will live with the integration for years, so evaluate it like any other dependency.

- **Test mode.** Documented test numbers that return every state (registered, not registered, unknown, pending, unsupported and errors) let you build every branch without real personal data. Our [test mode](/docs/test-mode) uses the UK's reserved drama range `+44 7700 900000–900999`.
- **A machine-readable contract.** An [OpenAPI](https://spec.openapis.org/oas/v3.1.0.html) description lets you generate clients and give coding agents the exact contract. Ours is at [/docs/openapi](/docs/openapi).
- **Predictable errors.** Stable error codes, a `retryable` flag and a request ID. Ask to see the [errors reference](/docs/errors).
- **Safe retries.** Idempotency keys on every POST, so a retry never double-charges.
- **Standard headers and webhooks.** Rate-limit state in headers such as those in the IETF [RateLimit header fields draft](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/), and webhooks signed to a published scheme such as [Standard Webhooks](https://www.standardwebhooks.com/).
- **SDK, CLI and agent access.** A typed SDK saves boilerplate. If AI agents will call the checks, an MCP server built to the [Model Context Protocol](https://modelcontextprotocol.io/specification/2025-06-18) specification should come with spend caps and scoped keys. See our [MCP docs](/docs/mcp).

## What does a real evaluation request look like?

Send one request that exercises the edge cases, not just the happy path. This test-mode call mixes a registered number, a national-format number, a malformed one and two e-mail addresses:

```bash
curl https://api.mobilevalidate.com/v1/lookup \
  -H "Authorization: Bearer $MOBILEVALIDATE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"numbers": ["+447700900001", "07700 900002", "12345"],
       "emails": ["registered@test.mobilevalidate.com", "not-registered@test.mobilevalidate.com"],
       "default_country": "GB", "checks": ["carrier", "whatsapp", "email"], "wait": 5}'
```

The totals from the real test-mode response:

```json
"summary": {"total": 5, "registered": 2, "not_registered": 1, "unknown": 1, "pending": 0,
            "invalid": 1, "suppressed": 0,
  "by_service": {
    "network.carrier":     {"completed": 1, "registered": 1, "not_registered": 0, "unknown": 1, "pending": 0},
    "whatsapp.registered": {"completed": 2, "registered": 1, "not_registered": 1, "unknown": 0, "pending": 0},
    "email.valid":         {"completed": 2, "registered": 1, "not_registered": 1, "unknown": 0, "pending": 0}}},
"billing": {"billed_units": 0, "cost": {"amount": "0", "currency": "USD"}}
```

What to look for in any provider's version of this: `07700 900002` was normalized to `+447700900002` using `default_country`. `12345` came back as `invalid_number` with no checks run. The carrier lookup returned `unknown` with `reason: "NO_DATA"` for the second number instead of a guess. And the summary counts unknowns separately. (`billed_units` is 0 because test keys never bill.)

## What does the checklist look like?

Copy this table into your evaluation document and fill in one column per provider.

| Criterion | What good looks like | How to verify |
|---|---|---|
| Scope | Answers the questions you listed, in the modes you need | Service catalog, `modes` per service |
| Coverage | Per-country support stated; `unsupported_country` instead of guesses | Catalog plus your own sample |
| Conclusive rate | Published per service and country; matches your sample | Run a few hundred numbers you hold |
| Unknown handling | Explicit third state with a `reason`; never coerced to "no" | Test-mode unknown and timeout cases |
| Billing | Inconclusive, invalid and duplicate results free; estimate and cost cap | Usage report after the trial |
| Latency | Clear wait, poll and webhook model; no endless open connections | Time real-time calls from your region |
| Freshness | `checked_at` on every answer; visible cache age; forced refresh option | Repeat a check and compare |
| Privacy | Article 28 DPA; sub-processor disclosure; short default retention; masking | Contract and trust documentation |
| Anti-abuse | Enumeration refusal, caps, suppression, enforced AUP | Send a consecutive range in test mode |
| Test mode | Deterministic test numbers for every state and error | Build every branch before going live |
| Docs and tooling | OpenAPI, stable error codes, idempotency, signed webhooks, SDK, MCP | Integrate one flow end to end |

## What are the key takeaways?

- Define your questions and countries first. Evaluate providers against that scope, not against feature counts.
- Measure the **conclusive rate** on your own numbers, and compare **cost per conclusive answer**, not price per check.
- Insist on an explicit unknown state with a reason and a timestamp on every answer. Unknowns should be free.
- Check freshness and caching: `checked_at`, visible cache age, a per-customer cache and a way to force a fresh check.
- Treat privacy and anti-abuse controls as selection criteria: an Article 28 DPA, short retention, masking, enumeration limits and suppression.
- Use test mode to build every branch before any real number is checked. Start with our [test numbers](/docs/test-mode) and the [services reference](/docs/services).

## Sources

1. [API4:2023 Unrestricted Resource Consumption](https://owasp.org/API-Security/editions/2023/en/0xa4-unrestricted-resource-consumption/) — OWASP API Security Project, 2023
2. [General Data Protection Regulation (EU) 2016/679](https://eur-lex.europa.eu/eli/reg/2016/679/oj) — European Union, 2016
3. [OpenAPI Specification v3.1.0](https://spec.openapis.org/oas/v3.1.0.html) — OpenAPI Initiative, 2021
4. [Standard Webhooks](https://www.standardwebhooks.com/) — Standard Webhooks, 2026
5. [RateLimit header fields for HTTP (draft-ietf-httpapi-ratelimit-headers)](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/) — IETF, 2026
6. [Model Context Protocol specification (2025-06-18)](https://modelcontextprotocol.io/specification/2025-06-18) — Model Context Protocol, 2025

## Frequently asked questions

### What is the single most important number to ask a phone-intelligence provider for?

The conclusive rate per service and per country: the share of checks that return a definite yes or no instead of unknown. Headline accuracy figures mean little if a large share of your numbers never get a conclusive answer.

### Should I pay for unknown answers?

Ideally not. An unknown answer gives you nothing to act on. Ask how the provider bills timeouts, unsupported countries, invalid input and duplicates, and check it on a real invoice or usage report during your trial.

### How can I test an API without using real phone numbers?

Look for a test mode with documented test numbers that return every state: registered, not registered, unknown, pending, unsupported and the main errors. That lets you build and test every branch without touching real personal data.

### Is a lower price per check always cheaper?

Not necessarily. What you pay per useful answer depends on the conclusive rate, whether unknowns and duplicates are billed, and whether repeat checks are served from a free cache. Compare cost per conclusive answer on your own sample.
