Skip to content

User Preferences Webhook

Also called: user_preferences webhook · Marketing opt-out webhook · Stop marketing webhook

Definition
The user_preferences webhook tells your server when a WhatsApp user stops or resumes marketing messages from your business, so consent records stay in sync.

Exhibit A

Follow a stop event from payload to suppression list

5 / 5
{
"object": "whatsapp_business_account",
"entry": [{
"id": "102290129340398",
"changes": [{
"field": "user_preferences",
"value": {
"messaging_product": "whatsapp",
"metadata": {
"display_phone_number": "919876543210",
"phone_number_id": "106540352242922"
},
"contacts": [{ "wa_id": "919812345678" }],
"user_preferences": [{
"wa_id": "919812345678",
"user_id": "IN.40731866125599102847",
"detail": "User requested to stop marketing messages",
"category": "marketing_messages",
"value": "stop",
"timestamp": 1792387800
}]
}
}]
}]
}

Step 5 of 5 · line 20

timestamp is an integer of Unix seconds, not a string as in message webhooks.

Jump to
Step through a real-shaped user_preferences payload, then the handler that turns it into a consent record and a suppression-list change without letting late events win.

Webhook payload, step 5 of 5, line 20: timestamp is an integer of Unix seconds, not a string as in message webhooks.

What is the user preferences webhook?

The user preferences webhook is one of the WhatsApp Business Account webhook fields, user_preferences, that Meta posts when a person changes their marketing preference for your business inside WhatsApp. Each item in the value.user_preferences array says who changed it (user_id, the person's business-scoped user ID, and normally wa_id, which is left out for username users who have not shared their number), what it applies to (category, documented as marketing_messages), the new state (value is stop or resume), a readable detail such as "User requested to stop marketing messages", and a timestamp in Unix seconds — an integer here, unlike the string timestamps in message webhooks.

It exists because customers can switch off a business's marketing using WhatsApp's own controls, without typing anything your bot could parse. Once a person has stopped marketing from you, Meta does not deliver it: any marketing template you send them fails with error 131050, "This recipient has chosen to stop receiving marketing messages on WhatsApp from your business", and Meta's guidance for that error is not to retry. The event lets you record the change the moment it happens instead of discovering it through failed campaigns.

It is not the same as keyword opt-out handling. When a customer replies "STOP" in a chat, that arrives as an ordinary text message in the messages field and your own code decides it means an opt-out. user_preferences is WhatsApp telling you about a choice made through the app, with no message text involved. It concerns marketing messages only, it is not a block (a customer who blocks your number is a separate case), and Meta notes it does not fire for "Interested" or "Not interested" feedback given through the Offers and announcements setting.

Key takeaways

  • The user preferences webhook (user_preferences) fires when a WhatsApp user stops or resumes marketing messages from your business.
  • Each item carries the BSUID in user_id, usually wa_id, category marketing_messages, value stop or resume, and an integer Unix timestamp.
  • After a stop, marketing templates to that user fail with error 131050, and Meta advises not to retry them.
  • It covers marketing only and never replaces your own STOP keyword handling, which arrives as an ordinary inbound message.
  • The field must be subscribed explicitly and needs the whatsapp_business_management permission.

The user preferences webhook in code

from datetime import datetime, timezone
from flask import Flask, request
app = Flask(__name__)
@app.post("/webhooks/whatsapp")
def whatsapp_webhook():
verify_signature(request) # X-Hub-Signature-256 over the raw body
body = request.get_json()
for entry in body.get("entry", []):
for change in entry.get("changes", []):
if change.get("field") != "user_preferences":
continue # other fields are handled elsewhere
for pref in change["value"].get("user_preferences", []):
if pref.get("category") != "marketing_messages":
continue
jobs.enqueue("sync_marketing_preference", {
"user_id": pref.get("user_id"), # BSUID
"wa_id": pref.get("wa_id"), # omitted for some username users
"value": pref["value"], # "stop" or "resume"
"changed_at": datetime.fromtimestamp(
pref["timestamp"], timezone.utc).isoformat(),
})
return "", 200 # always acknowledge

Pick out user_preferences changes, queue them for the consent sync and acknowledge straight away.

Why does the user preferences webhook matter?

Consent has to match what the customer actually did. India's DPDP Act expects withdrawing consent to be as easy as giving it, and Meta's policy expects businesses to honour opt-outs. If your CRM still marks someone as opted in after they stopped your marketing inside WhatsApp, every campaign wastes an attempt that fails with 131050, delivery reports look worse than they are, and your consent evidence contradicts the customer's own action. Syncing this one webhook into your suppression list keeps campaign audiences, consent records and reporting honest — and the resume event tells you when someone wants to hear from you again.

How does the user preferences webhook work?

  1. Subscribe to the field

    Add user_preferences to your app's WhatsApp Business Account webhook fields. It needs the whatsapp_business_management permission (the messages field needs whatsapp_business_messaging), and it does not arrive unless you subscribe to it explicitly.

  2. Read every preference item

    The notification has field: "user_preferences" and a value with metadata, contacts and a user_preferences array. Loop over every item rather than reading only the first.

  3. Turn it into a consent event

    Write an append-only consent record: the user (BSUID and wa_id), the new state (stop or resume), the event time and the source (whatsapp_user_preferences), so you can later show when and how the preference changed.

  4. Update the suppression list

    A stop adds the user to the marketing suppression list that every sending tool checks — broadcasts, journeys, the CRM's campaign module. A resume lifts only the block this source created; a keyword STOP from the same customer stays in force.

  5. Keep the latest choice

    Webhooks can arrive late or twice. Compare the event's timestamp with the last stored change and ignore anything older, so a delayed stop cannot undo a newer resume.

Common mistakes with the user preferences webhook

  • Treating it as your only opt-out signal

    Customers also type STOP, tap an opt-out quick reply in your template or tell an agent. Keep keyword and button handling, and feed every source into the same suppression list.

  • Suppressing every message type

    The preference covers marketing. Blocking order updates, OTPs and support replies as well punishes the customer for muting promotions. Suppress marketing only — unless the customer asked you to stop everything, which you then honour from your own records.

  • Treating resume as a brand-new opt-in

    Resume lifts the stop made in WhatsApp. It does not replace the opt-in evidence your policy needs, so keep the original consent record and collect a fresh opt-in if you never had one.

  • Letting a late event win

    A retried stop that arrives after a newer resume would wrongly suppress the customer. Compare timestamps and keep only the latest change per user.

Example: A Surat saree shop's Diwali list

A customer of a Surat saree shop stops the shop's marketing messages in WhatsApp on a Sunday evening. The user_preferences webhook arrives seconds later with value: "stop"; the handler logs a consent event and adds her to the marketing suppression list. Monday's Diwali broadcast excludes her automatically, so no send fails with 131050. Her order confirmations — utility templates — keep arriving as normal. Three weeks later she resumes marketing from the shop, the resume event lifts the block, and she is back in the next campaign audience because her original opt-in record still stands.

User Preferences Webhook FAQs

Does a WhatsApp marketing stop block utility or authentication templates?+
No. The preference covers marketing messages only, and error 131050 applies to marketing sends. Utility and authentication templates are separate categories, though you should still honour any wider request the customer makes to you directly.
Can I still send marketing to someone who stopped?+
No. Meta does not deliver it and the send fails with 131050. Meta advises against retrying for that user, so remove them from every marketing audience until a resume event arrives.
Do I still need to handle STOP replies if I use this webhook?+
Yes. A typed STOP arrives as a normal inbound message on the messages field, not as a user_preferences event, so your own keyword handling must still catch it and feed the same suppression list.
How is a stop different from the per-user marketing limit?+
A stop is the customer's choice about your business; the per-user marketing limit is WhatsApp capping marketing from all businesses. A stop fails with 131050 until the user resumes, while the limit fails with 131049 and Meta suggests waiting at least 24 hours.
Is a user_preferences stop the same as the customer blocking my number?+
No. Blocking is a separate action that stops everything from your number. user_preferences reports only a change to marketing messages from your business, and the customer can still receive your other messages.

Best practices for the user preferences webhook

  • Check the suppression list at send time as well as when the audience is built, so a stop that lands mid-campaign is honoured.
  • Chart stops per campaign: a spike after one send is the clearest sign of message fatigue.
  • Store the BSUID (user_id) from each preference item, so records keep matching as usernames roll out and numbers change.
  • Treat a 131050 failure as a missed or unsynced stop and backfill the suppression list from it.

See InfiQ pricing

Try it on the official WhatsApp Business API

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