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

# Consent, opt-out, and suppression: the recipient-state model

> How a contact's consent records, channel preferences, and suppression entries form one recipient state, which entry points write it, and how the send chain evaluates it before every dispatch.

# Consent, opt-out, and suppression

Three stores — `consent_records`, `channel_preferences`, and the
`suppression_list` — hold a contact's recipient state. Every opt-in or
opt-out, from any entry point, writes all three together, so a send gate
never has to ask *which door* consent came through: the answer for a
`(contact, channel)` pair is the same from everywhere.

This page is the model the individual guides assume: what the stores are,
which entry points mutate them, how channel scoping works, and where the
state plugs into the send chain.

## The three stores

| Store                                  | Role                                                                                                        | What it answers                                                                               |
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------- |
| `consent_records`                      | Append-only audit table — every grant and revocation, with source, lawful basis, purpose, and proof fields. | *Who consented to what, when, under which basis?* — the TCPA / GDPR Art 7(1) proof-of-record. |
| `channel_preferences` (on the contact) | The read-side mirror the send path checks — per-channel opt-out flags plus a `global_opt_out`.              | *Is this contact reachable on this channel right now?* — the fast-path lookup.                |
| `suppression_list`                     | The block list a send is gated against — one row per `(channel-scope, address)` with a reason and source.   | *Is this address hard-blocked before dispatch?*                                               |

A write also flips a short-lived STOP-fence cache key so in-flight
campaign batches converge on the new state within minutes rather than on
the next contact read. The STOP-fence is a convenience, never the source
of truth — the authoritative state lives in the stores above.

Because every entry point maintains all three surfaces atomically, the
stores stay consistent by construction: the audit trail, the read mirror,
and the gate verdict are one state, not three that can drift apart.

## Entry points that write recipient state

Recipient state changes from every direction consent can enter:

* **Inbound STOP / START / HELP replies** — the
  [opt-out keyword lists](/guides/opt-out-lists) layer that recognizes the
  reply writes the opt-out.
* **The Preference Center** — contact self-service per-channel toggles.
* **The Consent API** — `POST /compliance/consent`, the programmatic
  record (`opt_in: true` / `false`) covered by
  [Consent Management](/compliance/consent-management).
* **The public consent form** — a hosted, unauthenticated submission page
  you can enable per tenant; every submission writes the same three
  stores as the carrier-side keyword handlers. See
  [Public consent form](/guides/public-consent-form).
* **Bulk CSV import** — migrating an existing suppression list writes
  suppression entries directly; see
  [Opt-Out & Suppression Lists](/compliance/opt-out-suppression).
* **DSAR requests** — a delete / opt-out request resolves into the same
  stores; see [DSAR](/compliance/dsar).

Whichever door the write arrived through, the downstream effect is
identical: the send gates read the same stores.

## Scopes and channel semantics — `all` vs per-channel

Each suppression entry carries a channel scope. The full scope set is:
`all`, `sms`, `voice`, `whatsapp`, `email`, `push`, `telegram`,
`messenger`, `rcs`.

How the scope is chosen depends on the entry point:

* **Keyword replies, the Preference Center, the Consent API, and the
  public consent form** always write scope `all` — an opt-out through any
  of these removes the contact from every channel.
* **Bulk CSV import** infers the scope per row from the address type:
  phone and WhatsApp addresses default to `all` (a STOP signal on a phone
  number suppresses every channel reachable on that number), while email
  addresses are scoped to `email`. A `channel` column in the CSV
  overrides the default per row.

<Note>
  Scope `all` on a phone number reaches voice too: the voice and dialer
  gates read the suppression list directly, so a number that opts out on
  any channel stops receiving calls as well as messages.
</Note>

## Where recipient state plugs into the send chain

Recipient state is one gate in the outbound admission chain — the
per-recipient block-list check. Its position in the chain, the error it
returns (`422 RECIPIENT_OPTED_OUT` on direct sends), and how campaign
sends skip instead of erroring are covered by
[Outbound send gating](/concepts/send-gating-and-quiet-hours) — the chain
walks wallet posture, quiet hours, duplicate-content suppression,
recipient block lists, frequency caps, and throughput in a fixed order,
and this page does not repeat that ordering. What matters here: the
block-list gate reads `channel_preferences` and the `suppression_list`,
so the moment an opt-out lands, the next send to that recipient is a
refusal or a skip, not a dispatch.

## Re-consent and revocation semantics

Consent is reversible in both directions, and a revocation is never a
deletion:

* **Opt-out** writes a new consent record, flips the contact's
  `channel_preferences` flags, and inserts an active suppression row.
* **Opt-in (re-consent)** writes a fresh consent record, clears the
  flags, and **revokes** the matching suppression rows — sets
  `revoked_at` on the existing row rather than deleting it, so the ledger
  keeps the full history of "suppressed, then re-consented" for audit.
* **Expiring consent** — an opt-in recorded with `valid_until` or
  `expires_in_days` ages out on its own: the lookup reports `expired`
  and `requires_reconfirmation`, and
  [Consent Management](/compliance/consent-management) documents the
  sweep endpoint that feeds a re-permission campaign.

Never re-message a previously suppressed contact without a documented,
fresh consent event — the re-opt-in through the Consent API is also what
clears the block, so the legal and the mechanical steps are the same
call.

## Interaction with the other gates

Consent, opt-out, and suppression answer one question — *may I send to
this recipient at all?* The other gates answer different questions and
run independently:

* **Quiet hours** ask *is it the right time, recipient-local, under my
  window?* A fully consented recipient is still blocked outside the
  window.
* **[Frequency caps](/guides/frequency-caps)** ask *has this contact
  already received too many sends in my window?* — a count axis, blind to
  consent state.
* **[Message suppression](/guides/message-suppression)** asks *did this
  exact body already reach this recipient on this channel?* — a content
  axis, blind to consent state.

Because the block-list check runs before the frequency-cap slot claim in
the admission chain, an opted-out recipient never consumes a cap slot,
and a duplicate-content skip never happens for a recipient who was
blocked on consent grounds first. Configure each gate on its own axis —
none of them substitutes for the others.

## Tenant-owned controls

The recipient state on this page is **your data and your responsibility**:
you capture consent, you honour revocations, and Orbit carries the
records, evaluates them at send time, and keeps the audit trail. The one
gate in the send chain a tenant cannot disable — the TCPA federal voice
dialing window for US recipients — operates independently of recipient
state and is covered in
[Outbound send gating](/concepts/send-gating-and-quiet-hours).

Recording consent in Orbit creates an auditable trail; it does not by
itself make a send lawful. You remain responsible for obtaining valid
consent and for the content you send.

## See also

* [Outbound send gating](/concepts/send-gating-and-quiet-hours) — the full admission chain this state plugs into
* [Consent Management](/compliance/consent-management) — the record / lookup / export endpoints over `consent_records`
* [Opt-Out & Suppression Lists](/compliance/opt-out-suppression) — bulk import and export of the suppression ledger
* [Custom Opt-Out Keyword Lists](/guides/opt-out-lists) — how inbound STOP/START replies are recognized and branded
* [Public consent form](/guides/public-consent-form) — the hosted self-service entry point
* [Preference Center and send gates](/compliance/send-gates) — contact self-service and the gate-preview endpoint
* [Message suppression](/guides/message-suppression) — the duplicate-content axis
* [Frequency caps](/guides/frequency-caps) — the count axis
* [DSAR](/compliance/dsar) — how access / delete requests resolve into recipient state
