> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kapso.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Marketing opt-outs

> What happens when a contact stops marketing messages, and how to check and mirror their preference

WhatsApp lets users stop marketing messages from a business number without blocking it. When a contact does, Meta notifies Kapso, Kapso records the preference, and marketing template sends to that contact on that number are refused.

The scope is narrow and per number:

* Only MARKETING-category templates are blocked. Utility and authentication templates, and free-form messages inside an open session, always go through.
* The preference is scoped to the number the contact stopped. Sends from your other numbers are unaffected.
* A contact with no recorded preference is subscribed.

The preference can only be set by the contact, inside WhatsApp. There is no API or dashboard control to opt a contact out or back in — to resume, the contact taps *Resume promotions* (or messages you and re-enables marketing) in WhatsApp.

## Blocked sends

Sending a marketing template to a stopped contact returns `422`:

```json theme={null}
{
  "error": "Contact stopped marketing messages on this WhatsApp number",
  "code": "marketing_preference_stopped"
}
```

Do not retry the same send — it will keep failing until the contact resumes. Switch to a utility or authentication template, or send from a different number.

The check runs before billing, so refused sends are never charged.

Other send surfaces handle it without erroring:

* **Broadcasts** mark the recipient `suppressed` and skip them. See [Marketing opt-outs in broadcasts](/docs/platform/broadcasts/overview#marketing-opt-outs).
* **Workflow send-template steps** record the send as skipped and the workflow continues.

## Check a contact's preference

```bash theme={null}
curl 'https://api.kapso.ai/platform/v1/whatsapp/contacts/15551234567/marketing_preferences' \
  -H 'X-API-Key: YOUR_API_KEY'
```

The identifier is a contact UUID or phone number. The response has one entry per number the contact has a recorded preference on:

```json theme={null}
{
  "data": [
    {
      "id": "123456789012345",
      "phone_number_id": "123456789012345",
      "status": "stopped",
      "detail": "User requested to stop marketing messages",
      "source": "meta_webhook",
      "marketing_allowed": false,
      "config_display_name": "Main line",
      "last_event_at": "2026-08-18T15:44:16Z",
      "created_at": "2026-08-18T15:44:17Z",
      "updated_at": "2026-08-18T15:44:17Z"
    }
  ]
}
```

`status` is `stopped` or `resumed`. `marketing_allowed` is what you should branch on before a marketing send. An empty `data` array means the contact never changed their preference — subscribed everywhere.

Fetch a single number with `GET /whatsapp/contacts/{identifier}/marketing_preferences/{phone_number_id}`. A `404` with `"Marketing preference not found"` means the contact has no recorded preference on that number — subscribed. Check the error string before treating a `404` as subscribed: a mistyped identifier returns `"WhatsApp contact not found"` and an unknown number returns `"WhatsApp configuration not found"`.

## Mirror opt-outs into your system

Subscribe to [`whatsapp.contact.marketing_preference_changed`](/docs/platform/webhooks/message-events#whatsapp-contact-marketing-preference-changed). It fires on every real transition — stop and resume — with a monotonic `sequence` to order deliveries by.

## In the dashboard

The contacts list shows a **Marketing** column and a subscribed/unsubscribed filter. The contact panel lists the preference per number. Starting a conversation with a marketing template warns and disables send when the contact has stopped that number, and broadcast details show how many recipients will be skipped before you send.
