Skip to main content

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 and Consent Management. This page covers the operational loop: the setting, the state machine, the prompt, the skips, the reply, and the audit trail.
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.

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 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.
Every (contact, channel) pair reads as one of four states: 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:
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.
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. 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.
  • 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.
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. 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. 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.