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

# Keyword opt-outs on WhatsApp, RCS & Viber

> Set up opt-out keyword rules for WhatsApp (WABA), RCS, and Viber channels — per-channel rule scope, cross-channel suppression, testing, and where to verify the ledger.

# Keyword opt-outs on WhatsApp, RCS & Viber

The keyword mechanism that handles `STOP` and `START` is not SMS-only. Any inbound surface that can carry a keyword reply — a WhatsApp Business (WABA) number, an RCS agent, or a Viber channel — can run the same opt-out and opt-in rules, provided you add the rule with the matching channel scope. This guide walks you through per-channel setup, the cross-channel suppression one keyword triggers, and how to verify the ledger entries.

## Why the SMS keyword docs do not cover WhatsApp/RCS/Viber

The rules editor at **Messages → SMS → Opt-out Rules** and its seed defaults are scoped to SMS. As the [Opt-out keyword alias table](/compliance/opt-out-keyword-alias-table) states, the shipped seed defaults are scoped to the `sms` channel — because inbound SMS on long codes and short codes is the classic opt-out carrier surface. A tenant that runs WhatsApp or RCS traffic and relies only on those defaults has no rules firing on the non-SMS channel at all: a `STOP` texted to your WABA number matches nothing, and the contact stays reachable.

The fix is not a new mechanism. You handle WABA / RCS / Viber opt-outs through the same keyword mechanism by adding a rule on the `whatsapp`, `rcs`, or `viber` channel.

## How channel scope works on rules

Every keyword rule in `GET /api/v1/settings/opt-out-rules` carries a channel annotation — one of `sms`, `whatsapp`, `rcs`, `viber`, or `email`. **A rule only fires on the channel it is stored with.** The scope is a routing latch, not a language hint: a `whatsapp`-scoped `STOP` only matches inbound WhatsApp turns on your WABA numbers.

The suppression the match writes is deliberately wider. When any opt-out rule matches — regardless of which channel it fired on — Orbit writes the suppression entry with scope `all` on the reply-capable phone address. That means a `STOP` sent to your WABA number blocks that contact on SMS, WhatsApp, RCS, and Viber at once. The recipient's `STOP` is a request to stop being contacted, not a request to stop being contacted on one channel. This propagation lives in the suppression record, not in the keyword vocabulary — see [Opt-Out & Suppression Lists](/compliance/opt-out-suppression) for the ledger view.

<Note>
  These controls are **tenant-owned** — you decide which keywords and channels
  qualify as an opt-out inside your own account. Nothing here is a
  platform-mandated gate; both the shipped seed set and any additions stay your
  editable list.
</Note>

## WhatsApp (WABA) setup

A WhatsApp Business number that can receive inbound messages is the only surface that carries keywords on this channel.

1. Open **Messages → SMS → Opt-out Rules** (also at `/messages/sms/opt-out-rules`). The same editor manages every channel scope — the route just lives under the SMS workspace.
2. In the **Opt-out keywords** section, add a rule with the keyword you want to match on WhatsApp — usually `STOP`.
3. In the channel field, select **whatsapp**. Without this step the rule still fires on SMS only — the most common WABA mis-configuration.
4. Save with **Save Rules**.

Over the API, the same rule is a `POST /api/v1/settings/opt-out-rules` call:

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/settings/opt-out-rules" \
  -H "X-API-Key: dv_test_sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"keyword": "STOP", "channel": "whatsapp", "action": "opt-out"}'
```

## RCS setup

An RCS agent that accepts inbound replies falls in the same channel scope:

1. Open **Messages → SMS → Opt-out Rules**.
2. Add the rule with **channel** set to **rcs**.
3. Save. Any inbound keyword RCS turn against your agent now flips the consent flag.

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/settings/opt-out-rules" \
  -H "X-API-Key: dv_test_sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"keyword": "STOP", "channel": "rcs", "action": "opt-out"}'
```

## Viber

```bash cURL theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/settings/opt-out-rules" \
  -H "X-API-Key: dv_test_sk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{"keyword": "STOP", "channel": "viber", "action": "opt-out"}'
```

## Email — use List-Unsubscribe instead

Email opt-outs do not run through keyword rules. Recipients unsubscribe via the RFC-8058 `List-Unsubscribe` / `List-Unsubscribe-Post: One-Click` header and the in-body link; Orbit merges both on every outbound email. Point email recipients there instead of a keyword scheme — see [CAN-SPAM → List-Unsubscribe header behavior](/compliance/can-spam#list-unsubscribe-header-behavior) for the wire format and the in-body link merge rules.

## Testing non-SMS channels end to end

Run a real inbound against the channel you scoped, and check all three downstream effects before relying on the rule in a campaign:

1. **Send the keyword** — text `STOP` from a handset to your WABA number (or to the RCS agent / Viber channel you registered a rule for).
2. **Contact profile** — the conversation shows the inbound turn and auto-reply; the contact profile flips the channel's `opted_out` flag, or `opted_in` again after a subsequent `START` (or your opt-in synonym).
3. **Suppression entry** — the [Opt-Out & Suppression Lists](/compliance/opt-out-suppression) page lists the phone row with scope **`all`**, the channel it was matched on, and the keyword that fired.

If any of the three is missing, the rule did not fire — walk the troubleshooting table below.

## Troubleshooting

| Symptom                                   | Likely cause                                                                                 | Fix                                                                                                                                       |
| ----------------------------------------- | -------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- |
| Keyword never fires on the channel        | Rule stored on the wrong channel (e.g. WABA first opened the defaults, which are `sms`-only) | Re-save the rule with the correct `channel` (`whatsapp` / `rcs` / `viber`) via dashboard or `POST /settings/opt-out-rules`.               |
| Contact still reachable on other channels | Rule came from the wrong surface, or active=false                                            | Look at the suppression list — the scope should read `all`; otherwise rewrite the rule/create it on the right channel and re-send `STOP`. |
| WABA number has no inbound capability     | The number only registers as outbound-capable in Meta                                        | Enable inbound on the WABA number, or attach a number that accepts replies; keyword handling only fires on reply-capable surfaces.        |
| Auto-reply never arrives                  | `auto_reply_text` was left blank on create                                                   | Add a response payload on the rule (PUT bulk update or POST create).                                                                      |
| Editor shows read-only                    | Team member role without write access                                                        | Owner or admin can create rules; billing/viewer/supervisor get the read-only view.                                                        |

## Where to verify

* Rules list: `GET /api/v1/settings/opt-out-rules` (cursor-paginated).
* Create a single rule: `POST /api/v1/settings/opt-out-rules` — body `keyword` (default `STOP`), `channel` (default `sms`), `action` (`opt-out` | `opt-in`, required), optional `auto_reply_text`.
* Bulk update or toggle rules: `PUT /api/v1/settings/opt-out-rules` with a `rules` array (up to 100 entries with `id` + the fields to change). All writes are gated to **owner/admin** roles; reads are also the management surface for the editor.
* Ledger view of suppressed addresses, scopes, and keyword that fired: [Opt-Out & Suppression Lists](/compliance/opt-out-suppression).
* Reference vocabulary for every shipped alias and market: [Opt-out keyword alias table](/compliance/opt-out-keyword-alias-table).
