Three different questions hide inside the word validation. One asks whether the number is shaped like a real number. One asks whether a network answers for it at all. One asks whether the person you are talking to holds it. Each needs a different check. Each leaves something unknown.

## What can a format check tell you?

That the number belongs to a range a carrier is allowed to assign.

[Google's libphonenumber](https://github.com/google/libphonenumber/blob/master/FAQ.md), the number-parsing library most of the industry uses, treats a range as valid when carriers are free to hand its numbers to subscribers. Its FAQ:

> A valid number range is one from which numbers can be freely assigned by carriers to users.

Validity says nothing about whether a particular number has been handed out or answers. The same page:

> Do not rely on libphonenumber to determine whether numbers are currently assigned to a specific user and reachable.

So a format check answers a question about the numbering plan. It says nothing about whether the range has been assigned to anyone, and nothing about whether a phone rings.

Dialing is not a substitute test either. The FAQ gives two reasons a call can connect to a number that is not valid. Some countries ignore extra digits on the end, so `1800 MICROSOFT` reaches a shorter number. During a renumbering, some operators keep old numbers working after they have stopped working generally.

## What does a network lookup add?

The parts of the answer that only a network holds.

A lookup asks carrier and number-intelligence sources about a specific number rather than about its range. That moves several questions from unknown to answered:

| Check           | What it returns                                                                 | What it still leaves open                                 |
| --------------- | ------------------------------------------------------------------------------- | --------------------------------------------------------- |
| Format          | The number parses and sits in an assignable range                               | Whether the range is assigned to anyone                   |
| Line type       | Whether the number is mobile, fixed line, VoIP, toll-free or machine-to-machine | What service the range is allocated to at finer precision |
| Serving network | The network answering for the number now, and the one that issued it            | Whether a handset is switched on                          |
| Porting state   | When the number last moved network                                              | Nothing about the subscriber                              |
| Presence        | Whether the number is registered and able to receive traffic right now          | Who is holding the handset                                |
| Possession      | Nothing. A lookup never asks the person                                         | Whether your user controls the number                     |

The last row is the one that matters for a signup flow. No lookup establishes possession, because a lookup never involves the person.

## What only a verification challenge can prove?

That whoever is in your flow can receive traffic at that number.

The libphonenumber FAQ treats a challenge as the only workable answer, because numbering practice differs too much between countries for anything else to settle it:

> This is not technically feasible without such a verification step given the complicated international world we live in, with varying standardization practices in different regions.

Sending a code and accepting it back is therefore a different kind of check from the two above. It costs a message and a round trip. It is also the only one that ties the number to the person in front of you. [What does OTP mean](/explained/verify/what-does-otp-mean) covers the code itself, and the [Verify guide](/docs/guides/verify/overview) covers running the challenge.

## How do I read a check nobody could answer?

As unknown, which is not the same as no.

A number whose presence could not be determined is not an unreachable number. Treating the two alike blocks customers whose networks simply did not answer.

Bird keeps them apart in the response. Each property you request reports its own `status`:

- `ok`: the property was answered and its value is present.
- `unavailable`: no answer arrived, so the block is `null`.
- `inconclusive`: an answer arrived that does not resolve the property.

Only `ok` carries a value. A presence block with `status: ok` and `reachable: false` is a real negative, because the network answered and reported the number as unreachable.

So branch on `ok` first. Treat everything else as not answered. The status vocabulary is an open enum, so an unrecognized value is a future status rather than an error. Branching on `ok` therefore stays correct as the vocabulary grows.

## How do I look one up on Bird?

Send the number to the lookup endpoint. Read the blocks you asked for.

`POST /v1/lookup/phone-number` takes a `phone_number` and an optional `type` array. Every lookup returns the serving and issuing networks, the porting state, the country and the line type. The `type` array adds `classification`, `porting`, `presence`, `roaming`, `sim_swap` or `score`, each billed separately and only when it is delivered. The lookup does not contact the number.

Reusing an `Idempotency-Key` returns the stored result rather than performing and billing a second lookup. The [lookup guide](/docs/guides/lookup/phone-numbers) covers the flow and the [API reference](/docs/api/reference/create-phone-number-lookup) covers the fields.

## Related resources

- [SMS numbers](/products/sms/numbers) (product)
- [Number types](/docs/guides/numbers/number-types) (docs)
- [What is a virtual phone number (VMN)?](/explained/numbers/what-is-a-virtual-phone-number) (answer)

[Get an implementation brief](/learn/workspace?topic=phone-numbers)
