Phone number lookup

Know what a number is. Before you send to it.

One POST, one answer, no resource to create or poll. The base lookup returns the number's country, the network serving it today, the network that issued its range, a flag saying whether it has moved between the two, and what kind of line it is. Five further properties are yours by naming them.

phone-number.ts
200
const answer = await bird.lookup.phoneNumber({
  phone_number: "+31612345678",
  type: ["classification", "porting"],
});

console.log(answer.country_code, answer.line_type);
// → "NL" "mobile"
console.log(answer.network_info?.carrier_name);
// → "KPN"
console.log(answer.original_network_info?.carrier_name);
// → "Vodafone"
console.log(answer.flags);
// → ["ported"]

if (answer.porting?.status === "ok") {
  console.log(answer.porting.ported, answer.porting.last_ported_at);
  // → true "2021-04-18T00:00:00Z"
}

Two networks, and the gap between them.

That gap is what porting looks like in a response.

Phone number lookup is one of the two operations in the Bird Lookup API. Send a number in international format, with or without the leading plus, and you get back country_code, a network_info block for the carrier serving the number today, and an original_network_info block for the carrier that was allocated its range. When those two disagree the number has been ported, and flags says so. National-only numbers are rejected rather than guessed at, so a bad input fails loudly instead of returning a plausible answer about the wrong country.

What comes back, and when.

The first three arrive with every lookup. The rest arrive when you name them in type.

  1. 01

    Country and both carriers.

    country_code is the ISO country of the range, and it is absent for non-geographic numbers rather than guessed. network_info and original_network_info each carry a carrier name plus the mobile country and network codes, which is what you want if you route on MCC and MNC rather than on a name.

  2. 02

    Line type, from a closed list.

    mobile, fixed_line, voip, toll_free, premium_rate, satellite, pager, payphone, m2m, service, other, or unknown. The list is closed, so a switch over it stays exhaustive, and it is the field to check before you decide an SMS is even possible.

  3. 03

    The ported flag, at no extra charge.

    flags carries ported when the number has moved network at any point. It arrives with the base answer, so the cheap question of whether a number has ever been ported needs no property at all.

  4. 04

    classification, a second opinion on the line.

    A finer reading from a different source, with values line_type does not have: fixed_line_or_mobile, shared_cost, national_rate, personal_number, isp, voice_mail, short_codes, and more. It sits beside line_type in the response rather than replacing it, so you can compare the two when a number looks unusual.

  5. 05

    porting, with dates and a history.

    ported as a boolean, last_ported_at as a timestamp, last_ported_at_is_approximate when the registry only knows the month, and history as the list of porting events oldest first. Each event carries a registry-specific action code, which is worth showing and not worth branching on.

  6. 06

    presence and roaming, from the live network.

    presence queries the network and reports reachable, which is the closest thing to asking whether the line is switched on. roaming reports is_roaming plus the MCC and MNC of the visited network, so a signup from a number sitting on a foreign network is something you can see rather than infer.

  7. 07

    score, a single number from 0 to 100.

    A composite credibility score. It is not derivable from the other properties, which is the point of asking for it: one integer you can threshold on in a signup flow without writing rules over carrier names and line types yourself.

Every property tells you whether it answered.

Each block carries its own status: ok, unavailable, or inconclusive. Only ok carries a value, so you never have to inspect a response to work out that it is empty, and a field with no value is left out rather than set to null. The billing follows the same line. The base lookup bills once, a property bills only when its status is ok, and a lookup that fails bills nothing.

properties.ts
200 · partial
const answer = await bird.lookup.phoneNumber({
  phone_number: "+31612345678",
  type: ["presence", "roaming", "score"],
});

// Only a block whose status is ok carries a value.
if (answer.presence?.status === "ok") {
  console.log(answer.presence.reachable);
}

if (answer.roaming?.status === "ok") {
  console.log(answer.roaming.is_roaming, answer.roaming.mcc, answer.roaming.mnc);
}

// unavailable and inconclusive both mean no value, and no charge.
if (answer.score?.status !== "ok") {
  console.log("no credibility score on this answer");
}

One number per request.

There is no batch form, by design: a lookup is a live query against carrier data, and a batch would hide which of a thousand rows was answered and which was not. The rate limit starts at 10 requests a minute per acting credential and Lookup has its own budget, so screening numbers never eats into your sending. Send an Idempotency-Key and a retry replays the answer you already paid for instead of buying a second one.

Go deeper in the docs.

Look up a phone number walks the request and every field it can return. The Lookup overview covers both operations and the property statuses in one page, rate limits documents the lookup group, and idempotency explains what a replayed answer costs.

Phone number lookup questions, answered.

Formatting, line types, porting, and what a lookup does not do.

What does a phone number lookup answer?
The base lookup answers the number's country, the network serving it today, the network that issued its range, whether it has ever moved network, and a coarse line type. It always runs, and if it cannot be answered the whole request fails rather than returning a half-empty answer.
How should I write the number?
Country calling code first, then the national number. The leading plus is optional and 00 works in its place, so +31612345678, 31612345678 and 0031612345678 are all the same number.
Why was my number rejected?
A number written for dialling inside one country, with no country code, returns E22000 rather than being guessed at. Prefixing a country code onto 0612345678 would name a real number somewhere else and bill you for looking that one up instead.
Which line types can it return?
mobile, fixed_line, voip, toll_free, premium_rate, satellite, pager, payphone, m2m, service, other, or unknown. unknown means the carrier platform holds no classification for the range, and other means it holds one with no equivalent here. Request the classification property for the allocated service at finer precision.
How do I tell whether a number has been ported?
network_info is the network serving the number today and original_network_info is the network that issued its range. The two differ once a number has been ported, and flags contains ported in that case. Request the porting property when you also need the date and the full record.
Why is country_code missing from my answer?
Because the number belongs to no single country, as a non-geographic range does. Fields with no value are omitted rather than returned as null, so every field present in the answer was resolved.
Does a lookup call or message the number?
No. A lookup never contacts the number itself. It reads carrier and number-intelligence data, and the presence and roaming properties query the network the number is registered on, so nothing rings and nothing arrives on the handset.

Run your first lookup on a number you know.

The dashboard runs the same operation one number at a time, which is the fastest way to see an answer before you write any code.

Mulai dengan satu channel.
Tambahkan yang lain saat Anda siap.

API key uji coba langsung tersedia untuk Anda. Akses produksi terbuka setelah Anda menambahkan metode pembayaran dan memverifikasi pengirim.

Menggunakan Claude Code, Cursor, atau Codex? Salin prompt pengaturan dan agen Anda akan menginstal Bird CLI dan skill untuk Anda. Pilih milik Anda:

Cursor