Skip to content

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 a system object whose type says what changed.
  • user_changed_number puts the new WhatsApp ID in system.wa_id; user_changed_user_id reports a new business-scoped user ID only.
  • System messages carry no contacts array, and from is omitted when the user has enabled a username.
  • Move history, consent and open tickets to the new identifier instead of creating a second customer.

See InfiQ pricing

Interactive stop

Open a number-change system message

9 / 9
{
"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"
}
}
]
}
}
]
}
]
}
A real-shaped user_changed_number webhook. Step through the fields a CRM needs: the old ID in from, the new one in system.wa_id, and the business-scoped user IDs before and after.

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?

  1. Receive it on the messages field

    System messages arrive on the same messages webhook field as customer messages, so no extra subscription is needed.

  2. 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.

  3. Read `system.type`

    For user_changed_number, the old ID is in from and the new one in system.wa_id. For user_changed_user_id, map previous_user_id to user_id.

  4. 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.

  5. 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 username
const newId = s.wa_id ?? s.new_wa_id; // new_wa_id on older webhook versions
const 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.

— A gym member's new number in Nagpur

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_id and the user ID fields instead.

  • Relying only on phone numbers

    With usernames, from and wa_id can be absent. Store BSUIDs as well, and match on previous_user_id when no number is present.

  • Confusing it with status webhooks

    System messages describe the user, not your messages. Statuses are a separate payload with a statuses array instead of messages.

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?+
It is a webhook WhatsApp generates itself to report a change to a user, such as a new phone number. It arrives as type system on the messages field rather than as something the user typed.
How do I know when a WhatsApp customer changes their phone number?+
You receive a system message whose system.type is user_changed_number. The old ID is in from and the new WhatsApp ID in system.wa_id, so update your records to the new one.
What does user_changed_user_id mean?+
It means the user's business-scoped user ID changed and no shareable phone number is included. Map system.previous_user_id to the new system.user_id in your records.
Is a system message the same as a status webhook?+
No. A system message reports a change to the user; a status webhook reports what happened to a message you sent. Both use the messages field, but one carries a messages array and the other a statuses array.

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.