GLOSSARY

What is a Phone Number ID?

A Phone Number ID is the opaque numeric identifier the WhatsApp Business Platform assigns to each registered business phone number. It is the value that goes in the send endpoint path, POST /{phone-number-id}/messages, and it is not the phone number itself, not the WABA ID, and not the recipient's wa_id.

Free forever plan · No credit card required · Cancel anytime

Quick definition

A Phone Number ID is the opaque numeric identifier the WhatsApp Business Platform assigns to each registered business phone number. It is the value that goes in the send endpoint path, POST /{phone-number-id}/messages, and it is not the phone number itself, not the WABA ID, and not the recipient's wa_id.

In a single sentence: it is the "from" address, and it looks nothing like a phone number.

What it means

When a phone number is added to a WhatsApp Business Account and verified, Meta mints an internal identifier for it. That identifier is the Phone Number ID. It is a long numeric string, it has no arithmetic relationship to the actual number, and it is the only thing the messaging endpoints accept.

The send call is:

POST /v22.0/{phone-number-id}/messages

There is no version of this endpoint that takes an E.164 number. Media upload is addressed the same way, at /{phone-number-id}/media. Registration, the two-step PIN, and the request for a new display name all hang off the same node. In practice the Phone Number ID is the busiest identifier in the entire integration, which is exactly why it deserves its own place in configuration rather than being pasted into a service class.

The five identifiers people mix up

Nearly every "why is this returning 400" question in a WhatsApp integration reduces to using one of five identifiers in the place of another. They are all numeric, they are all long, and the API error messages are not generous about telling you which one was wrong.

The distinction that bites hardest is phone_number_id against wa_id. Your sender is a Phone Number ID. The customer is a wa_id, which really is their phone number, in digits, with no plus sign and no spaces. So a send has an opaque ID in the path and a real number in the body, which reads backwards the first time you see it.

One more subtlety on wa_id: it is not always identical to the number you stored. Some countries normalise differently, and the classic case is Brazil, where a stored number may carry a digit that the WhatsApp ID does not. The safe pattern is to send to the number you have, then persist the wa_id that comes back in the contacts array of the send response, and use that for everything afterwards.

Verification is not registration

Adding a number produces three states that teams routinely collapse into one:

  • Added. The number exists under the WABA. It cannot do anything yet.
  • Verified. You proved control by entering an SMS or voice code. The field code_verification_status reads VERIFIED.
  • Registered. You called POST /{phone-number-id}/register with messaging_product: "whatsapp" and a six-digit pin. Only now can the number send.

The PIN is the number's two-step verification code. Set it, record it somewhere your team can find it, and expect to need it again: re-registering after a migration requires the same PIN, and a mismatch fails the call. Repeatedly retrying registration also trips a rate limit of its own, so the fix for a failed register is to find the right PIN rather than to loop.

Reading the number's health

The Phone Number ID node is also where you read the operational state that decides whether your campaign will actually go out. A single field query returns the things worth alerting on: quality_rating, the display name and its approval state, the messaging tier, and the throughput level. That last one matters at volume: Cloud API senders start at a default messages-per-second throughput and can be upgraded, and knowing which level a number is on explains queue behaviour that otherwise looks like your own code being slow.

Because these fields are per number rather than per account, a monitoring job that iterates the WABA's numbers and stores the result gives you a quality history Meta does not keep for you in any exportable form.

Why it matters

Multi-number correctness is the reason to care. With one number, an environment variable works and nothing goes wrong. Add a second brand, a second country or a second department, and every place that assumed a single sender becomes a bug: replies leave from the wrong identity, conversation threading merges two audiences, and the quality damage lands on whichever number the hardcoded value pointed at.

The fix is architectural and cheap if you do it early. Store the Phone Number ID alongside the tenant or brand it belongs to, read it from the inbound webhook when replying, and never let a send path default to "the" number.

Real-world examples

  1. The test number that never graduates. Meta gives new apps a test Phone Number ID that can only message a short allow-list. Teams build against it, then ship, and discover the production number has a different ID and a different tier.
  2. The agency with 40 senders. Every reply is routed by looking up the tenant whose phone_number_id matches the one in value.metadata. Nothing in the send path knows a default number exists.
  3. The Brazilian contact list. Half the imported numbers failed until the team started persisting the wa_id from the send response instead of trusting the CRM's stored formatting.
  4. The forgotten PIN. A number migrated between providers could not be re-registered because nobody had recorded the two-step PIN. Recovery meant support tickets and four days of downtime on a live support line.

Common mistakes

  • Putting the E.164 number in the path. The endpoint takes the ID. The number belongs only in the to field, and even there without a plus sign.
  • Hardcoding the ID. It is tenant configuration, not a constant, and it can change on migration.
  • Ignoring the webhook's metadata. Replying with a globally configured sender is the single most common multi-number bug.
  • Confusing the ID with the WABA ID. Templates live on the WABA. Messages live on the number. Neither node accepts the other's ID.
  • Retrying registration in a loop. A wrong PIN does not become right on the fifth attempt, and the attempts themselves are rate limited.

Related concepts

  • WABA: the parent container that owns this number.
  • Quality rating: read from this exact node, per number.
  • Messaging limit: the tier attached to the number, not to the account.
  • Message template: addressed to the WABA but sent from the number.
  • Webhook: carries the Phone Number ID in every inbound payload.
  • Omnichannel CRM: maps several sender identities onto one shared inbox.

How Pinlyx handles it

Pinlyx stores the Phone Number ID per connected sender and resolves the reply identity from the inbound webhook rather than from configuration, so an agency running dozens of numbers never answers from the wrong brand. The connection screen shows the verification status, registration status, display name approval and quality rating for each number side by side, and a background poller records quality history so you can see the slide before Meta flags it. Read more on WhatsApp CRM.

Cheat sheet · five identifiers, one integration

They are all long numbers. They are not interchangeable.

Example values are illustrative, not real accounts.

FieldLooks likeIdentifiesUsed in
phone_number_id106540352242922Your registered business sender.The path of every send call and every media upload.
display_phone_number+90 555 000 00 00The human-readable E.164 number shown to customers.Logs and UI only. Never an API path segment.
waba_id102290129340398The account container that owns the number.Template CRUD and webhook subscription.
wa_id905550000000The customer you are messaging.The "to" field. Digits only, no plus sign.
wamidwamid.HBgLOTA1NTUw...One specific message.Status webhooks, replies in context, read receipts.
Where the ID appears on the wire

Opaque ID in the path, real number in the body.

# Sending: the ID is the sender, "to" is the customer
POST /v22.0/106540352242922/messages
{
  "messaging_product": "whatsapp",
  "recipient_type": "individual",
  "to": "905550000000",
  "type": "text",
  "text": { "body": "Your appointment is confirmed." }
}

# Response: keep the wa_id, it may differ from what you sent
{
  "messaging_product": "whatsapp",
  "contacts": [{ "input": "905550000000", "wa_id": "905550000000" }],
  "messages": [{ "id": "wamid.HBgLOTA1NTUwMDAwMDAwFQIAERgS..." }]
}

# Inbound webhook: reply from THIS id, not from config
{
  "field": "messages",
  "value": {
    "messaging_product": "whatsapp",
    "metadata": {
      "display_phone_number": "905550000000",
      "phone_number_id": "106540352242922"
    },
    "contacts": [{ "profile": { "name": "Ada" }, "wa_id": "905551112233" }],
    "messages": [{
      "from": "905551112233",
      "id": "wamid.HBgLOTA1NTUxMTEyMjMzFQIAEhgU...",
      "timestamp": "1757260800",
      "type": "text",
      "text": { "body": "Can I move it to Friday?" }
    }]
  }
}
Multi-number checklist

Six rules that survive the second phone number.

  • Store the Phone Number ID per tenant or brand, never in a single global setting.
  • Resolve the reply sender from value.metadata.phone_number_id on every inbound event.
  • Persist the wa_id returned by the send response and use it for later sends.
  • Record the two-step registration PIN somewhere your on-call engineer can reach it.
  • Poll quality_rating and the messaging tier per number and keep the history yourself.
  • Never let one integration and one third-party tool both send from the same number.

Phone Number ID: FAQ

The identifier questions that stall most first WhatsApp integrations.

Three places. In the Meta app dashboard under WhatsApp, the API Setup screen shows it directly under the test or production number. Programmatically, GET /{waba-id}/phone_numbers returns every number in the account with its id field. And every inbound webhook carries it at value.metadata.phone_number_id, which is the most reliable source because it is the ID the platform itself used to route the message.
No, and the distinction causes more failed first integrations than anything else. The Phone Number ID is an opaque numeric handle assigned by Meta, typically fifteen digits, with no relationship to the digits of your actual number. Putting the E.164 number in the send path returns an unsupported request error. Treat the ID as configuration you look up and store, never as something you can derive.
Treat it as stable for a registered number in a given WABA, but not as a permanent constant. Migrating a number to a different WhatsApp Business Account, or moving between hosting setups, can issue a new identifier. That is why hardcoding it in source is a bad idea: keep it in configuration, keyed by tenant, and refresh it from GET /{waba-id}/phone_numbers when a migration happens.
Registration is a separate step from verification. Verification proves you control the number by SMS or voice code. Registration, POST /{phone-number-id}/register with messaging_product set to whatsapp and a six-digit two-step verification PIN, is what enables the number to send and receive through the Cloud API. A number that is verified but not registered returns an error on the first send, which is a very common day-one surprise.
Because the reply used a globally configured ID instead of the one in the webhook. When a WABA holds several numbers, every inbound payload tells you which sender the customer messaged, at value.metadata.phone_number_id. Always echo that value back when you reply. Reading it from a single environment variable works perfectly in testing with one number and silently mixes up brands the moment a second number is added.
Technically yes, because access is controlled by tokens rather than by exclusivity, and any app subscribed to the WABA with a valid token can call the send endpoint. Operationally it is a bad idea. Both systems will receive the same inbound webhooks, both may reply, and the customer sees a duplicated conversation. If two tools genuinely need to work the same number, one should own sending and the other should read only.
Ready to ship

Many numbers. One correct reply.

Pinlyx resolves the sending identity from the inbound webhook, so replies always leave from the number the customer wrote to.

Free forever plan · GDPR-ready · No credit card required

We value your privacy

We use cookies to improve our site, analyze traffic, and personalize ads. You can accept all, reject non-essential, or customize your choices. Read our Cookie Policy.