Every SMS platform has an opt-in page in its docs, and they all read differently. AWS talks about registrations and opt-out lists. Braze talks about subscription groups. Twilio talks about Messaging Services. Underneath, the carriers ask one question, whatever tool you use: can you show that this person asked to get texts from this brand, and what did they see when they agreed?

This guide covers where each platform puts its opt-in controls, the parts the carriers check on every one of them, and how to build a double opt-in flow on Ready's API that keeps an audit trail. Platform consoles change often, so treat the platform notes as a map and confirm the details in each vendor's current docs before you build.

What carriers check, whatever platform you use

A2P 10DLC registration goes to the same carriers whether you submit through AWS, Braze's SMS provider, Twilio or Ready. Reviewers look at your opt-in flow and your sample messages. For more on that review, see what carriers actually check. Here is what they look for at the point of opt-in:

  • A visible call to action. This is a web form, a keyword ("Text JOIN to..."), a checkout checkbox or a paper form. The reviewer has to be able to find it, so a URL or screenshot is usually required.
  • Brand name. The person has to know who will text them.
  • Message type. For example: order updates, appointment reminders, promotions.
  • Frequency. "Up to 4 msgs/month" or "Message frequency varies."
  • "Msg & data rates may apply."
  • STOP and HELP instructions.
  • Links to your privacy policy and terms. The privacy policy must say you don't share mobile numbers with third parties for marketing.
  • An unchecked consent box that isn't bundled. SMS consent can't be a condition of buying, and it can't be hidden inside "I agree to the terms."

If your wording is the weak spot, our post on opt-in wording that clears registration on the first submission has copy you can adapt.

Platform by platform: where opt-in lives

AWS (Amazon End User Messaging SMS, formerly Pinpoint SMS)

AWS gives you the infrastructure and leaves the opt-in flow to you. In the console you submit 10DLC brand and campaign registrations, or toll-free verification. Those forms ask you to describe how people opt in, with a URL or screenshot. AWS also keeps opt-out lists and recognizes STOP-type keywords. You can turn on self-managed opt-outs if you'd rather handle them in your own system.

What you build yourself: the sign-up form, the consent record, the confirmation text and any double opt-in logic. AWS sends what you tell it to send. It doesn't know whether your list was collected properly.

Braze

Braze manages SMS consent through subscription groups. A user is subscribed or unsubscribed per group. Inbound keywords move users between those states, and Braze has an optional double opt-in setting where a confirmation reply completes the subscription. Braze sends through an underlying SMS provider, and your 10DLC registration still goes through that provider.

What you build yourself: the form or SDK call that puts the user into a pending or subscribed state, plus wording that matches the subscription group's purpose. If you have one group for "transactional" and one for "promotional," each needs its own consent language.

Twilio

Twilio's Messaging Services include opt-out keyword handling. Some accounts have advanced opt-out settings that let you edit the confirmation replies. Twilio doesn't collect opt-ins for you. Your 10DLC campaign submission describes the flow, and you build the double opt-in yourself with an inbound webhook.

Ecommerce SMS tools (Klaviyo, Attentive, Postscript and similar)

These tools usually ship hosted sign-up forms and popups with consent text and double opt-in built in. If you run a store and stay inside one of them, much of this guide is done for you. They're a reasonable choice for that use case.

Summary

PlatformWhere opt-in is configuredDouble opt-inWhat you still own
AWS End User MessagingRegistration forms describe it; you build the flowYou build itForm, consent record, confirm logic
BrazeSubscription groups and keyword settingsOptional settingWording per group, form or SDK wiring
TwilioCampaign submission describes it; Messaging Service handles STOPYou build itForm, consent record, webhook logic
Ecommerce SMS toolsHosted forms and popupsUsually built inWording review, terms and privacy pages
ReadyRegistration handled in-app; API sends and receivesYou build it on the API (below)Form, per-contact consent record

The pattern is the same everywhere: the platform handles STOP, and you own proof of consent. Most of these platforms leave proof of consent to you. Ready keeps it only for contacts who sign up on a Ready-hosted opt-in page (time, IP address and exact wording); for every other form, your system stores who agreed, when and to what wording.

Why double opt-in is worth the extra text

Single opt-in means the form submission counts as consent. Double opt-in adds a step: the person gets a text and replies YES to confirm. That step catches typos, fake numbers and people who entered a friend's number. Those mistakes otherwise turn into complaints, and complaints count against you at the carrier level. We cover this in detail in the deliverability case for the extra confirm step.

The cost is one or two extra segments per subscriber, and the setup is not complicated.

Building double opt-in on Ready

Step 1: capture consent on your side

Your form stores the record that matters:

  • the phone number
  • the timestamp
  • the exact consent wording shown
  • the page URL
  • the IP address or user agent

Ready records the sender's attestation on each API and bulk send: who sent, to how many, and when. It does not store per-contact opt-in wording or page URLs, and a keyword reply doesn't create a consent record in Ready. Your database keeps that record. Our post on documenting SMS consent so it holds up lists the fields. (A contact who signs up on a Ready-hosted opt-in page is the exception: Ready stores that sign-up, with the time, IP address and exact wording, and support@tryready.com can send you a copy.)

Step 2: send the confirmation text

When the form posts, send one text with consent_attested: true. The person just asked for it.

POST https://api.tryready.com/v1/messages
X-API-Key: <your key>
Idempotency-Key: 6f1c2a9e-3b7d-4e1a-9c55-2d8f0e4b7a13
Content-Type: application/json

{
  "to": "+12125550199",
  "body": "Acme Clinic: Reply YES to confirm appointment and offer texts. Up to 4 msgs/mo. Msg & data rates may apply. Reply HELP for help, STOP to opt out.",
  "consent_attested": true
}

That body is 145 GSM-7 characters, which is one segment. If you add an emoji, the limit drops to 70 characters and the text becomes 3 segments. Keep confirmations plain.

The Idempotency-Key header matters here. If your form handler retries after a timeout, the person still gets one confirmation, not two.

Step 3: catch the YES

Inbound replies arrive by webhook. You can also read them with GET /v1/messages, which pages with before_id. The webhook payload format is in the webhooks docs. When a YES arrives from a pending number, mark the contact confirmed in your database and store the reply timestamp next to the original form record. If no YES arrives within a window you choose (48 hours is common), leave the contact unconfirmed and don't text it again.

Step 4: STOP is already handled

Inbound STOP and UNSUBSCRIBE are honored automatically. The opt-out applies across all your campaigns, and any later send to that number is refused before it goes out, at no charge. You can check a number with GET /v1/opt-outs/:phone before re-enrolling someone. The SMS opt-out API post covers the edge cases.

One detail that surprises people: quiet hours

Ready enforces permitted local hours for the recipient's area. Campaigns, drip campaigns and automations wait up to 24 hours for the window, but a one-to-one or API text is held only if the window opens within 6 hours; otherwise it is refused, not sent, and the API answers with the refusal. So if someone signs up at 11 PM their time, an API confirmation is refused and you resend it in the morning, while one sent by an automation waits for the window and is charged only when it sends. Tell sign-ups on the form that they'll get a confirmation text, so a morning text doesn't look random.

What a double opt-in flow costs on Ready

Here is an example for a business that adds 1,000 sign-ups a month. It assumes each sign-up uses 3 one-segment texts: the confirmation, the YES reply (replies are billed like sent texts) and a welcome text.

  • 1,000 × 3 = 3,000 segments
  • Ready Standard: 3,000 × $0.0075 = $23
  • Carrier fee: 3,000 × $0.0045, itemized on the bill

This all-in figure excludes the compliance surcharge. TCPA/DNC scrubbing and landline validation are each $0.003 per segment when switched on, and both are off by default. Some sign-ups won't reply YES, so your real number will be lower.

AWS, Twilio and GoHighLevel's LeadConnector carry a lower per-segment rate. If you're already on one of them and your opt-in flow works, keeping it is a reasonable call. What Ready adds is registration handled in-app, sub-accounts for platforms texting on behalf of their own customers, and the opt-out, quiet-hours and scrub tooling built into one API.

Getting registered before you scale

Registration has no setup fee. You pay the first month at submit, $25. After that the monthly charge is $25/mo for registration and $2 per number. Most approvals take 2 to 7 days.

Until you register, an account can send up to 500 texts a month, which is enough to test the confirm-and-reply loop end to end. The first 20 texts are free one-to-one sends. They end once a registration is paid for, so use them for testing first. To send, you add a card and get a number, which is $2 a month with the first month charged when you get it.

The practical takeaway

Whichever platform you use, the platform handles STOP and you own the consent record. Get the form wording right and store the timestamp, wording and URL. Add a YES confirmation that catches bad numbers before they turn into complaints. Then pick the platform based on what you need around that flow.

If you want to try the flow on Ready, the quickstart walks through an API key and a first send, and you can create an account to test the confirm loop on your own number.