Skip to content
man glossary/webhook-contacts-object

glossary define webhook-contacts-object

Name

Webhook Contacts Object

The contacts array in WhatsApp webhooks that identifies who an event is about: profile name, wa_id and, with usernames, a business-scoped user_id.

Synopsis

contacts array, value.contacts, Webhook contact profile, Sender profile in webhooks

Section

Webhooks & events

Level

practitioner

▍

Reviewed

Who sent this? Read the contacts object

7 / 7
{
"object": "whatsapp_business_account",
"entry": [
{
"id": "102290129340398",
"changes": [
{
"field": "messages",
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "919876543210",
"phone_number_id": "106540352242922"
},
"contacts": [
{
"profile": {
"name": "Ananya",
"username": "ananyareads"
},
"wa_id": "919812345678",
"user_id": "IN.18273645509182736455"
}
],
"messages": [
{
"from": "919812345678",
"from_user_id": "IN.18273645509182736455",
"id": "wamid.HBgMOTE5ODEyMzQ1Njc4FQIAEhggMkM5RTFBQjQ",
"timestamp": "1792390000",
"type": "text",
"text": {
"body": "Is the blue kurta back in size M?"
}
}
]
}
}
]
}
]
}
An inbound message from a customer with a username. Step through each identifier in contacts and see which one stays reliable when the phone number is hidden.

Field 7: entry.0.changes.0.value.messages.0.from_user_id — Same value as user_id. Match on this when from is missing.

Description

What is the webhook contacts object?

The webhook contacts object is the contacts array that every inbound message on the messages webhook carries next to the messages array, describing the sender. It sits inside value, the part of the webhook payload your code reads. Each item has a profile object with the name the user set in WhatsApp, a wa_id (the user's WhatsApp ID, normally their phone number as digits without a leading plus) and, since BSUIDs began appearing in webhooks in early April 2026, a user_id: the business-scoped user ID, written as a country code, a dot and up to 128 alphanumeric characters. If you have enabled parent BSUIDs, a parent_user_id appears too.

WhatsApp usernames change what you can rely on. When a user has adopted a username, profile.username appears, and the phone number — wa_id in contacts and from in the message — is omitted unless you messaged or called that number, or it messaged or called you, in the last 30 days (checked per business phone number), or the user is in your contact book. user_id is always included, and the message carries the same value as from_user_id. Status webhooks follow similar rules: the contacts block leaves out username on sent statuses and is dropped entirely on failed ones.

Do not confuse it with the contacts message type. When a customer shares a contact card, that card is the content of a message (type: "contacts") inside messages[], with names, phone numbers and emails of someone else. The contacts object is metadata about the person who triggered the event. And profile.name is whatever the user typed into WhatsApp — a display hint, never verified identity.

Key takeaways

  • The webhook contacts object is the contacts array beside messages or statuses that says who a WhatsApp event is about.
  • Each item can carry profile.name, profile.username, wa_id and user_id, the business-scoped user ID (BSUID).
  • user_id is always present; wa_id is omitted for username users unless you were in touch within 30 days or they are in your contact book.
  • profile.name is whatever the user typed into WhatsApp — use it for display, never to identify or merge customers.
  • It is not the contacts message type, in which a customer shares someone else's contact card inside messages[].

Properties

The webhook contacts object: key facts and limits

Location
entry[].changes[].value.contacts[]
Always present
user_id (the BSUID)
Sometimes omitted
wa_id, when a username hides the number
Phone shown if
Contact within 30 days, or in your contact book
BSUID format
Country code, dot, up to 128 alphanumerics
BSUID scope
One business portfolio
In webhooks since
Early April 2026
BSUID change
System message on messages; no user_id_update field

Mechanics

How does the webhook contacts object work?

  1. step 1 — Find it next to the event

    Read entry[].changes[].value.contacts[] alongside messages[] (or statuses[]). It is part of the same value, so process them together.

  2. step 2 — Match contact to message

    Pair contacts[].wa_id with messages[].from when the phone is present, or contacts[].user_id with messages[].from_user_id when it is not. Match explicitly rather than assuming item 0.

  3. step 3 — Resolve the customer

    Look up by user_id first, then by wa_id. Create the record if neither matches, and store every identifier you received so later events can match on either.

  4. step 4 — Refresh the display name

    Update profile.name and profile.username as display fields. Never merge two customers or grant access because their names match.

  5. step 5 — Follow identifier changes

    A BSUID is regenerated when a user changes their phone number. There is no user_id_update field to subscribe to: the change arrives on messages as a system message (user_changed_number, or user_changed_user_id when no number can be shared), so map the old ID to the new one when you see it.

Usage

The webhook contacts object in code

"contacts": [{
"profile": { "name": "Arjun", "username": "arjunreads" },
"user_id": "IN.40731866125599102847"
}],
"messages": [{
"from_user_id": "IN.40731866125599102847",
"id": "wamid.HBgMOTE5ODEyMzQ1Njc4FQIAEhggNEFCRDlFQkM",
"timestamp": "1792390400",
"type": "text",
"text": { "body": "Is the new Bengali poetry anthology in stock?" }
}]

No wa_id and no from: the user_id is the only stable key in this event.

Caveats

Common mistakes with the webhook contacts object

  • Assuming wa_id is always there

    Code such as contacts[0].wa_id.startsWith("91") throws on username users. Treat wa_id as optional and fall back to user_id.

  • Using profile.name as identity

    Users choose and change their profile name, and many share common names. Use it for greeting and display, never to merge records or verify who someone is.

  • Reading contacts[0] blindly

    Match the contact to the message by wa_id or user_id. It costs one line and stays correct if a payload ever carries more than one item.

  • Treating wa_id as an E.164 number

    wa_id has no plus sign, and Meta notes it may not match the number you have on file. Normalise both sides to the E.164 phone number format before comparing, and store what WhatsApp sends as its own field.

Questions

Webhook Contacts Object FAQs

Why is wa_id missing from my WhatsApp webhook?
Because the user has adopted a username and your business number has not been in touch with them recently. The phone appears only after a message or call either way within 30 days, or if the user is in your contact book; user_id is always there.
Is wa_id the customer's phone number?
Usually, but not always. It is normally the number in digits without the plus sign, yet Meta notes it may not match the number you hold, and it is omitted for some username users. Treat it as WhatsApp's ID for the person.
Can I use a BSUID across my businesses?
Only inside one business portfolio. The same person has a different BSUID under another portfolio, and a new one if they change their phone number.
Can I send a message to a user_id?
Meta is adding the ability to send by BSUID, so check what your integration and provider support today. Until BSUID sends work end to end for you, keep the last known phone number alongside the BSUID and send to the number.

Why it matters

Why does the webhook contacts object matter?

The contacts object is how every event finds its customer record. CRMs, inboxes and bots that key everything on the phone number worked for years because wa_id was always present; with usernames rolling out through 2026, some events will arrive with only a user_id. An integration that stores both identifiers now, and looks people up by either, keeps threads joined up. One that assumes wa_id will create duplicate contacts, misroute replies and lose conversation history the moment a customer hides their number.

Example

Example: A Kolkata bookshop's inbox after usernames

A Kolkata bookshop's inbox has always keyed customers on phone number. A long-time customer adopts a username and, two months after their last chat, asks whether a new novel is in stock. The webhook arrives with profile.name, profile.username and user_id, but no wa_id or from, because nobody has messaged that number in 30 days. Because the shop backfilled user_id into its customer table when BSUIDs first appeared, the lookup succeeds, the agent sees the customer's order history, and the reply goes into the existing thread instead of a new, anonymous one.

Notes

Best practices for the webhook contacts object

  • Backfill user_id onto existing customers from incoming webhooks now, before username adoption grows.
  • Index customers on both BSUID and wa_id so either lookup is fast.
  • Mask wa_id in logs; it is personal data under the DPDP Act.

See InfiQ pricing

Put Webhook Contacts Object to work

InfiQ is an official Meta Business Partner. Start a 7-day free trial — no card needed — and see this running on your own number.