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

# Enable and Operate the SMS Double Opt-In Flow

> Turn on confirmed consent for marketing SMS per organization, then follow the prompt, YES-reply, and send loop end to end and report on pending_consent skips.

# Enable and Operate the SMS Double Opt-In Flow

Double opt-in (confirmed consent) holds your first marketing SMS to a
contact with no consent record on file and sends a one-time confirmation
prompt instead. The contact receives your marketing copy only after they
reply YES. This guide walks a US-style marketing tenant through enabling
the flow, watching each state land, and reporting on held sends.

For the regulatory posture and the per-contact handshake API, see
[Confirmed Consent (Double Opt-In) Handshakes](/compliance/double-opt-in)
and [Consent Management](/compliance/consent-management). This page covers
the operational loop: the setting, the state machine, the prompt, the
skips, the reply, and the audit trail.

<Info>
  Double opt-in is a tenant-owned control. It is off by default, and
  Orbit never enables it, prompts a contact, or confirms consent except
  where your setting or your API calls say to. Whether your program must
  require confirmed consent is your determination; this page shows how
  to operate the control, not when the law requires it, and is not
  legal advice.
</Info>

***

## 1. When to enable it

Enable the flow where your marketing program is graded on confirmed
consent:

* **US and Canadian marketing traffic.** The CTIA Short Code Monitoring
  Handbook (§5.1.3 and §5.2) grades short code and 10DLC campaigns on
  verified affirmative consent: a recorded prompt followed by a recorded
  affirmative reply. Carriers reviewing campaign attestations expect to
  see exactly that pattern, and short code programs are monitored most
  closely.
* **Launches headed for campaign review.** A prompt plus a recorded
  reply is stronger opt-in evidence than a bare web-form capture, and it
  is the evidence tier 10DLC and short code reviews ask for.

Leave it off where single opt-in is the accepted regime:

* **Most of the EU/UK under GDPR**, where legitimate interest or an
  existing soft opt-in exception covers the send.
* **Australia under the Spam Act**, where a prior business relationship
  plus a working unsubscribe path suffices.
* Any audience where consent you already hold (imported or collected at
  signup) satisfies the local regime; see
  [Country Requirements](/compliance/country-requirements) for
  per-jurisdiction posture.

The setting is per organization, so a US marketing org can run the flow
while an EU org in the same account leaves it off.

***

## 2. The consent state machine

Every (contact, channel) pair reads as one of four states:

| State | Meaning | Next marketing SMS to this contact |
| - | - | - |
| No record | No consent signal captured yet. | Replaced by the confirmation prompt; the original copy is not sent. |
| Pending (awaiting YES) | The prompt was sent and the reply is outstanding. | Held. The send returns `skipped` with reason `pending_consent`. |
| Confirmed | A YES / START / SUBSCRIBE reply was recorded, or consent was imported or collected earlier. | Delivered as written. |
| Opted out | A STOP (or a revocation) was recorded. | Blocked until consent is re-established. |

How the states map onto rows in your consent ledger:

* **No record** is simply the absence of a consent row for the pair.
* **Pending** is a row with consent type `sms_double_opt_in` stamped
  `awaiting_yes` at prompt time. It records that the contact was
  prompted; it is not a grant, and while it is the pair's only row,
  marketing stays held.
* **Confirmed** is an `opted_in` grant row written when the reply
  arrives. The original prompt row stays in the ledger, stamped
  confirmed, so the pair carries two dated events: prompted at, and
  confirmed at.

STOP is terminal. An opt-out row outranks a pending one, and a later
YES writes a fresh grant that outranks the opt-out, matching the
inbound re-subscribe semantics your suppression lists already follow.

***

## 3. Enable it

The flow reads three keys in your organization settings:
`sms_double_opt_in.enabled` (the gate), `sms_double_opt_in.brand_name`
(up to 32 characters, embedded in the prompt), and
`sms_double_opt_in.help_contact` (up to 64 characters, appended as a
`Help:` line when it fits the single-SMS budget).

### From the dashboard

Open **Settings → Compliance → SMS double opt-in**, flip the switch,
set the brand name and help contact if you want them, review the live
preview (it renders exactly what the recipient will receive), and choose
**Save changes**.

### From the API

The same keys go through the organization settings endpoint:

```bash theme={null}
curl -X PUT https://api.orbit.devotel.io/api/v1/settings/general \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "settings": {
      "sms_double_opt_in": {
        "enabled": true,
        "brand_name": "Acme",
        "help_contact": "help@acme.com"
      }
    }
  }'
```

Two cautions:

* `enabled` must be the literal boolean `true`. The string `"true"`
  leaves the flow off, because the gate checks strict equality.
* The settings merge replaces the whole `sms_double_opt_in` object, so
  send all three keys every time; sending only `enabled` clears your
  branding.

To disable the flow, send the same payload with `enabled: false`. Held
sends are not released retroactively; re-send the campaign when you are
ready.

***

## 4. The confirmation prompt, and customizing it

The shipped prompt follows the CTIA §5.2 confirmation format: program
identification, the affirmative act, the rates disclosure, frequency
language, and the STOP instruction.

> Reply YES to subscribe to Acme alerts. Msg & data rates may apply.
> Msg freq varies. Reply STOP to opt out. Help: [help@acme.com](mailto:help@acme.com).

Customization is the two setting keys, and deliberately only those:

* `brand_name` replaces the generic service reference. Keep it at or
  under 32 characters.
* `help_contact` appends the `Help:` sentence when the branded body
  still fits one SMS segment (160 GSM-7 characters). If your branding
  pushes the body over one segment, the prompt falls back to a shorter
  unbranded body so the rates disclosure and STOP instruction are never
  dropped.

Whatever you write, keep the CTIA shape: identify the program, name the
affirmative keyword, disclose message and data rates, and keep STOP.
Carriers review attestation copy against that shape; a prompt that
drops the rates disclosure or the keyword instruction is the kind of
finding that fails a campaign review. Platform-mandated STOP handling
applies to your program regardless of prompt copy.

***

## 5. While pending: marketing sends are held, not failed

After the first marketing send is rewritten to the prompt, further
marketing sends to the same contact short-circuit before they reach a
carrier:

* The send returns the message with `status: "skipped"` and
  `reason: "pending_consent"`. This is a soft skip in the same family as
  quiet-hours and suppression skips, not the 422 an opted-out recipient
  produces; batch and campaign jobs continue past the contact.
* Campaign reports show the recipient as skipped with that reason: not
  delivered, not failed. A held send is not billed as a delivered
  message.
* Because the message never reaches a carrier, no delivery webhook
  follows it. The skipped result is the whole record of the attempt, so
  do not build alerting that treats `pending_consent` as a delivery
  failure; it is the flow working as designed.

Transactional messages and one-time passcodes bypass the gate entirely.
Only sends you classify as marketing
(`metadata.message_type = "marketing"`) are ever held or rewritten.

***

## 6. Inbound YES: how the reply unblocks the contact

When the contact replies YES, START, or SUBSCRIBE, the standard inbound
keyword handling writes the `opted_in` grant and stamps the pending row
confirmed. You wire nothing extra: the same matcher that honors STOP
for opt-outs recognizes the affirmative side, and the next marketing
send delivers as written.

Multilingual replies are honored. The matcher recognizes affirmative
keywords in English, Turkish, German, Spanish, French, Portuguese,
Italian, Arabic, and Dutch (JA, OUI, SÍ, SIM, EVET and the rest), and it
normalises casing, invisible characters, and trailing punctuation, so
`yes.` and `YES` confirm exactly as `YES` does. Opt-out keywords win
any tie: a STOP is always honored over an affirmative read of the same
text. If you relay replies yourself through
`POST /compliance/consent/double-opt-in/confirm`, you may pass a `lang`
hint to pin the keyword set; see
[Confirmed Consent (Double Opt-In) Handshakes](/compliance/double-opt-in).

A reply that matches nothing (say, "maybe later") changes nothing: the
contact stays pending.

***

## 7. Audit: reading the evidence back

* **Per contact:** open Audience → Contacts → the contact → Consent
  log. You see the pending prompt row (prompted-at, and the send that
  triggered it) and the `opted_in` grant (confirmed-at, source of the
  reply) as separate entries.
* **Tenant-wide:** the Consent ledger lists grants and their states,
  including the Expiring view for time-bounded grants.
* **Exports:** the consent export gives you ledger rows over a window;
  use it to show that for any marketed contact, a prompt event precedes
  the grant event. See
  [Consent Management](/compliance/consent-management).
* **Evidence packages:** the evidence binder assembles consent history
  with the rest of your compliance evidence for a regulator or carrier
  discovery request. See
  [Evidence Binder](/compliance/evidence-binder).

Because the prompt and the reply are two dated ledger events rather
than one consent write, your export shows the handshake itself, which
is what a §5.1.3 review asks to see.

***

## 8. Common failure modes

**The contact never replies.** The pair stays pending indefinitely;
marketing stays held and nothing auto-sends, and the prompt does not
expire on its own. Re-issuing the send is safe: the contact is prompted
once, and later attempts skip with `pending_consent`. To re-engage the
contact, use another channel or a re-permission campaign per
[Migrating Consent](/guides/compliance-consent-migration).

**The contact replies STOP while pending.** Opt-out wins. The pair
moves to opted out, marketing is blocked, and the usual STOP
acknowledgement goes out. A later YES writes a fresh grant that
supersedes the opt-out.

**The contact replies with an unrecognized phrase.** State is
unchanged; the contact remains pending and the next marketing attempt
skips with `pending_consent` again.

**You enabled the flow over an already opted-in list.** Nothing changes
for those contacts. Any existing grant satisfies the gate, so confirmed
contacts are neither prompted nor held; only pairs with no consent
record receive a prompt.

**Migrating existing opted-in lists onto the flow.** Import the consent
you already hold before or as you enable the flow; imported grants
satisfy the gate, so proven contacts are never prompted. The migration
mechanics live in
[Migrating Consent](/guides/compliance-consent-migration).

**The prompt delivered but replies never confirm.** Check that the
replying number is one Orbit routes (inbound keyword handling only sees
messages that arrive on your numbers) and that the reply comes from the
same number that received the prompt: the YES is matched to the contact
by the number it arrives from.

***

## Worked example: US marketing tenant, end to end

Acme Runs, a US short code program, turns the flow on and sends a
campaign:

1. In **Settings → Compliance → SMS double opt-in**: switch on, brand
   name `Acme Runs`, help contact `help@acmeruns.com`, save. (The
   `PUT /settings/general` call from §3 does the same.)
2. The campaign sends a marketing SMS to `+14155550101`, a contact with
   no consent record. The send is rewritten: the contact receives
   `Reply YES to subscribe to Acme Runs alerts. Msg & data rates may apply. Msg freq varies. Reply STOP to opt out. Help: help@acmeruns.com.`
   and the contact's Consent log gains a pending row.
3. A second campaign fires before the contact answers. That recipient's
   result is `status: "skipped"`, `reason: "pending_consent"`; everyone
   else in the audience receives the campaign.
4. The contact texts `Yes.` Inbound keyword handling writes the
   `opted_in` grant and stamps the pending row confirmed; the Consent
   log now shows both dated events.
5. The next campaign delivers the real creative to that contact.

The pair's ledger entry, prompt at one timestamp and grant at another,
is the evidence a carrier or campaign review asks for.

***

## Related

* [Confirmed Consent (Double Opt-In) Handshakes](/compliance/double-opt-in)
* [Consent Management](/compliance/consent-management)
* [Migrating Consent](/guides/compliance-consent-migration)
* [Evidence Binder](/compliance/evidence-binder)
* [Opt-Out & Suppression Lists](/compliance/opt-out-suppression)


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