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_statusreadsVERIFIED. - Registered. You called
POST /{phone-number-id}/registerwithmessaging_product: "whatsapp"and a six-digitpin. 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
- 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.
- The agency with 40 senders. Every reply is routed by looking up the tenant whose
phone_number_idmatches the one invalue.metadata. Nothing in the send path knows a default number exists. - The Brazilian contact list. Half the imported numbers failed until the team started persisting the
wa_idfrom the send response instead of trusting the CRM's stored formatting. - 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
tofield, 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.