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

# The Affirmative Opt-In Gate (consent_required)

> How to enable the tenant-owned gate that blocks outbound sends to recipients who never gave consent: the settings shape, channel scoping, transactional exemption, ledger preparation, the 403 failure envelope, and safe rollback.

# The Affirmative Opt-In Gate (consent\_required)

`consent_required` is the tenant-owned affirmative opt-in gate. When you
enable it, an outbound send on a gated channel requires a recorded, live
`opted_in` consent row for the (contact, channel) pair, and a recipient
who has **never given** consent is refused with
`403 MESSAGING_CONSENT_REQUIRED`. The gate's own source header calls it
the "positive-consent twin of the opt-OUT suppression path": suppression
blocks recipients who withdrew consent, this gate blocks recipients who
never gave any.

It ships off by default, and nothing on the platform side can enable it
for you. This page walks through turning it on, scoping it, and
operating it without blocking legitimate traffic.

<Note>
  This page covers the org-level gate. The per-contact consent ledger it
  reads (recording, lookup, expiry, receipts) is documented in
  [Consent Management & Receipts](/compliance/consent-management).
</Note>

***

## What the gate is (and what it is not)

Three tenant knobs decide what a contact without a clean consent story
receives, and they answer different questions:

| Knob | Question it answers | Where it applies |
| - | - | - |
| `consent_required` (this page) | Did this recipient ever affirmatively opt in on this channel? | Directly addressed sends, per recipient, before dispatch |
| `unknown_marketing_policy` | May a marketing send reach a contact whose consent state is `unknown`? | The marketing send gate, after this gate |
| `consent_default_policy` | Does a CDP destination fanout or subscription check reach a contact with no ledger row at all? | CDP fanout and subscription checks |

The two policies *resolve* the unknown tri-state
(`opted_in` / `opted_out` / `unknown`): `refuse` or
`allow_with_logging`, `permit_on_missing` or `deny_on_missing` answer on
the contact's behalf. `consent_required` resolves nothing. It demands a
recorded grant: with the gate enabled, a non-exempt send to a contact
with no `opted_in` row is blocked under every setting of the other two
knobs.

The gate is also not:

* The **TCPA known-litigator preflight**, which blocks only US (+1)
  numbers on the litigator list.
* The **double-opt-in confirmation flow**, which records consent after a
  send and does not gate the first send.
* **Opt-out suppression**, which blocks recipients who withdrew.

***

## A tenant-owned posture, off by default

The gate exists for operators whose regimes require affirmative opt-in
before outbound contact:

* **GDPR Art. 6/7** (EU/EEA) — consent as the lawful basis for consumer
  marketing.
* **LGPD Art. 8** (Brazil) — the explicit-consent standard.
* **PDPA s. 14** (Singapore) — the consent-before-send obligation.

It is tenant-scoped and off by default. There is no platform or
country-level switch that turns it on for you, and enabling it is a
posture decision to take with counsel. Orbit enforces the posture you
set and keeps the evidence trail; it never decides that a send is
"compliant."

***

## The `consent_required` settings shape

The gate reads `organizations.settings.consent_required`:

```json theme={null}
{
  "consent_required": {
    "enabled": true,
    "channels": ["sms", "mms"],
    "exempt_transactional": true
  }
}
```

| Field | Type | Default | Effect |
| - | - | - | - |
| `enabled` | boolean | `false` | The master switch. Anything other than the literal `true` leaves the gate off. |
| `channels` | string\[] | `["sms", "mms"]` | Channels the gate applies to, lower-cased. Add `voice`, `whatsapp`, or `email` to widen. An empty or unparseable list falls back to the default set rather than disabling the gate. |
| `exempt_transactional` | boolean | `true` | When true, sends categorised `transactional`, `otp`, `service`, `alert`, or `notification` (via `message_type` on the send) bypass the gate on a non-consent lawful basis. Set the literal `false` for the strictest posture: every send on a gated channel then requires an opt-in. |

Enable it by merging the object into your organization settings
(owner role):

```bash theme={null}
curl -X PATCH https://api.orbit.devotel.io/api/v1/organizations/settings \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "settings": {
      "consent_required": {
        "enabled": true,
        "channels": ["sms", "mms"],
        "exempt_transactional": true
      }
    }
  }'
```

Two exemptions apply on top of the channel set, regardless of
configuration:

* **The consent prompt itself.** A double-opt-in confirmation message is
  how consent is gathered, so it is always allowed out.
* **Transactional traffic**, while `exempt_transactional` is true (the
  default), per the table above.

For phone channels the gate matches recipients by their E.164 number;
for the `email` channel it matches by the recipient's address, so
email opt-ins you record are honoured when you gate `email`.

***

## How it composes with `unknown_marketing_policy`

The two knobs fire at different points and on different populations:

1. **This gate** evaluates each directly addressed recipient at send
   time: does a live `opted_in` row exist for (contact, channel)?
2. **The marketing gate** afterwards resolves contacts whose state is
   `unknown` through your `unknown_marketing_policy`.

In practice: with `consent_required` enabled on a channel, a contact
with no ledger row is blocked here before the marketing policy is
consulted, so on gated channels the gate is the stricter of the two for
marketing traffic. `unknown_marketing_policy` keeps its role on channels
you did not gate and for traffic this gate exempts, such as
transactional sends under the default exemption. And nothing either
knob permits overrides an explicit `opted_out` or a suppression entry:
suppression drops the send before any policy is read. See
[Consent vs. Suppression](/compliance/consent-vs-suppression-model).

Enabling `consent_required` never changes your unknown-consent
policies, and loosening those policies never weakens this gate.

***

## Populate the ledger before you enable

<Warning>
  Enabling the gate over an empty consent ledger blocks every
  non-exempt send on the gated channels with
  `403 MESSAGING_CONSENT_REQUIRED`. Prepare the ledger first.
</Warning>

Record the grants you already hold before you flip `enabled`:

1. **Import historical opt-ins through the Consent API.**
   `POST /api/v1/compliance/consent` writes the `opted_in` row the gate
   reads, including the channel and the grant's metadata.
2. **Let double-opt-in confirmations land.** A confirmed opt-in writes
   the same ledger row, so a contact mid-confirmation is covered the
   moment they confirm.
3. **Wire preference-center signups.** Channel selections saved from
   your preference center should write an `opted_in` row per chosen
   channel.

A workable sequence: import what you can substantiate, enable with the
narrow channel set (`["sms"]`), watch the block audit entries for one
campaign cycle, then widen to `["sms", "mms"]` and beyond.

Also mind expiry. A grant stored with a `valid_until` window blocks
again once the window lapses (`details.consent_expired: true`); the
consent-management expiry surface lists grants that are about to lapse
so you can re-confirm them before they do.

***

## Failure shape, the settings cache, and rollback

A blocked send returns:

```json theme={null}
{
  "error": {
    "code": "MESSAGING_CONSENT_REQUIRED",
    "status": 403,
    "details": {
      "to": "+1555****",
      "channel": "sms",
      "consent_required": true,
      "consent_expired": false
    }
  }
}
```

* `consent_expired: false` — no opt-in was ever recorded; capture a
  first opt-in.
* `consent_expired: true` — a grant existed but its `valid_until`
  lapsed; re-confirm the recipient.
* The destination is redacted to its first five digits, both in the
  envelope and in the audit entry the gate writes for every blocked
  send, so a compliance review can rebuild the timeline without
  exposing numbers.
* A blocked send is never charged: the gate runs before the billing
  hold.
* If the consent lookup itself hits a backend error, the send fails
  closed with `503 SERVICE_UNAVAILABLE` and is safe to retry with
  backoff.

**The settings cache.** Organization settings are held in an
in-process cache of about 60 seconds. After a PATCH, allow up to a
minute for the new posture to take effect on every API process; a send
that lands inside the window may still see the previous posture.

**Rolling back safely.** Set `enabled: false` and the gate returns to a
no-op; the gated channels resume the prior single-opt-in behaviour
within the cache window. Disabling deletes nothing: every ledger row
you wrote stays in place for the next enablement. If enabling surfaced
unexpected blocks, roll back in this order: disable first so traffic
resumes, read the block audit entries to see exactly which recipients
lacked a grant, record the missing opt-ins, then re-enable.

***

## Related

* [Consent Management & Receipts](/compliance/consent-management) — the
  ledger this gate reads.
* [Consent Posture: The Unknown-Consent Policies](/compliance/consent-default-policy) —
  `unknown_marketing_policy` and `consent_default_policy`.
* [Double Opt-In](/compliance/double-opt-in) — the confirmation flow
  that writes the rows this gate requires.
* [Opt-Out & Suppression Lists](/compliance/opt-out-suppression) — the
  twin path that blocks withdrawn consent.
* [Assembling a GDPR Posture End to End](/compliance/gdpr-posture-guide) —
  the full opt-in-regime walkthrough.
* [Compliance Gate Error Codes FAQ](/compliance/compliance-gate-error-codes-faq) —
  the `MESSAGING_CONSENT_REQUIRED` Q\&A.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.