- Messages & interactivity
- Practitioner
- Developers
System Message
Also called: WhatsApp system message · System notification · user_changed_number
A message WhatsApp itself generates and delivers by webhook, such as a notice that a user changed their phone number, rather than one a person wrote.
Reviewed
What is a system message?
A system message is a notification that WhatsApp generates itself and delivers to your webhook in the shape of an incoming message, to tell you that something changed about a user rather than to carry anything they wrote. On the WhatsApp Cloud API it arrives on the Messages Webhook (the messages field) with type: system and a system object holding a human-readable body and a machine-readable type.
Two types are documented today. user_changed_number means the user moved WhatsApp to a new phone number that can be shared: the old WhatsApp ID (wa_id) is in the message's from, the new one in system.wa_id, and the body reads like 'User Rohan changed from 919812345678 to 919811122233'. user_changed_user_id means the user's Business-Scoped User ID was regenerated with no phone number to share. In both, system.user_id carries the current BSUID and previous_user_id the old one when it is available; parent_user_id fields appear only if parent BSUIDs are enabled. Older webhook versions used new_wa_id for the new number.
System messages behave differently from other inbound messages. They have no contacts array, from is omitted for users who have enabled WhatsApp Usernames, and they say nothing about messages you sent — those updates come on the Statuses Webhook. They are also distinct from the Identity Change Check, which blocks sends when a user's security identity changes, for example after a reinstall, and has nothing to do with a new number. Like an Unsupported Message Type, a system message is easy to forget in a handler built only for text and buttons.
Key takeaways
- A system message is a webhook WhatsApp generates itself, not written by the user, reporting a change to the user's identity.
- It arrives on the messages field as
type: system, with asystemobject whosetypesays what changed. user_changed_numberputs the new WhatsApp ID insystem.wa_id;user_changed_user_idreports a new business-scoped user ID only.- System messages carry no contacts array, and
fromis omitted when the user has enabled a username. - Move history, consent and open tickets to the new identifier instead of creating a second customer.
Interactive stop
Open a number-change system message
{"object": "whatsapp_business_account","entry": [{"id": "102290129340398","changes": [{"field": "messages","value": {"messaging_product": "whatsapp","metadata": {"display_phone_number": "919876543210","phone_number_id": "106540352242922"},"messages": [{"from": "919812345678","id": "wamid.HBgMOTE5ODEyMzQ1Njc4FQIAEhgUM0VCMEQ3RjE5QzQyMkE1OEIyNkUA","timestamp": "1760866500","type": "system","system": {"body": "User Rohan changed from 919812345678 to 919811122233","wa_id": "919811122233","type": "user_changed_number","user_id": "IN.13491208655302741918","previous_user_id": "IN.10230984751029384756"}}]}}]}]}
Field 9: entry.0.changes.0.value.messages.0.system.body — Readable text for logs and agents. Don't parse it — use the fields.
How does a system message work?
Receive it on the messages field
System messages arrive on the same
messageswebhook field as customer messages, so no extra subscription is needed.Branch on `type: system`
Route it away from your bot. It is not something the user said, and an automatic reply to it makes no sense.
Read `system.type`
For
user_changed_number, the old ID is infromand the new one insystem.wa_id. Foruser_changed_user_id, mapprevious_user_idtouser_id.Move the record, don't duplicate it
Make the new identifier primary, keep the old one as an alias, and carry over consent, tags and open tickets.
Record and notify
Log the timestamp and both identifiers for audit, and alert the agent who owns any open conversation with the customer.
A system message in code
// m = one item of value.messages[] where m.type === "system" (these carry no contacts array)export async function onSystem(m) {const s = m.system;switch (s.type) {case "user_changed_number": {const oldId = m.from; // omitted if the user has a usernameconst newId = s.wa_id ?? s.new_wa_id; // new_wa_id on older webhook versionsconst customer =(oldId && (await crm.findByWaId(oldId))) ||(s.previous_user_id && (await crm.findByUserId(s.previous_user_id)));if (!customer) break;await crm.update(customer.id, {waId: newId,userId: s.user_id ?? customer.userId,aliases: [...customer.aliases, oldId, s.previous_user_id].filter(Boolean),});break;}case "user_changed_user_id": {const customer = s.previous_user_id && (await crm.findByUserId(s.previous_user_id));if (customer) {await crm.update(customer.id, { userId: s.user_id, aliases: [...customer.aliases, s.previous_user_id] });}break;}default:log.warn("unhandled system message type", s.type); // keep the raw payload for review}await audit.record({ wamid: m.id, type: s.type, at: Number(m.timestamp) });}
Never parse body; it is for people. Match on from or previous_user_id, then move the record.
Example: A gym member's new number in Nagpur
A Nagpur gym chain's CRM keys members by WhatsApp ID. A member moves from 919812345678 to 919811122233, and a user_changed_number system message arrives. The handler finds the member by the old ID, sets the new one as primary, keeps the old one as an alias and moves the member's tags, consent record and open membership-freeze request across. When the member writes from the new number the next morning, the agent sees two years of history and the pending request instead of a blank profile.
Common mistakes with a system message
Creating a new customer
Treating the next message from the new number as a stranger splits history and consent. Handle the system message and move the record.
Sending it to the bot
An intent engine that sees the body may answer 'Sorry, I didn't understand'. Route system messages to their own handler.
Parsing the body text
The body is written for people, and its wording can change. Use
system.type,wa_idand the user ID fields instead.Relying only on phone numbers
With usernames,
fromandwa_idcan be absent. Store BSUIDs as well, and match onprevious_user_idwhen no number is present.Confusing it with status webhooks
System messages describe the user, not your messages. Statuses are a separate payload with a
statusesarray instead ofmessages.
A system message: key facts and limits
- Webhook field
- messages
- Message type
- system
- Documented system types
- user_changed_number · user_changed_user_id
- New WhatsApp ID
- system.wa_id (new_wa_id on older versions)
- BSUIDs
- system.user_id and system.previous_user_id
- Contacts array
- Not included
- from
- Omitted when the user has enabled a username
System Message FAQs
What is a system message in the WhatsApp API?+
How do I know when a WhatsApp customer changes their phone number?+
What does user_changed_user_id mean?+
Is a system message the same as a status webhook?+
Best practices for a system message
- Keep a table of every identifier each customer has had, with the date each one changed.
- Store raw system payloads for a few weeks; they are rare and invaluable when a merge goes wrong.
- Notify the agent who owns an open conversation when the customer's number changes.
- Test the handler with a sample payload, since a real number change is hard to trigger on demand.
Why does a system message matter?
A number change is the moment a customer record silently splits in two. Without handling it, the next message from the new number lands as a stranger: no order history, no consent record, no open ticket, perhaps even a second opt-in request. Handling one webhook type keeps your CRM integration, the inbox and consent records joined to the same person. With usernames and business-scoped user IDs rolling out through 2026, identifier changes are no longer rare enough to leave to manual clean-up.
Talk to InfiQ
From definition to your first message
InfiQ is an official Meta Business Partner. Start a 7-day free trial — no card needed — and see this running on your own number.