# Ekas 10DLC Rule Registry — Message content

> The 122 message content rules Ekas checks during A2P 10DLC registration.

- Source: https://ekas.io/rules/10dlc/
- Rules in this document: 122
- Registry last updated: 2026-07-25
- Licence: CC BY 4.0 — https://creativecommons.org/licenses/by/4.0/
- Layer: `MESSAGE_CONTENT`

---
## MSG-008 — Opt-in confirmation must be 20–255 characters

> The opt-in confirmation must be at least 20 and at most 255 characters.

- **Rule ID:** MSG-008
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optin_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, Bird, Sinch
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-008/

### Why this rule exists

The confirmation has the longest required element list of the three auto-replies — brand, programme, frequency, rates, HELP and STOP — so it is the one most likely to overrun. Truncation drops the tail, and the tail is where STOP lives.

### How to fix it

Compress to 255 characters while keeping all six required elements. Abbreviate "Msg & data rates may apply" rather than dropping it.

### Example of a compliant value

```text
Acme Coffee: you're subscribed to offers. Msg frequency varies. Msg & data rates may apply. Reply HELP for help, STOP to cancel.
```

---

## MSG-009 — HELP reply must be 20–255 characters

> The HELP response must be at least 20 and at most 255 characters.

- **Rule ID:** MSG-009
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.help_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, Bird, Sinch
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-009/

### Why this rule exists

Below 20 characters the reply cannot carry the brand name and a contact route, which are the two things it exists to deliver. Above 255 it exceeds the portable ceiling and is truncated at some providers — losing the tail, which is usually where the opt-out instruction sits.

### How to fix it

Fit the HELP reply into 255 characters carrying the brand name, a real support contact, the rates notice and the opt-out instruction. Drop marketing language before dropping any of those.

### Example of a compliant value

```text
Acme Coffee: for help email support@acmecoffee.com or call 415-555-0134. Msg & data rates may apply. Reply STOP to unsubscribe.
```

---

## MSG-011 — Opt-out confirmation must be 20–255 characters

> The STOP confirmation must be at least 20 and at most 255 characters.

- **Rule ID:** MSG-011
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optout_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, Bird, Sinch
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-011/

### Why this rule exists

This is the last message you are permitted to send, so it must fit in one segment and say everything it needs to in one pass. A truncated opt-out confirmation can lose the acknowledgement itself, leaving the consumer unsure whether the unsubscribe worked.

### How to fix it

Fit the confirmation into 255 characters: brand name, the acknowledgement, and that no further messages will be sent.

### Example of a compliant value

```text
Acme Coffee: you have been unsubscribed and will receive no further messages. Reply HELP for help.
```

---

## MSG-015 — A message must not render as ten or more segments

> No sample message may be long enough to render as 10 or more SMS segments.

- **Rule ID:** MSG-015
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-015/

### Why this rule exists

Every segment is billed and delivered separately, and long concatenated messages are reassembled unreliably across carriers — so a ten-segment message costs ten times as much and is the most likely thing in your programme to arrive broken. Reviewers read extreme length as a sender who does not understand the channel.

### How to fix it

Shorten the message and move detail behind a link on your own domain. Aim for one or two segments — 160 GSM characters per segment, or 70 if the message contains any non-GSM character.

### Example of a compliant value

```text
Acme Coffee: your order is ready. Details: https://acmecoffee.com/o/4471 Reply STOP to opt out.
```

---

## MSG-018 — An MMS campaign must attach at least one sample media file

> A campaign that requests MMS capability must supply at least one sample media file alongside the sample message text.

- **Rule ID:** MSG-018
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.mms_sample_media`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** AWS
- **Applies:** Applies when `mmsEnabled` is true.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-018/

### Why this rule exists

MMS is approved on what the recipient will actually see, and for a picture message that is the picture — a reviewer who is shown only the caption has no way to tell a product photo from something that would fail SHAFT screening on sight. Businesses miss this because the sample text field accepts their submission happily and nothing on the form says the attachment is a separate requirement, so the rejection arrives for a field they never noticed was empty.

### How to fix it

Attach the actual image or video you will send to the campaign's MMS sample media, one file per sample message that carries media. Done when every MMS sample has a file next to its text, not just a caption describing one.

### Example of a compliant value

```text
mms_sample_media: acme-summer-sale.png (image/png, 214 KB) — the same artwork the weekend promotion will send.
```

### Common mistakes

- Turning MMS on and leaving the attachments for later is the usual cause: the capability flag and the sample media are separate fields, and the flag is what puts you under this requirement.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| AWS | `MISSING_CONDITIONAL_FIELD` | yes |

---

## MSG-019 — Each MMS sample file must sit under its per-type size ceiling

> Every attached MMS sample file must be at most 500 KB for GIF, JPEG and PNG images, and at most 600 KB for any other media type.

- **Rule ID:** MSG-019
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.mms_sample_media`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** AWS
- **Applies:** Applies when `mmsEnabled` is true.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-019/

### Why this rule exists

The ceiling is the handset's, not the reviewer's: an oversized MMS is transcoded or dropped somewhere in the carrier chain, so the recipient gets a broken message and the sender never learns why. Registration rejects it up front instead. This catches out businesses who attach the print-resolution asset their designer handed over, because nothing about a 3 MB PNG looks wrong until it is measured.

### How to fix it

Re-export each attachment under its ceiling — 500 KB for GIF, JPEG and PNG, 600 KB for everything else — and re-upload. Resizing to 1200 px on the long edge and exporting at 80% JPEG quality clears it for almost any promotional image. Done when every file in the sample media list reports a size below its own limit.

### Example of a compliant value

```text
acme-summer-sale.png re-exported at 1200x628 → 214 KB (limit 500 KB for PNG).
```

### Common mistakes

- The tighter 500 KB bound is keyed on the file type, not on it being an image: a WebP or a short MP4 gets the 600 KB allowance, a PNG does not.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| AWS | `INVALID_FIELD_VALUE` | yes |

---

## MSG-020 — MMS sample images must not be placeholder or stock artwork

> The attached MMS sample media must show the artwork the campaign will actually send, not a placeholder graphic or an unlicensed stock image standing in for it.

- **Rule ID:** MSG-020
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.mms_sample_media`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI vision over a consent artifact (screenshot, scan, MMS media)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** AWS
- **Applies:** Applies when `mmsEnabled` is true.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-020/

### Why this rule exists

The picture is how a reviewer decides whether an MMS programme is what it claims to be, so a grey "image goes here" block or a generic stock photo leaves them judging the campaign on the caption alone — and campaigns that register with filler artwork are the ones that later send something else. The honest cause is usually sequencing: the artwork is still with the designer when the registration goes in, and a stand-in feels harmless.

### How to fix it

Replace each attachment with the finished creative for that message, carrying your own branding and your own products. Done when someone who has never seen your business could name it from the image alone.

### Example of a compliant value

```text
acme-summer-sale.png: the Acme Coffee wordmark over a photo of the espresso blend on offer, with "20% off this weekend" set in the brand typeface.
```

### Common mistakes

- A licensed stock photo is still a fail here when nothing in the frame identifies the sender — the objection is anonymity, not the licence.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| AWS | `NON_COMPLIANT_MESSAGE_SAMPLES` | yes |

---

## MSG-026 — Samples must not contain mustache or curly-brace template tokens

> Curly-brace and mustache tokens such as {order_id} or {{name}} must not appear in sample messages.

- **Rule ID:** MSG-026
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-026/

### Why this rule exists

Square brackets are the convention reviewers read as "this varies at send time"; curly braces read as an unrendered template that leaked into the registration. The distinction is arbitrary but it is the one applied, and the fix costs nothing.

### How to fix it

Convert every curly-brace or mustache token to square-bracket notation with a readable name.

### Example of a compliant value

```text
Acme Coffee: hi [first name], order [order number] ships today. Reply STOP to opt out.
```

---

## MSG-031 — Sample messages must be in English

> Sample messages must be written in English, or an English translation supplied alongside.

- **Rule ID:** MSG-031
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-031/

### Why this rule exists

US reviewers assess against US requirements in English, and a sample they cannot read cannot be checked for the disclosures and content rules everything else depends on. Sending in other languages is fine — the registration artifact needs to be readable.

### How to fix it

Supply the samples in English. Where the programme genuinely sends in another language, include both the original and an English translation in the sample.

### Example of a compliant value

```text
Acme Coffee: su pedido está listo. / Acme Coffee: your order is ready. Reply STOP to opt out.
```

---

## MSG-034 — Samples must not be framed as test, demo or machine-to-machine traffic

> Sample messages and the campaign description must describe real messages sent to real subscribers, not test traffic, demonstrations, or machine-to-machine signalling.

- **Rule ID:** MSG-034
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + campaign.description`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-034/

### Why this rule exists

10DLC is a production registration: the throughput and the trust that come with it are granted on the basis that a person receives each message and consented to it, so a campaign that says it is for testing is asking for a production route to carry something that is not production traffic. Developers land here honestly, registering during integration with exactly the samples their test harness sends — and reviewers cannot tell that from a sender who intends to keep the campaign in test framing indefinitely, so they refuse it.

### How to fix it

Replace the samples with the messages the campaign will send once it is live, and rewrite the description so it names the real audience and what they will receive. Done when nothing in the submission would still be true if the word "test" were the point — a reviewer should not be able to tell you registered during integration.

### Example of a compliant value

```text
Acme Coffee: your order #4471 is ready for pickup at our Mission St store until 6pm today. Reply STOP to opt out, HELP for help.
```

### Common mistakes

- Registering a throwaway campaign to test the integration and a real one later does not work either — the test campaign is refused on this rule, so the integration has nothing to test against.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| AWS | `CAMPAIGN_NON_COMPLIANT_CONTENT_NON_SUBSCRIBER` | yes |
| AWS | `NON_COMPLIANT_USE_CASE` | yes |

---

## MSG-038 — A registered domain can substitute for the brand name in a sample

> Where a sample does not carry the brand name, the brand's registered domain appearing in the message can satisfy sender identification.

- **Rule ID:** MSG-038
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + brand.website`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-038/

### Why this rule exists

Sender identification exists so the recipient knows who is texting them, and a link to acmecoffee.com does that as well as the words "Acme Coffee". Recording this explicitly prevents the brand-name check from producing false failures on messages that are perfectly identifiable.

### How to fix it

Prefer the brand name at the start of the message. Where space is genuinely tight, a link to the registered domain identifies the sender acceptably.

### Example of a compliant value

```text
Order ready for pickup: https://acmecoffee.com/o/4471 Reply STOP to opt out.
```

---

## MSG-042 — Every message must identify who is sending it

> The message body must identify the entity on whose behalf it is sent, and where relevant give a contact route.

- **Rule ID:** MSG-042
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR, T-Mobile, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-042/

### Why this rule exists

Sender identification is the foundational content requirement: a consumer receiving a text from an unknown number has no way to distinguish a legitimate business from a scam. Everything else in the framework assumes the recipient can tell who is texting them.

### How to fix it

Lead every message with the brand name. Where the message is sent on behalf of another entity, name that entity rather than the platform.

### Example of a compliant value

```text
Acme Coffee: your order #4471 is ready for pickup. Reply STOP to opt out.
```

---

## MSG-045 — Samples must not impersonate another organisation

> Sample messages must not impersonate or misrepresent another business, bank, government agency, or technology company.

- **Rule ID:** MSG-045
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + campaign.description`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** CTIA, T-Mobile, Twilio, TCR, FTC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-045/

### Why this rule exists

Impersonation is a Severity-0 finding that stops all messaging on the programme, and it attracts per-message violation fees rather than a rejection you can fix. It is also the category carriers escalate fastest, because it maps directly onto fraud.

### How to fix it

Remove any content implying you are, or are authorised by, another organisation. Send only under your own registered brand identity.

---

## MSG-046 — Samples must be consistent with the brand website

> Sample messages must describe a business consistent with what the brand website shows.

- **Rule ID:** MSG-046
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + brand website`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, AWS, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-046/

### Why this rule exists

Reviewers read the samples with the website open, and a mismatch is the signature of a registration assembled from someone else's business. It is also how an undeclared use case gets discovered.

### How to fix it

Rewrite the samples to describe the products, services and locations the website actually shows.

### Example of a compliant value

```text
Website sells coffee subscriptions → samples reference orders, roasts and store events.
```

---

## MSG-049 — Opt-out instructions must name a recognised keyword

> Opt-out instructions in message bodies must use a widely accepted keyword, not an invented alternative.

- **Rule ID:** MSG-049
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, FCC, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-049/

### Why this rule exists

Handsets and carrier platforms recognise a fixed keyword set, so an instruction like "text 2 to opt out" produces a reply nothing acts on — the consumer believes they have unsubscribed and keeps receiving messages. That is the exact scenario that turns into a complaint.

### How to fix it

Use STOP in message bodies. Reserve other keywords for the declared keyword list rather than advertising them as the primary route.

### Example of a compliant value

```text
Reply STOP to opt out, HELP for help.
```

### Common mistakes

- "Reply 2 to unsubscribe" and "text QUITNOW" both fail — handsets do not route them.

---

## MSG-054 — Universal opt-out keywords must be supported in copy and configuration

> STOP, END, CANCEL, UNSUBSCRIBE and QUIT must all be supported, both in the keyword configuration and honoured in practice.

- **Rule ID:** MSG-054
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optout_keywords`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, FCC, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-054/

### Why this rule exists

These five are recognised at handset and carrier level regardless of configuration, so a consumer using any of them has effectively opted out whether your platform noticed or not. Declaring them aligns your suppression list with what has already happened.

### How to fix it

Add all five universal keywords to the configuration, ideally alongside REVOKE and OPTOUT.

### Example of a compliant value

```text
STOP, QUIT, END, REVOKE, OPTOUT, CANCEL, UNSUBSCRIBE
```

---

## MSG-056 — A no-reply route must disclose that replies are not received

> Where the sending route cannot receive inbound texts, every message must clearly disclose that replies are not monitored.

- **Rule ID:** MSG-056
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-056/

### Why this rule exists

Telling a consumer to "reply STOP" on a route that discards inbound messages is worse than saying nothing: they believe they have opted out and keep receiving messages. If replies genuinely cannot be received, the opt-out route must be stated some other way.

### How to fix it

Use a route that receives replies. If you genuinely cannot, disclose it in every message and give a working alternative opt-out route.

### Example of a compliant value

```text
Acme Coffee: your order is ready. This number does not receive replies — manage texts at https://acmecoffee.com/sms-preferences
```

---

## MSG-058 — A recurring programme must have an opt-in confirmation

> Every recurring message programme must send a confirmation message when a consumer opts in.

- **Rule ID:** MSG-058
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optin_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR, Bandwidth, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-058/

### Why this rule exists

The confirmation is the consumer's receipt: it tells them the opt-in worked, what they joined, and how to leave. Without one, the first message they receive is marketing from an unfamiliar number, which is the single most reliable way to generate a spam report.

### How to fix it

Configure an opt-in confirmation carrying the brand, programme name, frequency, rates notice, HELP and STOP.

### Example of a compliant value

```text
Acme Coffee: you're subscribed to offers. Msg frequency varies. Msg & data rates may apply. Reply HELP for help, STOP to cancel.
```

---

## MSG-060 — The opt-in confirmation must be the first message sent

> The confirmation must precede any other messaging to a newly opted-in consumer.

- **Rule ID:** MSG-060
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.message_flow + campaign.optin_message`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-060/

### Why this rule exists

Leading with marketing to someone who has just given a number, before confirming what they joined, inverts the relationship the confirmation exists to establish. CTIA sequences it deliberately: acknowledge first, then send.

### How to fix it

Sequence the confirmation ahead of any campaign content in your automation, and describe that ordering in the message flow.

### Example of a compliant value

```text
On opt-in we immediately send the confirmation; campaign content begins with the next scheduled send.
```

---

## MSG-061 — The opt-in confirmation must name the registered brand

> The opt-in confirmation message must contain the registered brand name or DBA, matching the brand record.

- **Rule ID:** MSG-061
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optin_message + brand.display_name`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** Bandwidth, AWS, Sinch, Infobip, Bird, TCR, Aerialink, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-061/

### Why this rule exists

The confirmation is the first message the programme ever sends, and it arrives at a moment when the recipient has typed a number into a form and may not remember which one. If it does not say who it is from, the rational response is to treat it as spam and report it — which is why a nameless confirmation produces complaints out of all proportion to its volume. Almost every provider checks this field specifically, and it is missed because the confirmation is usually written last, as a technical acknowledgement rather than as a message to a person.

### How to fix it

Put the registered brand name at the start of the opt-in confirmation, before anything else — use the name on the brand record rather than a programme nickname a reviewer cannot match to it. Done when someone who has forgotten signing up could tell from the first three words who is texting them.

### Example of a compliant value

```text
optin_message: "Acme Coffee Rewards: you are subscribed to offers and rewards updates. Msg frequency varies. Msg & data rates may apply. Reply HELP for help, STOP to cancel."
```

### Common mistakes

- A programme name is not the brand name unless the brand name is inside it — "Rewards Club" fails where "Acme Coffee Rewards" passes, because the reviewer is matching against the registration.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Bandwidth | `5104` | yes |
| Twilio (gen1) | `30927` | yes |
| AWS | `OPT_IN_MESSAGE_MISMATCH` | yes |

---

## MSG-062 — Opt-in confirmation must name the programme

> The confirmation must name the programme or describe the product, so the consumer knows which subscription they joined.

- **Rule ID:** MSG-062
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optin_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-062/

### Why this rule exists

A business can run several programmes on one number, and "you are subscribed" tells the consumer nothing about which. Naming it is what lets them recognise the later messages as expected rather than unsolicited.

### How to fix it

Name the specific programme in the confirmation, not just the brand.

### Example of a compliant value

```text
Acme Coffee Rewards: you're subscribed to weekly offers. Msg frequency varies. Msg & data rates may apply. Reply HELP for help, STOP to cancel.
```

---

## MSG-063 — Opt-in confirmation must disclose message frequency

> The confirmation must state how often messages will arrive.

- **Rule ID:** MSG-063
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optin_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-063/

### Why this rule exists

CTIA requires frequency in the confirmation specifically, and it is the disclosure most often present at the web opt-in and missing from the confirmation. It sets the expectation that determines whether the third message of the week reads as service or spam.

### How to fix it

Add a frequency statement, matching whatever you promised at the opt-in.

### Example of a compliant value

```text
Msg frequency varies.
```

---

## MSG-064 — Opt-in confirmation must carry the rates disclosure

> The confirmation must state that message and data rates may apply.

- **Rule ID:** MSG-064
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optin_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR, Bandwidth, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-064/

### Why this rule exists

The consumer may be billed per message by their carrier, and the confirmation is the first point at which they could act on that knowledge. It is a mechanically-checked element, so its absence is caught reliably.

### How to fix it

Add "Msg & data rates may apply." to the confirmation. Keep it even when tight on characters — it is mechanically checked, and dropping it is a certain finding while shortening the marketing copy is free.

### Example of a compliant value

```text
Msg & data rates may apply.
```

---

## MSG-065 — Opt-in confirmation must carry HELP instructions

> The confirmation must tell the consumer how to get help or give a support contact.

- **Rule ID:** MSG-065
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optin_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-065/

### Why this rule exists

The confirmation arrives from a number the consumer has never seen before, so it is exactly the moment they may want to check who is texting them. Giving the HELP route here closes that loop before it becomes a complaint.

### How to fix it

Add "Reply HELP for help" or a direct support contact to the confirmation.

### Example of a compliant value

```text
Reply HELP for help, STOP to cancel.
```

---

## MSG-066 — Opt-in confirmation must carry a working opt-out instruction

> The confirmation must include STOP instructions echoing a keyword the programme honours.

- **Rule ID:** MSG-066
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optin_message + campaign.optout_keywords`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, FCC, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-066/

### Why this rule exists

A consumer who realises immediately that they did not mean to subscribe should be able to leave from the first message. The keyword named must be one the platform actually honours, or the instruction is worse than useless.

### How to fix it

Add "Reply STOP to cancel" and confirm STOP is in your declared opt-out keyword set.

### Example of a compliant value

```text
Reply HELP for help, STOP to cancel.
```

---

## MSG-073 — HELP response must name the brand or programme

> The HELP reply must contain the registered brand or programme name.

- **Rule ID:** MSG-073
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.help_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-073/

### Why this rule exists

HELP exists so a recipient who does not recognise a number can find out who is texting them. A reply that omits the name answers the wrong question and leaves reporting the message as spam as the only remaining option.

### How to fix it

Start the HELP reply with the brand or programme name, using the name the consumer would recognise from the opt-in rather than the legal entity name.

### Example of a compliant value

```text
Acme Coffee Rewards: for help email support@acmecoffee.com. Reply STOP to unsubscribe.
```

---

## MSG-074 — HELP response must give a real support contact

> The HELP reply must contain at least one support contact — a phone number, an email address, or a support URL.

- **Rule ID:** MSG-074
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.help_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-074/

### Why this rule exists

CTIA requires help routes not to be dead ends. A reply naming the brand but offering no way to reach it satisfies the letter of "respond to HELP" while failing its entire purpose, and it is a named Severity-2 audit finding.

### How to fix it

Add a monitored support email, a phone number that is answered, or a support page URL on the brand domain.

### Example of a compliant value

```text
Acme Coffee: for help email support@acmecoffee.com or call 415-555-0134. Reply STOP to unsubscribe.
```

---

## MSG-075 — HELP reply support contact must be on the brand domain

> The support email given in the HELP response must be on the registered brand domain.

- **Rule ID:** MSG-075
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.help_message + brand.website`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-075/

### Why this rule exists

A HELP reply pointing at a domain unrelated to the brand looks like a redirection to a third party, which is precisely what reviewers screen for. It also breaks the CTIA requirement that help routes actually reach the sender rather than a dead end.

### How to fix it

Use a support address on the brand's own domain in the HELP reply, matching the brand website.

### Example of a compliant value

```text
Acme Coffee: for help email support@acmecoffee.com. Reply STOP to unsubscribe.
```

---

## MSG-078 — HELP must be a configured help keyword

> The literal keyword HELP must appear in the configured help keyword set.

- **Rule ID:** MSG-078
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.help_keywords`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-078/

### Why this rule exists

HELP is the universal keyword handsets and consumers expect, and it must produce a response whether or not the requester is subscribed. Configuring only a custom alternative like INFO leaves the standard route silent.

### How to fix it

Add HELP to campaign.help_keywords, alongside any custom alternatives you support. Done when texting the bare word HELP produces the help reply for a subscriber and a non-subscriber alike.

### Example of a compliant value

```text
help_keywords: HELP, INFO, SUPPORT
```

---

## MSG-081 — STOP confirmation must name the brand or programme

> The opt-out confirmation must contain the registered brand or programme name.

- **Rule ID:** MSG-081
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optout_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-081/

### Why this rule exists

A consumer who unsubscribes from several programmes needs to know which one just stopped. An anonymous confirmation leaves them unsure whether the right subscription ended, which produces a second opt-out attempt or a complaint.

### How to fix it

Start the opt-out confirmation with the brand or programme name, so a consumer unsubscribing from several programmes knows which one just ended.

### Example of a compliant value

```text
Acme Coffee Rewards: you have been unsubscribed and will receive no further messages.
```

---

## MSG-082 — STOP confirmation must acknowledge the request

> The confirmation must acknowledge that the opt-out request was received and acted on.

- **Rule ID:** MSG-082
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optout_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, FCC, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-082/

### Why this rule exists

Without an explicit acknowledgement the consumer cannot tell whether their STOP registered, and the rational response to that uncertainty is to complain to the carrier. The acknowledgement is what closes the interaction.

### How to fix it

State plainly that the consumer has been unsubscribed, in the past tense so it reads as a completed action rather than a request received.

### Example of a compliant value

```text
Acme Coffee: you have been unsubscribed.
```

---

## MSG-083 — STOP confirmation must state no further messages will be sent

> The confirmation must state explicitly that the consumer will receive no further messages.

- **Rule ID:** MSG-083
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.optout_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, FCC, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-083/

### Why this rule exists

Acknowledging the request and promising the consequence are different statements, and CTIA requires both. "We got your request" without "you will receive no more messages" leaves open whether anything actually changes.

### How to fix it

Add the forward-looking statement that no further messages will be sent, alongside the acknowledgement — CTIA requires both, and an acknowledgement alone leaves open whether anything changed.

### Example of a compliant value

```text
Acme Coffee: you have been unsubscribed and will receive no further messages. Reply HELP for help.
```

---

## MSG-088 — Public URL shorteners are prohibited in every registration field

> No public URL shortener may appear in the description, message flow, samples, HELP reply, or either confirmation message.

- **Rule ID:** MSG-088
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.* (every text field)`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR, Twilio, Bandwidth, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-088/

### Why this rule exists

Shorteners hide the destination, so carriers cannot assess where a message leads and block them categorically. Tools typically check only the sample messages, but the prohibition covers every field — a shortener in the HELP reply or the opt-in confirmation is rejected exactly the same way.

### How to fix it

Replace every shortened link with the full URL on your own domain. Note the two Twilio generations disagree on whether this is fixable — assume the strict reading, where it is not resubmittable.

### Example of a compliant value

```text
https://acmecoffee.com/sale rather than https://bit.ly/3xY2z
```

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen1) | `30892` | yes |
| Twilio (gen2) | `30963` | no |
| Bandwidth | `8201` | yes |

---

## MSG-095 — Any shortener used must be dedicated to this sender

> Where a short domain is used, it must be dedicated to the exclusive use of the message sender.

- **Rule ID:** MSG-095
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-095/

### Why this rule exists

The published standard is stricter than "avoid bit.ly": CTIA requires the shortener to have a web address and IP addresses dedicated to the sender exclusively. A branded short domain running on shared redirect infrastructure still fails, which surprises brands who did the obvious thing and bought a vanity domain.

### How to fix it

Use a short domain you own on infrastructure only you use, or skip shortening and use full URLs on your primary domain — which sidesteps the requirement entirely.

### Example of a compliant value

```text
https://acme.link/sale where acme.link is yours alone — or simply https://acmecoffee.com/sale
```

### Common mistakes

- A vanity domain on a shared shortener service does not satisfy the dedicated-infrastructure rule.

---

## MSG-098 — Links must not pass through multi-hop redirects

> A URL in message content must not chain through multiple redirects that hide the eventual destination.

- **Rule ID:** MSG-098
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] link destinations`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR, T-Mobile
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-098/

### Why this rule exists

Redirect chains defeat the transparency the URL rules exist to create — the consumer, and the carrier, cannot know where the link ends up. It is also the standard technique for laundering a blocked destination through a clean-looking first hop.

### How to fix it

Link the final destination directly. Where click tracking is required, use a first-party tracking path on your own domain that redirects once.

### Example of a compliant value

```text
https://acmecoffee.com/sale (direct) rather than a tracking chain through three third-party hosts.
```

---

## MSG-101 — Links must not be intended to deceive or cause harm

> Embedded links must not be designed to mislead the recipient or deliver harm.

- **Rule ID:** MSG-101
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + link destinations`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** CTIA, T-Mobile, Twilio, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-101/

### Why this rule exists

Phishing and malware delivery are Severity-0 findings carrying "cease all messaging", and the audit scope explicitly includes the landing page and any downloaded artifact — not just the SMS body. This is judged on intent and presentation, not on the URL string.

### How to fix it

Remove any link whose presentation misrepresents where it leads or what it does. Link text and destination must match.

---

## MSG-103 — The page a sample links to is screened as part of the campaign

> The landing page reached from a link in a sample message must be free of prohibited content, and is screened whether or not it is on the registered brand domain.

- **Rule ID:** MSG-103
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] URL -> landing page`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the crawled website or policy page
- **Fix type:** Fix the website — no form edit clears it
- **Required by:** Twilio, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-103/

### Why this rule exists

A message is three words and a link, so the link is where the content actually lives — which is why Twilio's prohibited-content scope covers "campaign descriptions, sample messages, website content, and linked URLs" rather than stopping at the registered domain. The gap this closes is real and routinely exploited: a clean sample pointing at a dispensary menu, a sportsbook offer, or an affiliate page passes every check that reads text fields. It also catches honest senders, because a campaign link often lands on a partner or marketplace page that the brand does not control and has never read as a compliance artifact.

### How to fix it

Open every URL that appears in a sample and read the page a reviewer will land on, including anything it redirects to. Where the destination carries prohibited content, point the message at a page you control that does not — and if the prohibited content is the product, the campaign is not registrable on it. Done when every linked destination could be shown to a reviewer without explanation.

### Common mistakes

- Screening only the registered brand website misses this entirely: the finding is about where the message goes, and campaigns frequently link somewhere the brand record never mentions.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30953` | no |

---

## MSG-104 — Link destinations must identify their owner

> A landing page linked from a message must unambiguously identify the site owner as a person or registered business, with contact information.

- **Rule ID:** MSG-104
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] link destinations`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the website — no form edit clears it
- **Required by:** CTIA, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-104/

### Why this rule exists

CTIA requires the message URL and every site it redirects to to identify the owner and carry contact details such as a postal address. This is a second, independent requirement beyond not using a shortener, and almost no tooling checks it.

### How to fix it

Ensure every page linked from a message names the business and carries contact information, including a postal address in the footer.

---

## MSG-105 — The advertised offer must match the landing page

> The offer described in a sample message must be the offer a recipient finds on the page the message links to.

- **Rule ID:** MSG-105
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] <-> landing page`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the crawled website or policy page
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-105/

### Why this rule exists

Bait-and-switch is the complaint consumers actually make — they were told about a discount, clicked, and found a signup wall or a different price — and it is one of the named triggers for Twilio's deceptive-marketing code, which is not eligible for resubmission. Honest campaigns drift into it through timing rather than intent: the sample was written against last quarter's promotion and the page has moved on, or the deep link rots and lands on a generic homepage where the advertised offer is nowhere in sight.

### How to fix it

Rewrite each sample so it describes what is genuinely on the page it links to, or point the link at the page that carries the offer. Deep-link to the offer rather than to the site root, so the recipient sees the thing they were promised without hunting for it. Done when the headline on the landing page and the offer in the message say the same number.

### Example of a compliant value

```text
Acme Coffee: 20% off all espresso blends this weekend. Shop https://acmecoffee.com/sale — and the page at /sale leads with "20% off all espresso blends, this weekend only". Reply STOP to opt out.
```

### Common mistakes

- A page that carries the offer somewhere below three screens of other content still reads as a switch — reviewers judge what is visible on arrival.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30962` | no |

---

## MSG-106 — Link domains must not appear in threat intelligence

> Domains appearing in message content must not be flagged by threat-intelligence sources.

- **Rule ID:** MSG-106
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] link domains`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA, T-Mobile, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-106/

### Why this rule exists

Carriers screen destinations against reputation databases, so a link to a compromised or previously-abused domain gets the campaign filtered regardless of how clean the registration is. Shared hosting and recycled domains are the usual innocent cause.

### How to fix it

Check every domain you link against Google Safe Browsing and VirusTotal before registering, and move off any flagged host. A previously-abused domain will not clear simply by waiting.

### Check this yourself

**Is every domain you link to in these messages clean on Google Safe Browsing and VirusTotal today?**

1. List the domains in the sample messages, including link-shortener destinations.
2. Check each against Google Safe Browsing and VirusTotal.
3. Move off any flagged host — a previously abused domain will not clear simply by waiting.

*What wrong looks like:* A recycled domain or a shared host carries somebody else's history into your campaign, and the traffic is filtered regardless of how clean the registration is.

### Notes

Needs a reputation lookup the product does not have; surfaced as a warning with the check the user should run themselves.

---

## MSG-116 — embeddedPhone must ignore the HELP support number

> The embeddedPhone attribute should be set when a sample contains a phone number other than the support number given in the HELP reply.

- **Rule ID:** MSG-116
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.embedded_phone + campaign.sample[]`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-116/

### Why this rule exists

Publishing a support number in a HELP response is required, so counting it as an embedded phone number forces a true declaration that misrepresents the campaign. The attribute is meant to flag numbers inside marketing content, which is a redirection signal, not a support contact.

### How to fix it

Set the embedded-phone attribute based on numbers in campaign content, excluding the support number you publish in the HELP reply.

### Example of a compliant value

```text
Samples contain no numbers other than the HELP support line → leave "messages contain phone numbers" false.
```

---

## MSG-117 — A sample must contain a phone number when embeddedPhone is declared

> When embeddedPhone is true, at least one sample must contain a phone number.

- **Rule ID:** MSG-117
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.embedded_phone + campaign.sample[]`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-117/

### Why this rule exists

Mirror of the link rule: the attribute drives filtering for numbers inside message bodies, which is a redirection signal. Declaring it with no example leaves the reviewer unable to see what kind of number appears and why.

### How to fix it

Include a representative sample containing the number, or set the attribute false. Remember a HELP-reply support number does not by itself require the attribute.

### Example of a compliant value

```text
Acme Coffee: questions about your order? Call 415-555-0134. Reply STOP to opt out.
```

---

## MSG-119 — A sample must contain a URL when embeddedLink is declared

> When embeddedLink is true, at least one sample message must actually contain a URL.

- **Rule ID:** MSG-119
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.embedded_link + campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, AWS, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-119/

### Why this rule exists

The attribute tells carriers to apply link-specific filtering, so declaring it without demonstrating a link means the campaign is registered for treatment it never exercises — and a reviewer reads the mismatch as a careless or copied registration.

### How to fix it

Either include a representative link in a sample, or set the embedded-link attribute false if the programme genuinely sends no links.

### Example of a compliant value

```text
Acme Coffee: 20% off this weekend. Shop https://acmecoffee.com/sale Reply STOP to opt out.
```

---

## MSG-120 — Declared attributes must match sample content generally

> Every declared campaign attribute must be consistent with what the sample messages actually contain.

- **Rule ID:** MSG-120
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign attributes + campaign.sample[]`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-120/

### Why this rule exists

Attributes are self-declared and drive filtering, so a mismatch either over-restricts your own traffic or under-declares something carriers screen for. The link and phone pairs are checked individually; this catches the rest as a set.

### How to fix it

Walk each attribute against the samples and correct whichever side is wrong.

### Example of a compliant value

```text
Samples mention financing → direct lending: true.
```

---

## MSG-123 — Age-restricted content requires the age-gated attribute

> Where sample or description content covers alcohol, firearms, or tobacco, the age-gated attribute must be set true.

- **Rule ID:** MSG-123
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.age_gated + campaign content`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, CTIA, T-Mobile, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-123/

### Why this rule exists

The attribute is what tells carriers an age gate is in place, and the underlying categories carry per-message violation fees rather than rejections. Declaring it is the difference between a restricted campaign and an enforcement event.

### How to fix it

Set the age-gated attribute true and implement real date-of-birth verification at opt-in. Note several providers refuse these categories entirely even with a gate.

### Example of a compliant value

```text
Content references alcohol → age gated: true, with DOB collected at opt-in.
```

---

## MSG-131 — Non-GSM characters silently force Unicode encoding

> Characters outside the GSM-7 alphabet — smart quotes, ™, ®, em dashes, emoji — cut the per-segment limit from 160 to 70.

- **Rule ID:** MSG-131
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** LOW — Best practice. Worth fixing, rarely fatal on its own.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-131/

### Why this rule exists

A curly apostrophe pasted from a word processor more than doubles the cost of every message and can split a one-segment message into three, and nothing in the authoring flow warns you. The character is visually identical to the straight version, so this is almost impossible to spot by reading.

### How to fix it

Replace smart quotes with straight quotes, em dashes with hyphens, and remove ™, ® and emoji from message bodies. Retype rather than pasting from a word processor.

### Example of a compliant value

```text
Acme Coffee: you're subscribed — replace the curly apostrophe with a straight one.
```

---

## MSG-137 — No unsolicited bulk messaging

> Campaign content must not promote unsolicited bulk messaging, whatever the content of it is.

- **Rule ID:** MSG-137
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** T-Mobile, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-137/

### Why this rule exists

Spam is a category in its own right in the T-Mobile code of conduct and the CTIA principles, independent of whether the content would otherwise be allowed — a perfectly ordinary discount offer sent to people who did not ask for it is refused on the sending pattern alone. This matters because it is the one prohibition a business cannot read off its own message copy: the campaign looks fine and the defect is in where the list came from and how the traffic is shaped. It also carries runtime consequences rather than only registration ones, since carrier filters score volume and complaint rate continuously.

### How to fix it

Say in the message flow where each recipient's consent came from, in a way that names the surface and the wording they saw, and drop any part of the list you cannot trace to one. If the answer is that the list was acquired, the campaign is not registrable on that list — this is not a copy problem and rewriting the samples will not move it.

### Common mistakes

- A clean opt-in on the front of the list does not cover the back of it: reviewers ask about the whole audience, and an imported segment inside an otherwise organic list is what the finding is usually about.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio | `30007` | yes |
| Bandwidth | `4470` | yes |

### Notes

Runtime enforcement continues after registration — Bandwidth 4470 is a billable per-message spam rejection and Twilio 30007 is carrier filtering — so passing this rule at registration does not settle it for the life of the campaign.

---

## MSG-142 — The description must match the sample messages

> The campaign description must describe the messages the samples actually show.

- **Rule ID:** MSG-142
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, Bandwidth, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-142/

### Why this rule exists

The description is the claim and the samples are the evidence, so reviewers read them against each other first. A description promising appointment reminders beside samples full of promotions is the clearest possible signal that one of the two is untrue.

### How to fix it

Rewrite whichever is wrong so the description enumerates the message types the samples demonstrate, and the samples cover the types the description promises.

### Example of a compliant value

```text
Description mentions promotions, order updates and event invites → one sample of each.
```

---

## MSG-148 — Samples must match what the printed or in-person call to action promised

> Where consent is collected on paper, at a point of sale, by QR code or by keyword, the samples must match the programme the printed call to action described.

- **Rule ID:** MSG-148
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] <-> offline CTA artifact`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** Twilio, Aerialink
- **Applies:** Applies when consent was collected by paper form, point of sale, QR code and text-to-join keyword.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-148/

### Why this rule exists

An offline call to action is the whole of the consent record — the consumer never saw a web page, so the poster, the form or the counter card is the only thing they agreed to. When the samples describe a different programme there is nothing to fall back on, which is why reviewers compare the two directly and why the mismatch is fatal rather than fixable by adding a disclosure. It happens because the print run is long-lived: the card was designed for appointment reminders two years ago and the programme now sends offers, and nobody reprints a counter card to match a campaign registration.

### How to fix it

Read the artifact you uploaded as evidence and register the samples that match it. Where the programme has genuinely moved on, the artifact is the thing that has to change — reprint the card or the poster with the current programme described, collect consent against that, and upload the new version. Done when the content types in the samples all appear in the printed call to action.

### Example of a compliant value

```text
Poster: "Text SHELTER to 55512 for Riverside Shelter capacity updates and volunteer alerts. Msg frequency varies. Msg & data rates may apply." — samples show a capacity update and a volunteer alert, and nothing else.
```

### Common mistakes

- A QR code that has been reprinted but still points at the old landing page fails this on the destination rather than on the print, and the artifact looks correct in the upload.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen1) | `30893` | yes |

---

## MSG-149 — Samples must match the declared opt-in method

> Sample content must be consistent with how consent was collected, not only with the use case.

- **Rule ID:** MSG-149
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + consent method`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR, FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-149/

### Why this rule exists

The opt-in method sets expectations about what arrives: someone who texted a keyword for a discount code expects offers, while someone who ticked a box at checkout expects order updates. A mismatch means the consent obtained does not cover the messages sent.

### How to fix it

Align the samples with what the opt-in surface promised. Where you send more than the opt-in described, widen the disclosure rather than narrowing the samples.

### Example of a compliant value

```text
Keyword opt-in advertised as "text JOIN for offers" → samples are offers, not appointment reminders.
```

---

## MSG-152 — Transactional campaigns must contain no promotional element

> A campaign declared transactional or informational must have no coupon, offer, upsell, or promotional content in its samples.

- **Rule ID:** MSG-152
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + campaign.usecase`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, Bandwidth, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-152/

### Why this rule exists

Transactional use cases receive better throughput and lighter filtering precisely because they are not marketing. A single coupon inside an otherwise transactional set means the campaign obtained that treatment under a false description, which is why one offending sample is enough to reject.

### How to fix it

Remove promotional content from transactional samples, or move the campaign to MIXED and collect promotional-grade consent.

### Example of a compliant value

```text
ACCOUNT_NOTIFICATION: "Acme Coffee: your payment of $24.50 was received." — no offer attached.
```

### Common mistakes

- A discount code appended to an order confirmation converts the whole campaign into marketing.

---

## MSG-155 — Sweepstakes content requires the sweepstakes use case

> Where samples contain sweepstakes or contest content, the sweepstakes use case must be declared.

- **Rule ID:** MSG-155
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + campaign.usecase`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Sinch, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-155/

### Why this rule exists

Sweepstakes carry their own eligibility and official-rules requirements, and several providers subject them to special business review. Running one under a general marketing use case bypasses that review, so reviewers force the correction rather than accepting the label.

### How to fix it

Declare the sweepstakes use case and publish official rules linked from the message, or remove contest content from the campaign.

### Example of a compliant value

```text
Use case: SWEEPSTAKE, with official rules at acmecoffee.com/rules linked in the message.
```

---

## MSG-161 — SHAFT screening covers every campaign field, not a sample of them

> The SHAFT screen — sex, hate, alcohol, firearms, tobacco and profanity — must be applied to every sample message and to the campaign description and message flow, and a single hit anywhere fails the whole campaign.

- **Rule ID:** MSG-161
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** CTIA, T-Mobile, AT&T, TCR, Twilio, Bandwidth, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-161/

### Why this rule exists

Reviewers screen the submission as one document, so four clean samples and a fifth that mentions the bar tab is a rejected campaign, not a mostly-passing one. The innocent version of this is very common: the samples are written carefully and the description is written last, in a hurry, naming the product the samples were careful to avoid. Because the rejection names the campaign rather than the field, operators resubmit with the samples polished again and are refused a second time for text they never re-read.

### How to fix it

Find which letter was hit before changing anything, because the letters do not share a fix. Sex and hate have no path at any provider. Firearms has none under the strict reading. Alcohol and tobacco have a narrow one that runs through a 21+ date-of-birth age gate rather than through the message copy. The per-letter rule for the category you hit carries the actual path; this one only tells you the screen covers every field you submitted.

### Common mistakes

- Re-reading only the samples is the usual second failure — the description and the message flow are screened on the same pass and are where the product name most often survives.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Bandwidth | `4100` | no |
| Twilio (gen1) | `30883` | no |

### Notes

Deliberately HARD_STOP rather than RETRY_FIELD even though some letters are fixable: the umbrella verdict does not know which letter fired, and a blind regenerate-and-resubmit loop against a SHAFT rejection burns a campaign at Twilio, where the Gen-2 codes are not eligible for resubmission.

---

## MSG-163 — Family-friendly styling must not carry adult themes

> Content presented as suitable for a family audience must not carry adult themes, and must not depict children or characters aimed at children in a sexualised or otherwise unsuitable way.

- **Rule ID:** MSG-163
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Telnyx, Bird, T-Mobile
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-163/

### Why this rule exists

The harm is that nothing on the surface warns anyone: the message reads as a cartoon promotion, so it is forwarded, shown to a child, and only then understood. Telnyx and Bird both name this shape specifically because keyword screening is blind to it — every word in the message is clean, and the adult content lives in what the styling is pointing at. The honest version is a mascot or cartoon identity attached to an adult product, adopted because it tested well and without anyone thinking about who else receives the text.

### How to fix it

Drop the child-facing styling, the mascot and the cartoon voice, and describe the product to adults in adult terms. If the product itself is adult, note that restyling only settles this rule — the underlying content is still judged by the adult-content prohibition, which has no path on 10DLC.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Telnyx | `703` | no |
| Bird | `703` | no |

---

## MSG-164 — No underage, non-consensual or illegal sexual themes

> Campaign content must not promote underage, non-consensual or otherwise illegal sexual themes, simulated or real.

- **Rule ID:** MSG-164
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** T-Mobile, AT&T
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-164/

### Why this rule exists

This is the one band of content where carriers act on a single message and escalate outside the ordinary rejection process, because the exposure of carrying it is criminal rather than commercial. It sits apart from the general adult-content prohibition because simulation does not soften it: fiction, roleplay and "barely legal" framing are treated identically to the real thing, which is the distinction operators of legal adult businesses most often get wrong.

### How to fix it

There is no compliant framing and no age gate that reaches this content — remove it from the campaign and from every page a message links to. If the finding is a false positive on safeguarding or clinical copy, say in the description who the recipients are and what the service does, in the terms a clinician would use.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Bandwidth | `703` | no |
| Telnyx | `703` | no |
| Twilio (gen2) | `30953` | no |

### Notes

AT&T additionally bans how-to material about pedophilia or non-consensual contact. Content promoting the sexual exploitation of minors is a separate obligation (catalog MSG-166) that routes to human handling rather than to an automated verdict, and no rule in this registry decides it.

---

## MSG-170 — No content promoting, glorifying or inciting violence

> Campaign content must not promote violence, threats or physical harm.

- **Rule ID:** MSG-170
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, T-Mobile, CTIA, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-170/

### Why this rule exists

T-Mobile treats depictions and endorsements of violence as illicit content in their own right, independent of whether any protected group is targeted — so a campaign can clear the hate-speech screen and still be refused here. The consumer-protection reason is blunt: SMS is a channel with no way to warn or filter before the words are on the screen, and the recipient did not choose to see them. Businesses hit this through marketing register rather than intent, with copy about destroying the competition or killing it at the gym read literally by a screen that has no sense of humour.

### How to fix it

Remove the violent framing and describe what the business actually does. Where the copy was figurative, the fix is to say the literal thing instead: "our fastest sale of the year" rather than "prices we are murdering". If violence is genuinely the subject — an entertainment title, a game — no source publishes a carve-out for promoting it by SMS.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30954` | no |

### Notes

Twilio codes hate and violence to the same Gen-2 code, 30954, so a rejection under it does not tell you which of the two fired. The registry keeps them apart because the copy that causes each is different: MSG-SHAFT-HATE is content aimed at a group, this is content about harm.

---

## MSG-171 — Messages must not harass, intimidate or threaten the recipient

> Message content must not be designed to harass, bully or intimidate the person receiving it, and must not threaten them.

- **Rule ID:** MSG-171
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, CTIA, AT&T
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-171/

### Why this rule exists

This is hostility pointed at the individual holding the phone rather than at a group, and it is the shape complaints arrive in most often — the recipient reports the message because it frightened them, not because it offended them. Honest businesses land here through pressure copy and enforcement language: escalating reminders, "final warning", "we will be forced to take action", each of which reads as a threat on a small screen with no context around it. AT&T states it plainly — message content that deceives or threatens consumers is not permitted — and there is no volume threshold below which it is tolerated.

### How to fix it

Rewrite the copy to state the position and the recipient's options neutrally, and delete anything that predicts a consequence in order to frighten rather than to inform. A message that says what is owed, by when, and how to resolve it carries the same information without the pressure — and if the programme genuinely depends on the pressure, it is not registrable.

### Common mistakes

- Softening the wording while keeping an escalating cadence does not settle this: repetition aimed at wearing the recipient down is itself the harassment, and the samples are read as a sequence.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30954` | no |

---

## MSG-175 — Content must not invade privacy, defame, or otherwise cause harm

> Message content must not invade privacy, create a safety risk, or be unlawful, abusive, malicious, misleading, excessively violent, obscene or defamatory.

- **Rule ID:** MSG-175
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + campaign.description`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-175/

### Why this rule exists

CTIA's residual harm clause is what catches the damage nobody wrote a category for — a message that names a third party's debt, address or medical appointment to somebody else, or that asserts something ruinous about a named business. The recipient of a privacy leak is not the person harmed by it, which is why no complaint-driven check finds these and why the clause is written as a sweep. Businesses reach it innocently through personalisation: a template that renders the wrong record, or a referral message that tells the recipient why their friend needs the service.

### How to fix it

Strip any third-party detail out of the message body and address the recipient about their own relationship with you only. Where personalisation pulls in another person's data — a referrer, a dependent, a co-signer — replace it with a reference the recipient already holds, and remove any assertion about a named business you cannot document.

### Common mistakes

- A message that is accurate can still fail this: disclosing a true fact about someone who is not the recipient is the violation, not getting it wrong.

### Notes

This is CTIA MPBP §5.3.1, which is written as a catch-all covering several harms that have dedicated rules elsewhere. It is kept whole rather than split so the limbs nobody else owns — privacy invasion, safety risk and defamation — are not lost between rules; the criteria route the overlapping limbs so a single defect is reported once.

---

## MSG-177 — Content must not depict or facilitate substance abuse

> Message content must not depict, promote or be designed to facilitate the abuse of alcohol, drugs, tobacco or other controlled substances, including where the abuse is implied rather than stated.

- **Rule ID:** MSG-177
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + campaign.description`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-177/

### Why this rule exists

This is the limb of the alcohol prohibition that an age gate does not reach, and confusing the two costs operators a build cycle: gating the site stops minors seeing the offer, and does nothing about copy that sells drinking to excess as the point. AT&T and the CTIA messaging principles both extend it to non-verbal implication, so an emoji, an image or a wink carries the meaning as well as a sentence does. Bars and event promoters hit this constantly and innocently, because "bottomless", "all you can drink" and "we will not judge how many" are ordinary trade language that reads, to a screen, as encouragement to drink to harm.

### How to fix it

Remove the quantity, the challenge and the intoxication as the selling point, and price or describe the offer instead. Do not reach for the age gate here — it settles who may see an alcohol offer, not what the offer says, so building one leaves this finding exactly where it was. Done when nothing in the copy would read as encouragement if a regulator read it aloud.

### Common mistakes

- An emoji can carry the whole violation on its own: a row of beer glasses beside "Friday" is the implication the rule is written about, and deleting the words does not remove it.

### Notes

Graded BLOCKING on the strict reading. The research records the AT&T alcohol-abuse row at HIGH and the CTIA abuse-reference row at BLOCKING; the registry takes the stricter of the two and records the disagreement here rather than averaging it.

---

## MSG-179 — Alcohol content must not be aimed at people under the drinking age

> Alcohol brands, and drinks designed to resemble alcoholic ones, must not be marketed in a way that appeals to or targets people under 21.

- **Rule ID:** MSG-179
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + campaign.description`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** T-Mobile
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-179/

### Why this rule exists

An age gate is the whole basis on which alcohol messaging is permitted at all, so copy built to appeal to minors defeats the mechanism rather than failing to install it — which is why T-Mobile treats this as its own refusal rather than as an age-gating defect. Alcohol-resembling drinks are named explicitly because they slip the gate by construction: an alcohol-free brand extension in the same livery is sold to the same audience with none of the restrictions, and the brand association is the marketing. The innocent cause is a genuine 0% product line marketed on exactly the assets built for the alcoholic one.

### How to fix it

Remove the youth-facing appeal — the cartoon, the school or campus timing, the sweet-confectionery framing, the under-21 talent — and market the drink to adults. Note that the age gate is not the answer to this finding: gating the site is already required for alcohol content, and a campaign that targets minors is refused whether or not the gate exists.

### Common mistakes

- A zero-alcohol product does not escape this when it carries the parent brand's identity — the brand is what is being marketed, and it is an alcohol brand.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Bandwidth | `706` | yes |
| Twilio | `30456` | no |

---

## MSG-182 — No explosives, fireworks or pyrotechnics content

> Campaign content must not promote explosives, fireworks or pyrotechnics.

- **Rule ID:** MSG-182
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, Bandwidth, AT&T
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-182/

### Why this rule exists

Twilio files explosives under the same code as firearms and toll-free verification extends the SHAFT "F" to fireworks explicitly, which surprises seasonal retailers who reason — correctly, in their own state — that they hold every licence the law asks for. The prohibition is about the channel rather than the licence: a text is forwarded, screenshotted and read by people the seller never sold to, and carriers will not carry the promotion of something that injures thousands of people a year across a medium with no controls on who sees it.

### How to fix it

Remove the product from the campaign entirely — the age gate that works for alcohol has no equivalent here, and no provider publishes a licensed-retailer exemption. Where the programme is genuinely operational rather than promotional, say so in the description: crew scheduling, safety notices and public event information carry no product offer and are a different campaign.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30957` | no |
| Twilio | `30469` | no |

### Notes

The allowances above are the reframings that remove the product-promotion element, not documented exemptions — no source publishes a carve-out for public-display announcements. Treat them as the shape worth attempting, and expect the description to have to make the absence of a sale explicit.

---

## MSG-183 — No weapons that are not legal in all fifty states

> Campaign content must not promote weapons that are not lawful in every US state.

- **Rule ID:** MSG-183
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Bandwidth, Infobip
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-183/

### Why this rule exists

This is a legality sweep rather than a category ban, and it is the rule that catches sellers who are entirely lawful where they stand: switchblades, brass knuckles, certain knives, tasers and high-capacity magazines are ordinary retail in some states and criminal to possess in others. A campaign is one national object — the numbers reach every state — so carriers apply the most restrictive state rather than the sender's. Bandwidth and Infobip both refuse on the fifty-state test specifically, which is why a firearms-clean knife retailer still gets rejected and cannot see why.

### How to fix it

Take the state-restricted lines out of the message copy and register the campaign on the products that are lawful everywhere, or on services rather than product. The test is nationwide legality, not your own licence, so the fix is to check each item you name against the strictest state rather than to add a disclaimer or an age gate.

### Common mistakes

- Adding "where legal" to the message does not settle this — carriers apply the fifty-state test to the campaign, not to each recipient, and the disclaimer is read as an admission.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Bandwidth | `7009` | no |
| Bandwidth | `7011` | no |
| Infobip | `7009` | yes |

### Notes

The same code number resolves differently by namespace, so the remediability is recorded per provider rather than averaged: Bandwidth Proxy 7009 and 7011 are terminal, while Infobip 7009 is conditional on the product set being lawful nationwide. Kept apart from MSG-SHAFT-FIREARMS deliberately: that rule is the firearms category test, this one is a legality test that catches sellers who hold no firearms at all. A knife retailer trips this and passes that.

---

## MSG-190 — No kratom or drug-paraphernalia content

> Campaign content must not promote kratom, drug paraphernalia and smoking accessories.

- **Rule ID:** MSG-190
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, Sinch, Infobip, Plivo, Bird
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-190/

### Why this rule exists

Kratom is unscheduled federally and sold openly in most states, which is exactly why operators are blindsided: carriers screen it alongside cannabis rather than by legal status, and the paraphernalia ban reaches the pipe, the grinder and the rolling paper even where nothing controlled is being sold with them. The consumer-protection reason is the same one behind the cannabis ban — a channel with no age assurance and no way to check what the product actually contains — and the FDA import alerts on kratom are what keeps it there.

### How to fix it

Take kratom and accessory product out of the message copy and out of any page a message links to. There is no age gate or licence that opens this — a shop that sells other goods can register on those, but the campaign has to be describable without naming the restricted lines, including in the description and the message flow.

### Common mistakes

- Screening only the samples leaves the usual hit in place: the shop's name and the linked landing page are read on the same pass, and a store called anything with "smoke" or "head shop" in it is assessed on that alone.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio | `30469` | no |
| Bandwidth | `701` | no |
| Infobip | `7011` | no |

---

## MSG-206 — No sweepstakes, raffle or contest-entry content

> Campaign content must not promote sweepstakes, raffles, prize giveaways or contest entry.

- **Rule ID:** MSG-206
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, AWS, Bandwidth, Telnyx, Sinch
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-206/

### Why this rule exists

Twilio files sweepstakes under gambling and refuses the category outright for "high abuse potential and regulatory complexity", while TCR and Sinch publish a Sweepstakes use case you can register under — so the same giveaway is a legitimate programme on one route and a dead campaign on another. That split is what makes this expensive: a marketing team runs the giveaway that worked last year, registers it as MARKETING, and loses the campaign rather than being told to change one dropdown. Prize mechanics also carry real consumer harm on SMS, because a giveaway is the cheapest way ever invented to buy a phone number from someone who was not thinking about what they were joining.

### How to fix it

Check whether your route publishes a Sweepstakes use case before you do anything else, because that decides whether this is a dropdown change or the end of the campaign. Where it exists, register under it and link the official rules from the message. Where it does not, replace the chance-based mechanic with a certain one — every subscriber gets the discount — and remove the draw from the samples, the description and the opt-in copy.

### Common mistakes

- Moving the draw out of the samples but leaving "enter to win" in the opt-in call to action does not settle it: the incentivised-opt-in limb is judged on the message flow, and that is where the offer usually lives.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30945` | no |
| Twilio | `30462` | no |

### Notes

Genuine authority divergence rather than a strictness difference: Twilio 30945 and toll-free 30462 refuse the category, while TCR and Sinch (CR1105, CR2009, CR3009) provide a Sweepstakes use case to register it under. Kept BLOCKING on the strict reading, with the use-case route named in the remediation so a user on a permissive route is not told to abandon a legitimate programme.

---

## MSG-209 — A charity programme may not run games of chance or recurring donations

> A campaign registered under the CHARITY use case must not solicit lottery, sweepstakes or raffle entries, and must not enrol donors in recurring donations.

- **Rule ID:** MSG-209
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + campaign.description`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** T-Mobile, CTIA
- **Applies:** Applies when the use case is CHARITY.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-209/

### Why this rule exists

The charity use case buys favourable treatment — higher throughput, a lighter consent standard than marketing — on the basis that the traffic is mission communication to supporters. Games of chance and recurring billing are the two things that turn it into a payment funnel, and both carry the harms the concession was never meant to cover: a raffle is gambling however good the cause, and a recurring donation enrolled by text is a subscription the donor cannot see, cancel or reconcile. Charities are caught out by this constantly and in complete good faith, because the raffle at the fundraising dinner and the monthly giving programme are the two most normal things a small charity does.

### How to fix it

Take the draw and the recurring enrolment out of the text programme and keep both on the web, where the donor sees the terms and the billing schedule. The messages may link to them; they may not run them. Done when no sample asks for an entry, a ticket or a monthly commitment, and every donation ask in the campaign is for a single gift.

### Example of a compliant value

```text
Riverside Shelter: our winter beds are at capacity tonight and we need blankets. Give once at https://riversideshelter.org/give Reply STOP to opt out, HELP for help.
```

### Common mistakes

- Linking to the raffle page rather than selling tickets in the thread is the fix; describing the raffle in the message and linking to it is still soliciting entries and still fails.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio | `30462` | no |

### Notes

CTIA dropped this from the Short Code Monitoring Handbook at v1.9 while T-Mobile section 6.7 retains it, so it is a live requirement on the strictest reading rather than a historical one. Divergence recorded; strictest reading kept.

---

## MSG-210 — A political donation programme may not include gaming-related fundraising

> A campaign registered under the POLITICAL use case must not raise funds through lotteries, sweepstakes, raffles or any other game of chance.

- **Rule ID:** MSG-210
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA
- **Applies:** Applies when the use case is POLITICAL.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-210/

### Why this rule exists

Political fundraising by text already sits under the most restrictive consent and vetting regime in the framework, and attaching a prize draw to it compounds two separate exposures: gambling regulation, which is state by state, and campaign-finance law, which requires every contribution to be attributable to a qualified individual giving their own money. A raffle ticket is not a contribution in that sense, so the mechanic breaks the record-keeping the programme is required to keep. Committees reach it because "enter to win dinner with the candidate" is a standard grassroots tactic on every other channel.

### How to fix it

Remove the draw from the text programme and ask for the contribution directly. Where the prize event genuinely exists, describe it as an event with an entry price handled on the web, not as a chance the message sells. Done when every fundraising sample asks for a contribution and nothing in the campaign offers a chance to win.

### Example of a compliant value

```text
Riverside Shelter Action Fund: we are $4,000 short of our filing deadline. Chip in at https://riversideshelter.org/contribute Reply STOP to opt out, HELP for help.
```

### Notes

CTIA states the prohibition for political donation programmes specifically. MSG-209 is the same gaming ban for charities and adds the recurring-donation limb, which is not part of this one — the two are kept apart because they are gated on different use cases and do not say the same thing.

---

## MSG-214 — No student-loan programme content

> Campaign content must not promote student-loan refinancing, consolidation or forgiveness programmes.

- **Rule ID:** MSG-214
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, AT&T, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-214/

### Why this rule exists

Student-loan messaging is refused as a category because the fraud around it is industrial: forgiveness and consolidation offers by text are the delivery mechanism for advance-fee scams that charge borrowers for a free federal process. Carriers cannot tell a legitimate refinancer from that by reading a message, so they refuse the category and let the servicers who have a genuine relationship register on it. The line that decides your campaign is whether you service the loan you are texting about.

### How to fix it

Remove the acquisition offer. If you service the loans yourself, say so in the description in those words — who originated the loan, who services it, and that every recipient is an existing borrower — and keep the samples to account events rather than offers. Done when no message would make sense to somebody who is not already your customer.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30942` | no |

---

## MSG-215 — Samples must not collect information to qualify a consumer for a loan

> Sample messages must not ask the recipient to supply information used to qualify, price or route a loan application.

- **Rule ID:** MSG-215
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-215/

### Why this rule exists

A text asking for the last four of a social security number or the year and mileage of a car is a loan lead-generation funnel wearing the clothes of a service message, and it is refused for two reasons at once: the lending prohibition, and the fact that no legitimate lender collects underwriting data by SMS reply. The consumer harm is direct — an SMS thread is unencrypted, sits in the handset indefinitely, and is the highest-yield place a phishing operator can imitate. Businesses that genuinely lend land here by moving a working web form into a text conversation because the completion rate is better.

### How to fix it

Nothing about the phrasing rescues this, because the objection is to collecting the data in the thread at all. Move the whole qualification step behind an authenticated page on your own domain and let the message do nothing but link to it — and if the campaign has no purpose beyond routing loan enquiries, it is not registrable whatever the messages say.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30942` | no |

---

## MSG-221 — Debt relief and credit repair stay prohibited even with first-party consent

> Debt consolidation, debt reduction and credit repair content is refused whether or not the sender collected the consent itself.

- **Rule ID:** MSG-221
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, Bird, Infobip, Sinch
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-221/

### Why this rule exists

Consent is the answer to almost everything else in this framework, so operators reasonably assume it is the answer here too — and it is the one place it is not. Carriers refuse these categories on the business model rather than on the permission, because the consumer harm they are protecting against is the service itself: the fees, the credit damage and the misrepresentation happen to people who did agree to hear from the sender. Stating it as its own rule matters because the neighbouring first-party carve-outs are real, and a user who has just read that a creditor may chase its own invoice will otherwise conclude the same reasoning rescues a debt-settlement offer.

### How to fix it

Do not answer this by strengthening the consent record — a signed opt-in, a recorded call and a double opt-in all leave the verdict where it is. The campaign is registrable only without the debt-relief and credit-repair service in it, so remove those lines from the description, the samples and the flow, and register on whatever else the business does.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30949` | no |
| Twilio (gen2) | `30950` | no |

### Notes

MSG-DEBT is the semantic screen and is what catches euphemism; this is the deterministic backstop, and it exists because the objection users actually raise is consent rather than wording. Matching on an explicit lexicon on purpose: the point is to answer the consent question before a round trip is spent on it, not to be the primary detector.

---

## MSG-226 — No forex, binary options or speculative-derivative content

> Campaign content must not promote forex, binary options, contracts for difference and other speculative derivatives.

- **Rule ID:** MSG-226
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-226/

### Why this rule exists

These instruments are the ones retail regulators warn about most loudly, and SMS is where the promotion happens because it reaches people outside any suitability check. Twilio names them separately from the general stock and crypto ban because the promotion pattern is different — signal groups, copy-trading and leverage offers rather than tips on a named security — and because binary options are outright banned to retail investors in several jurisdictions the traffic reaches.

### How to fix it

Remove the solicitation. Account servicing for people who already hold an account with a regulated entity is a separate, registrable category — frame the campaign that way, name the regulator and the registration in the description, and keep the samples to account events with no market commentary in them.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30948` | no |

### Notes

Twilio 30948 also covers unregistered-securities offerings, which the catalog holds as a separate obligation requiring external data and human review (MSG-228). No rule in this registry decides that one.

---

## MSG-227 — No promises of unusually high or guaranteed returns

> Campaign content must not promote schemes promising guaranteed, risk-free or unusually high financial returns.

- **Rule ID:** MSG-227
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-227/

### Why this rule exists

A guaranteed return is the single most reliable marker of investment fraud, which is why it is screened as its own category rather than left to the deception rules: no lawful investment can promise one, so the claim is refused on its face without anyone having to establish what the underlying product is. Honest businesses reach it through marketing habit — "guaranteed savings", "risk-free trial", a headline percentage with the conditions in the next sentence — and the screen reads the headline.

### How to fix it

Delete the guarantee and the headline number from the message copy. Where the rate is genuinely contractual — a deposit account, an insured product — say what it is and who insures it in the same sentence rather than leading with the figure. Done when no sample makes a promise about money that the business could not be held to in writing.

### Common mistakes

- Adding "terms apply" or a disclaimer link does not settle this: the screen reads the claim, and a disclaimer confirms that the headline overstated it.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30948` | no |
| Twilio (gen2) | `30962` | no |

---

## MSG-243 — No relaying one-time passcodes on behalf of other service providers

> Campaign content must not promote persistent relaying of one-time passcodes for other service providers.

- **Rule ID:** MSG-243
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Telnyx
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-243/

### Why this rule exists

A verification code is the most trusted message a consumer receives, and its trust rests entirely on it coming from the service being logged into. A sender relaying codes for other companies breaks that: the recipient cannot tell whose login is being confirmed, and the sending brand cannot be held to the consent because it has no relationship with the recipient. It is also the exact shape traffic-pumping fraud takes, which is why it is refused as a pattern rather than assessed message by message.

### How to fix it

Register each business that owns the login under its own brand and campaign so the codes go out under the name the consumer is signing into. Where you are the platform, that means registering on behalf of each customer rather than pooling them under yours. Done when every sample names a service the registered brand actually operates.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Telnyx | `40322` | no |

### Notes

Telnyx 40322 is recorded as "Permanent — fix content" in one source and as remediable in another; the strict reading is kept. Telnyx is the only source that publishes this in these words, so the rule is left universal rather than provider-tagged: it is the same consent-chain and sender-identity requirement the whole framework applies, and tagging it Telnyx-only would drop a real obligation for every other route. Twilio and Bandwidth reach the same outcome through the ISV-versus-end-business rules instead.

---

## MSG-245 — No fake-prize, impersonation or advance-fee patterns

> Campaign content must not promote fake prizes, impersonated brands and advance-fee solicitations.

- **Rule ID:** MSG-245
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-245/

### Why this rule exists

These three patterns share a mechanism — manufacture a reason the recipient is owed something, then extract a payment or a credential to release it — and Twilio screens them together because they are what its fraud code was written about. They are separated from general deception because they are recognisable by shape rather than by verification: nobody has to establish what the business really does to know that a prize nobody entered for is not real. The registration-time signal is often the brand record itself, where the details do not match anything a search would find.

### How to fix it

Remove any sender identity other than the registered brand, any prize claim with no promotion behind it, and any payment asked for before a benefit is delivered. Where you act for a named principal, say so in the description and register under a brand that matches what the recipient will see. Done when the sender name in every sample is the brand on the registration.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30959` | no |

### Notes

Twilio 30959 is "a permanent disqualification from A2P 10DLC messaging" — the rejection ends the account's route, not just the campaign, so this must never be surfaced as something to edit and resubmit.

---

## MSG-246 — No manufactured urgency

> Messages must not manufacture urgency — neither a security pretext such as an account about to be suspended, nor a commercial countdown, scarcity or deadline that is not real.

- **Rule ID:** MSG-246
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-246/

### Why this rule exists

Urgency is the mechanism every SMS scam runs on, because a person who believes they have ninety seconds does not check the sender. Carriers therefore screen for the pattern rather than for the underlying truth, which is why an honest retailer running a fake countdown that resets every night is filtered alongside the phishing traffic it resembles. Twilio names both halves — "your account will be suspended" as the security pretext, fake countdowns and false scarcity as the commercial one — and codes them to rejections that are not eligible for resubmission.

### How to fix it

Take the deadline out unless it is real and you can show when it was set. A genuine sale that ends on Sunday can say so; a countdown that restarts, a "last chance" sent monthly, or a stock figure nobody is counting cannot. Where the message concerns a real account event, describe what happened and let the recipient act in their own time rather than telling them what is about to be lost.

### Common mistakes

- Softening the wording while keeping the mechanism does not settle it — "ending soon" on a promotion that never ends is the same finding as a countdown clock.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30960` | no |
| Twilio (gen2) | `30962` | no |

### Notes

Absorbs the catalog's separate artificial-urgency row (MSG-247). The two are one judgement about the same defect: MSG-246 is the security pretext, MSG-247 the commercial one, and a rule that split them would report one message twice.

---

## MSG-249 — No fraud or scam message content

> Campaign content must not promote fraud or scam content — deception for financial or personal gain.

- **Rule ID:** MSG-249
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** T-Mobile, AT&T, Twilio, Telnyx, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-249/

### Why this rule exists

This is the category carriers act on fastest and punish hardest, because a fraudulent text costs a real person real money within minutes of delivery and the carrier is the one who delivered it. T-Mobile grades it Severity-0 Tier 1 at $2,000 per violation, which is per message rather than per campaign, and Twilio describes its Gen-2 code for it as a permanent disqualification from A2P 10DLC. Nothing else in the registry escalates that far, and nothing else attaches to the account rather than to the campaign.

### How to fix it

There is no compliant version of this and no reframing to attempt. If the finding is a false positive on genuine transactional copy, the fix is to make the message verifiable rather than to soften it: name the actual transaction, link only to your own domain, and never ask the recipient to send money or credentials by reply.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30959` | no |
| Twilio (gen1) | `30884` | no |
| Telnyx | `40322` | no |

### Notes

The financial exposure is worth stating alongside the rejection: T-Mobile prices Severity-0 Tier 1 phishing and fraud at $2,000 per violation and Tier 2 illegal content at $1,000, assessed per message rather than per campaign. Twilio 30959 is described as permanent and may trigger account-level enforcement beyond the campaign.

---

## MSG-250 — No simulated-phishing or security-testing programmes

> Campaign content must not promote simulated phishing and security-awareness test messaging.

- **Rule ID:** MSG-250
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, T-Mobile
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-250/

### Why this rule exists

A simulated phishing text is indistinguishable from a real one to every system that handles it, so it trains carrier filters on the sender, generates the same consumer complaints, and reaches the same people — including employees who left months ago and whoever now holds a recycled number. T-Mobile fines it at Tier 1, the same band as actual phishing, which surprises security teams badly because the intent is defensive and the programme was signed off internally. Intent is not a defence the network can see.

### How to fix it

Move the simulation off SMS. Run the exercise on channels you control end to end — corporate email, an internal app, a managed device — where the deception never touches the public network. Where the awareness programme itself is worth texting about, register it on honest copy: reminders, enrolment and results, with nothing designed to be mistaken for something else.

### Common mistakes

- Internal authorisation and a signed engagement letter do not change the verdict: the carrier is assessing the traffic on its network, and the employer's consent is not the recipient's.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen1) | `30884` | no |
| Twilio | `30007` | yes |

### Notes

T-Mobile prices this at Severity-0 Tier 1, $2,000 per violation — the same band as real phishing, and assessed per message.

---

## MSG-255 — No impersonating a third-party brand on the landing page or in a linked file

> Neither the landing page a message reaches nor any file it offers for download may present itself as belonging to a business other than the registered brand.

- **Rule ID:** MSG-255
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] -> landing page + linked download`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the crawled website or policy page
- **Fix type:** Fix the website — no form edit clears it
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-255/

### Why this rule exists

Impersonation moved to the landing page precisely because message text is screened and pages historically were not: the text says "your delivery", the page wears a courier's livery, and the recipient hands over card details to something they believe is the courier. CTIA extends the prohibition to linked downloads for the same reason — a PDF invoice on somebody else's letterhead does the same work as a cloned page. Legitimate senders hit this through reseller and white-label arrangements where the page genuinely carries a partner's branding and nobody thought of it as impersonation.

### How to fix it

Make the destination page identify the registered brand above the fold — name, logo and contact route — and remove any third-party branding you are not authorised to display. Where you act for a named principal, say so on the page in the form "X, an authorised agent of Y" rather than presenting as Y. Done when the page names the sender before it names anyone else.

### Common mistakes

- A footer disclaimer does not settle it: reviewers judge what the page presents itself as on arrival, and a logo at the top outweighs a line of small print at the bottom.

---

## MSG-261 — The call to action must not misdescribe the programme

> Neither the call to action nor subsequent messages may use deceptive language, or misdescribe what the programme sends, how often, or what it costs.

- **Rule ID:** MSG-261
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + CTA copy + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the crawled website or policy page
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-261/

### Why this rule exists

This is deception measured against the promise rather than against the truth: a consumer who agreed to "occasional order updates" and receives daily promotions was misled at the point of consent, whichever message you read on its own. It is the one deception rule that reaches back to the opt-in copy, which is why it catches programmes that are entirely honest about each message and dishonest about the shape of the whole. The innocent cause is almost always drift — the CTA was written for the programme as it was launched, and nobody rewrote it when marketing was added.

### How to fix it

Rewrite the call to action to describe the programme you are actually registering — every content type it sends, the real frequency, and the cost position — then check the samples against it line by line. Done when a recipient reading only the CTA would be unsurprised by every sample in the campaign.

### Example of a compliant value

```text
CTA: "Text me Acme Coffee offers, rewards updates and order notifications. Msg frequency varies (about 4/month). Msg & data rates may apply." — matching a sample set that contains all three kinds.
```

### Common mistakes

- Adding the missing content type to the CTA usually changes the consent standard as well: a programme that admits it sends promotions needs promotional-grade consent, so the CTA edit and the use case have to move together.

---

## MSG-262 — No sender whose business is buying, selling or sharing consumer information

> Campaign content must not promote the buying, selling or sharing of consumer information as a business model.

- **Rule ID:** MSG-262
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-262/

### Why this rule exists

Every consent in the framework is held by one business for one relationship, so a sender whose business is moving consumer records between parties cannot hold the consent it is relying on — the person agreed to hear from somebody else. Twilio applies this to the sender rather than to the message, and explicitly to non-profits and political committees as well, because list-swapping is how their traffic is built too. That is the surprise: an organisation can have impeccable message copy and still be refused on what it does for a living.

### How to fix it

This is settled on the business model, so the fix is not in the message copy: stop selling or sharing consumer data for other parties' marketing, and make the privacy policy say so in the standard form — mobile information is never sold, rented, traded or shared with third parties or affiliates for their own marketing. Where a vendor genuinely only delivers the messages, name it as a processor rather than as a partner. Done when the policy, the website and the description all describe one business holding one relationship.

### Common mistakes

- The website and the privacy policy are read alongside the campaign, so a permissive data-sharing clause left in a generated policy fails this even when the business does not actually sell anything.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30951` | no |
| Twilio | `30468` | no |

---

## MSG-263 — An abandoned-cart message must carry an opt-out notice

> Every abandoned-cart reminder must tell the recipient how to stop receiving them.

- **Rule ID:** MSG-263
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `cart-reminder message body`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-263/

### Why this rule exists

The cart reminder is the message most likely to feel like surveillance: it arrives because the recipient looked at something and did not buy it, and it is the one people most want to stop on the spot. CTIA singles it out for a per-message opt-out notice for that reason, rather than letting it rely on the notice in some earlier message of the programme. Retailers omit it in good faith because the reminder is short by design and every character is fighting for the click — which is exactly the pressure the rule exists to overrule.

### How to fix it

Add "Reply STOP to opt out" to the cart-reminder template itself, not only to the welcome message. Done when the reminder carries it on its own, read in isolation, with no earlier message in the thread.

### Example of a compliant value

```text
Acme Coffee: you left the Ethiopia Guji in your basket. Finish up at https://acmecoffee.com/cart Reply STOP to opt out.
```

### Notes

Universal rather than tagged, because TCR has no use case for abandoned-cart messaging — it is a shape a MARKETING or MIXED campaign takes, and no fact on the registration declares it. The condition is carried in the criteria, which open with a PASS boundary for every campaign that sends no cart reminders.

---

## MSG-264 — An abandoned-cart message must not complete the purchase in the thread

> A cart reminder must not collect payment information, accept purchase approval by keyword reply, or otherwise complete the transaction — the recipient must finish the purchase through a direct URL.

- **Rule ID:** MSG-264
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `cart-reminder message body`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** T-Mobile, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-264/

### Why this rule exists

A purchase confirmed by replying Y is a charge authorised by a single character, sent from a device somebody else may be holding, with no price, no total and no terms on screen at the moment of authorisation. T-Mobile and CTIA both refuse it, and the harm is not hypothetical: the dispute rate on keyword-confirmed purchases is what put the rule in the handbook. Merchants build it because it converts, and because the platform offering the feature does not mention that carriers refuse the campaign that uses it.

### How to fix it

Replace the keyword purchase step with a direct link to the checkout page for that basket, and take every request for card, billing or address detail out of the message body. Done when the only thing a reply can do is stop the messages, and every purchase completes on your own site with the total on screen.

### Example of a compliant value

```text
Acme Coffee: your basket is still here — 2 bags of Ethiopia Guji, $34 total. Check out at https://acmecoffee.com/cart/4471 Reply STOP to opt out.
```

### Common mistakes

- A "reply Y to confirm and we will charge your card on file" flow is exactly the prohibited pattern, and it is the one most cart platforms offer as a headline feature.

### Notes

Universal for the same reason as MSG-263: no registration fact declares a cart programme, so the condition lives in the criteria and opens with a PASS boundary.

---

## MSG-266 — A forwarded or referred message must say why the recipient received it

> A message sent because another consumer referred or forwarded it must identify the person who sent it and state why the recipient is receiving it.

- **Rule ID:** MSG-266
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `viral message body`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-266/

### Why this rule exists

A referral message reaches somebody who never opted in to anything — the consent, such as it is, belongs to their friend — so the only thing standing between it and an unsolicited commercial text is the recipient being able to see immediately that a person they know is behind it. Without the name and the reason it is indistinguishable from spam and is reported as such, which damages the sending number for every other recipient. Businesses omit the name because their referral tooling does not have it, or because the message reads better without it, and neither is a reason the carrier recognises.

### How to fix it

Put the referring person's name and the reason into the first sentence of the referral template, before the offer — a [referrer name] token and a clause saying they sent it. Done when a recipient who has never heard of your business can tell, from the first line, who thought of them and why.

### Example of a compliant value

```text
Acme Coffee: [referrer first name] sent you a free bag of our Ethiopia Guji because they thought you would like it. Claim it at https://acmecoffee.com/r/4471 Reply STOP to opt out.
```

### Common mistakes

- Naming only the business does not satisfy this — the required identification is of the consumer who sent it, and that is the part referral tooling most often cannot supply.

### Notes

Universal rather than tagged: no fact on the registration declares a referral or refer-a-friend programme, so the criteria carry the condition and open with a PASS boundary for campaigns that have none. Note the interaction with the consent rules — a referral message reaches somebody who did not opt in, and satisfying this rule does not settle whether the programme may send it at all.

---

## MSG-267 — A political donation programme must confirm intent and certify eligibility

> A message-originated political contribution must be answered with a message confirming the contributor's intent to give and carrying the eligibility certification — at least 18, own funds, not a foreign national, not a federal contractor.

- **Rule ID:** MSG-267
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `political donation MT body`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA
- **Applies:** Applies when the use case is POLITICAL.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-267/

### Why this rule exists

Campaign-finance law puts the burden of establishing that a contribution is lawful on the committee receiving it, and a text has none of the surrounding form a web donation page would carry. The reply is where the certification has to live, because it is the only place the contributor can see it before the charge completes. Committees miss it because the message-originated flow feels like a confirmation receipt rather than a legal instrument, so they write it as one — and a receipt that does not ask the contributor to affirm anything leaves the committee unable to show the contribution was lawful.

### How to fix it

Write the reply to the donation keyword so it does two things in order: restate the amount and ask the contributor to confirm they intend to give it, then set out the four eligibility statements they are certifying by confirming. Done when the reply contains a confirmation step the contributor must answer and all four certifications are legible in the same message.

### Example of a compliant value

```text
Riverside Shelter Action Fund: reply YES to confirm your $25 contribution. By replying YES you certify that you are at least 18, a US citizen or lawful permanent resident, using your own funds, and not a federal contractor. Msg & data rates may apply. Reply STOP to opt out.
```

### Common mistakes

- Putting the certification behind a link does not satisfy this — the contributor must be able to read what they are certifying in the message they are replying to.

---

## MSG-290 — Political content is refused outright on platforms that prohibit it

> A political campaign cannot be registered through an ISV whose own terms prohibit political message content, whatever the carriers allow.

- **Rule ID:** MSG-290
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.usecase + campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Wait on an external system or a required interval
- **Required by:** Klaviyo
- **Applies:** Applies when the use case is POLITICAL, and the submission target is KLAVIYO.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-290/

### Why this rule exists

Political messaging is registrable at TCR under a dedicated use case with its own vetting, so a committee that clears that vetting reasonably expects to be able to send — and then finds its platform refuses the category as a matter of its own policy. Klaviyo does exactly this. Discovering it after the vetting is complete and the election calendar is running is the expensive way to find out, and there is no appeal because nothing has gone wrong with the registration: the platform simply does not carry this business.

### How to fix it

Move the programme to a route that carries political traffic. That is a commercial decision only you can make — pick a provider whose acceptable-use policy permits political content, register the brand and campaign there, and budget for the political vetting to be redone against the new route. Nothing in the campaign record needs to change, so do not spend a cycle editing it.

### Check this yourself

**Have you confirmed in writing that the replacement platform's acceptable-use policy permits political content?**

1. Read the acceptable-use policy, then get the answer in writing from the vendor. This is a vendor term, so no error code or vetting result will warn you.
2. Budget for the political vetting to be redone against the new route.
3. Do not spend a cycle editing the campaign record — nothing in it is the problem.

*What wrong looks like:* A committee clears political vetting, expects to send, and finds its platform refuses the category as a matter of its own policy. There is no appeal, because nothing has gone wrong with the registration.

### Notes

Off-platform and provider-tagged. What the user has to do themselves: confirm the acceptable-use policy of any replacement platform in writing before rebuilding, because this is a vendor term rather than a carrier rule and no error code or vetting result will warn them. Deliberately not generalised — most routes carry political traffic, and applying Klaviyo's position as a superset would refuse legitimate campaigns everywhere else. Source: prohibited-content.md.

---

## MSG-293 — Verbal opt-in grants no relief on sample content

> Samples must carry the brand name and opt-out instructions even when consent was collected verbally rather than on a web form.

- **Rule ID:** MSG-293
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** AWS
- **Applies:** Applies when consent was collected by live verbal and IVR.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-293/

### Why this rule exists

Collecting consent by phone changes what evidence you file, and nothing about what the messages have to say — but the belief that it does is widespread, because the agent already identified the business on the call and already said the customer could stop at any time. The recipient is a different person by the time the text arrives: hours later, looking at an unknown number, with none of the call in front of them. AWS states the requirement explicitly for exactly this reason, and it is the anti-exemption that stops an offline consent method quietly suppressing the two rules every message owes.

### How to fix it

Add the registered brand name to the start of every sample and "Reply STOP to opt out" to the end, exactly as a web-opt-in campaign would. Done when a sample read cold, with no memory of the call, still says who is texting and how to stop it.

### Example of a compliant value

```text
Acme Coffee: your support ticket 4471 is now with a specialist. We will text an update within one business day. Reply STOP to opt out.
```

### Common mistakes

- Naming the brand in the verbal script does not discharge this — the script is consent evidence, the samples are message content, and reviewers check them separately.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| AWS | `SAMPLE_MESSAGE_MISMATCH` | yes |

### Notes

Deliberately overlaps XBC-010 and MSG-SAMPLES-OPTOUT, which are universal and already require both elements. It exists as its own rule because the catalog records the anti-exemption separately: an author narrowing either of those to web surfaces would silently exempt verbal campaigns, and this rule is what would go red.

---

## MSG-296 — Platform sample specifications must be met where an ISV imposes one

> Where the campaign is registered through an ISV that publishes its own sample specification, the samples must satisfy it — for HubSpot, exactly two samples, each carrying the business name, opt-out instructions including STOP, a privacy-policy link, and bracketed personalisation.

- **Rule ID:** MSG-296
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** HubSpot
- **Applies:** Applies when the submission target is HUBSPOT.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-296/

### Why this rule exists

An ISV sits between the business and TCR and applies its own acceptance rules first, so a submission that would clear every carrier requirement is still rejected at the platform without ever reaching a carrier. HubSpot publishes the strictest sample specification found anywhere — a superset of what any carrier asks — and businesses meet the carrier bar, submit, and are refused by their own tooling with no reference to a carrier rule they can look up. It is worth stating separately because the fix is cheap and the confusion is expensive: nothing is wrong with the campaign, only with the shape of it for one route.

### How to fix it

Submit exactly two samples and put all four elements in each: the business name at the front, "Reply STOP to opt out", a link to your public privacy policy, and at least one [bracketed] personalisation token. Done when both samples carry all four — HubSpot checks each sample independently rather than the set as a whole.

### Example of a compliant value

```text
sample1: "Acme Coffee: hi [first name], 20% off all espresso blends this weekend. Privacy: https://acmecoffee.com/privacy Reply STOP to opt out."
sample2: "Acme Coffee: hi [first name], order [order number] is ready for pickup. Privacy: https://acmecoffee.com/privacy Reply STOP to opt out."
```

### Common mistakes

- The privacy policy behind the link has to carry the mobile-information non-sharing statement and the rates disclosure — a link to a generic generated policy satisfies this rule and is then rejected on the policy itself.

### Notes

Provider-tagged rather than applied as a superset, and that is the whole point of the tag here: this is one vendor's contract, not a carrier requirement, so imposing it on everyone would fail compliant registrations for not doing something no carrier asks. The check returns UNCLEAR while the submission target is unknown, because "we do not know which platform you are using" is the honest answer and returning a vacuous PASS would hide the requirement from the users who owe it. Source: aws-and-resellers.md section A, HUBSPOT-REG.

---

## MSG-ADULT-DATING — No adult dating or companionship solicitation

> Campaign content must not promote adult dating, companionship, or hookup services.

- **Rule ID:** MSG-ADULT-DATING
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-adult-dating/

### Why this rule exists

Dating content marketed on sexual availability falls under the SHAFT sex prohibition and carries an unusually high complaint rate, because recipients frequently did not knowingly opt in. Mainstream relationship services are judged separately on how they present themselves rather than on the category label.

### How to fix it

Remove sexually suggestive framing and restrict messaging to non-explicit service notifications for users who opted in inside your own product. If the service is adult-oriented by nature, 10DLC is not an available channel.

---

## MSG-BAIL-BONDS — No bail bonds or related solicitation

> Campaign content must not promote bail bonds and related legal-financial solicitation.

- **Rule ID:** MSG-BAIL-BONDS
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-bail-bonds/

### Why this rule exists

Bail bond marketing reaches people at a moment of acute distress, frequently using data obtained from arrest records rather than consent. Carriers treat unsolicited outreach on that basis as a per-se harm, independent of the legality of the underlying business.

### How to fix it

This solicitation model cannot be registered. Messaging existing clients about their own case is a different category — describe it that way and remove any acquisition content.

---

## MSG-CANNABIS — No cannabis, CBD, or hemp-derived product content

> Campaign content must not promote cannabis, CBD, hemp, or related products.

- **Rule ID:** MSG-CANNABIS
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-cannabis/

### Why this rule exists

Cannabis is prohibited regardless of state legality, because where federal and state law diverge the industry applies federal law. This surprises operators in legal states more than any other rule, and Twilio states explicitly that keyword detection alone is insufficient — euphemistic framing is caught and treated the same way.

### How to fix it

Cannabis-related messaging cannot be registered on 10DLC in the US regardless of state licensing. Do not attempt to re-frame it — euphemism detection is explicit in the vetting criteria.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30940` | no |

---

## MSG-CHARITY-SOLICIT — Charitable solicitation requires the charity use case and real status

> Campaign content must not promote charitable donation solicitation outside the charity use case.

- **Rule ID:** MSG-CHARITY-SOLICIT
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-charity-solicit/

### Why this rule exists

Donation solicitation gets favourable treatment and correspondingly stricter eligibility, including verified 501(c)(3) status. Soliciting donations under a marketing use case bypasses that check and is rejected on the mismatch rather than on the content.

### How to fix it

Register under the CHARITY use case with your 501(c)(3) EIN and tax-exempt status declared on the brand, or remove the donation ask from the campaign content.

### Example of a compliant value

```text
Entity type: NON_PROFIT · Tax exempt status: 501(c)(3) · Use case: CHARITY — or drop the ask: "Riverside Shelter: our winter programme opened today. Details: https://riversideshelter.org/winter Reply STOP to opt out."
```

---

## MSG-COLLECTIONS-FIRST-PARTY — First-party collections messaging must not use third-party framing

> Campaign content must not promote debt collection presented as third-party activity.

- **Rule ID:** MSG-COLLECTIONS-FIRST-PARTY
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-collections-first-party/

### Why this rule exists

First-party collection — a business chasing its own invoice — is registrable, while third-party collection is not. Businesses routinely describe their own collections in agency language, which reads as the prohibited category and gets rejected for something they are not doing.

### How to fix it

Describe the messaging as first-party — your business, your customer, your invoice — and remove agency framing and any threatening language from the samples.

### Example of a compliant value

```text
Acme Coffee: your invoice #4471 for $240 is now 14 days overdue. Pay at https://acmecoffee.com/pay/4471 or reply HELP to reach us. Reply STOP to opt out.
```

### Notes

Retryable rather than a hard stop, because the usual defect is describing legitimate first-party activity badly.

---

## MSG-CRYPTO — No cryptocurrency or high-risk investment solicitation

> Campaign content must not promote cryptocurrency, stock alerts, or high-risk investment offers.

- **Rule ID:** MSG-CRYPTO
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-crypto/

### Why this rule exists

Investment solicitation over SMS is heavily associated with pump-and-dump and fraud, so carriers refuse the category rather than assess individual senders. A regulated institution servicing existing accounts is judged separately.

### How to fix it

Investment solicitation cannot be registered. Account servicing for existing customers of a regulated institution is a separate category — frame the campaign that way if it applies.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30947` | no |
| Twilio (gen2) | `30946` | no |

---

## MSG-DEBT — No third-party debt collection, relief, or credit repair content

> Campaign content must not promote third-party debt collection, debt relief, or credit repair services.

- **Rule ID:** MSG-DEBT
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-debt/

### Why this rule exists

Third-party debt content combines a regulated activity with a high complaint rate, and carriers refuse it as a category. First-party collection — a business contacting its own customer about its own invoice — is treated differently, which is the distinction that decides whether your campaign is registrable.

### How to fix it

Third-party debt services cannot be registered. If you are collecting your own receivables from your own customers, say so explicitly in the description — that is a different, registrable category.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30943` | no |
| Twilio (gen2) | `30949` | no |
| Twilio (gen2) | `30950` | no |

### Notes

Three Gen-2 codes, one per limb: 30943 third-party collection, 30949 debt reduction or consolidation, 30950 credit repair. All three are "not eligible for resubmission", so a rejection under any of them ends the campaign rather than starting a fix loop.

---

## MSG-DECEPTIVE — Content must not be deceptive, misleading, or impersonating

> Messages must not misrepresent the sender, imitate another brand, or make claims the business cannot support.

- **Rule ID:** MSG-DECEPTIVE
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + campaign.description`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** CTIA, T-Mobile, Twilio, TCR, FTC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-deceptive/

### Why this rule exists

Deception and impersonation are Severity-0 findings that stop all messaging on the program, and they are the categories carriers escalate fastest because they map directly onto fraud. Unlike most defects, these attract per-message violation fees rather than a rejection you can fix and resubmit.

### How to fix it

Remove any content implying an affiliation the business does not have, any urgency claim that is untrue, and any sender identity other than the registered brand.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30962` | no |

---

## MSG-DESC-QUALITY — Campaign description must explain who, what, and how they opted in

> The description must state who receives the messages, what those messages contain, and how recipients consented.

- **Rule ID:** MSG-DESC-QUALITY
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, Bandwidth, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-desc-quality/

### Why this rule exists

The description is the first thing a reviewer reads and the basis on which everything else is judged. A description that restates the use-case name gives them nothing to verify against, and is the most frequently cited reason for a campaign-description rejection.

### How to fix it

Write three things explicitly: the audience, the message content, and the opt-in source. Name the business and the website rather than describing a generic program.

### Example of a compliant value

```text
Acme Coffee sends weekly promotional offers, new product announcements, and loyalty rewards updates to customers who opted in via the checkout consent checkbox at acmecoffee.com or in person at our Mission St store. Messages include discount codes and store event invitations.
```

### Common mistakes

- "Marketing messages to our customers" restates the use case and will be rejected as too vague.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen1) | `30886` | yes |

---

## MSG-FIELD-SIMILARITY — Description, message flow, and samples must not be the same text

> The description, message flow, and sample messages must each contain distinct content rather than repeated boilerplate.

- **Rule ID:** MSG-FIELD-SIMILARITY
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.message_flow + campaign.sample[]`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** Twilio, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-field-similarity/

### Why this rule exists

These three fields answer different questions — what the campaign is, how consent is collected, and what gets sent. Pasting the same paragraph into all three leaves two of those questions unanswered and is explicitly coded as a rejection reason.

### How to fix it

Write each field to its own purpose: the description explains the program, the message flow explains consent collection, and the samples show real messages.

### Example of a compliant value

```text
Description: what the program sends and to whom. Message flow: "Customers opt in at acmecoffee.com/signup by ticking…". Samples: the actual texts.
```

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30911` | yes |

---

## MSG-FIREARMS-ADJACENT — No firearms-adjacent product marketing

> Campaign content must not promote firearms accessories, ammunition, or related product marketing.

- **Rule ID:** MSG-FIREARMS-ADJACENT
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-firearms-adjacent/

### Why this rule exists

The firearms prohibition covers ammunition, magazines, and components as well as complete weapons, which surprises retailers who reason that accessories are not weapons. Ranges, training and membership services remain registrable where they sell no product.

### How to fix it

Remove product content of every kind, including accessories and ammunition. Service messaging for ranges, training and memberships remains registrable.

---

## MSG-GAMBLING — No gambling or sportsbook content

> Campaign content must not promote gambling, casino, sportsbook, or lottery content.

- **Rule ID:** MSG-GAMBLING
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-gambling/

### Why this rule exists

Gambling is banned by some providers and gated behind a special use case by others. The consumer-harm rationale is the same one behind age gating, and the divergence between providers means the safe default is to treat it as blocking.

### How to fix it

Confirm whether your provider offers a gambling or sweepstakes use case before proceeding; several refuse the category outright. Where a sweepstakes use case exists, register under it rather than under marketing.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30944` | no |

---

## MSG-HIGH-RISK-FINANCIAL — No payday, short-term, or high-interest lending content

> Campaign content must not promote payday loans, short-term lending, or high-interest credit offers.

- **Rule ID:** MSG-HIGH-RISK-FINANCIAL
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-high-risk-financial/

### Why this rule exists

High-risk lending is the category most associated with consumer harm complaints on SMS, and it is coded separately from the ordinary direct-lending attribute. The distinction matters: declaring direct lending is a fixable attribute problem, while promoting payday-style credit is a business-model rejection with no remedy.

### How to fix it

This business model cannot be registered. Regulated lenders sending servicing messages to existing customers are a different category — if that is you, remove the acquisition-style offers and set the direct-lending attribute instead.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30942` | no |

---

## MSG-ILLEGAL — No content promoting illegal activity

> Campaign content must not promote illegal goods, services, or activity.

- **Rule ID:** MSG-ILLEGAL
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-illegal/

### Why this rule exists

Promotion of illegal activity is a Severity-0 finding carrying "cease all messaging" rather than a rejection, and it is assessed against federal law even where a state permits the activity. The scope includes the landing page and any downloadable artifact, not only the message body.

### How to fix it

This cannot be registered on any channel. Where the activity is state-legal but federally prohibited, federal law is the standard applied.

---

## MSG-JOB-LEADGEN — No third-party job-board or staffing lead generation

> Campaign content must not promote third-party job alerts or staffing lead generation.

- **Rule ID:** MSG-JOB-LEADGEN
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-job-leadgen/

### Why this rule exists

Job-alert messaging is a classic lead-generation shape: the consumer opted in on an aggregator and the messages come from employers or agencies they never heard of. Where the employer collected the consent directly, the same content is registrable — the distinction is who holds the relationship.

### How to fix it

Restrict messaging to candidates who opted in directly with the sending entity about that entity's own roles. Aggregated or purchased candidate lists cannot be registered.

---

## MSG-LEAD-GEN — No third-party lead generation or multi-level marketing

> Campaign content must not promote third-party lead generation, affiliate marketing, or MLM recruitment.

- **Rule ID:** MSG-LEAD-GEN
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-lead-gen/

### Why this rule exists

Lead generation depends on messaging people whose consent was collected by someone else, which is the transfer of consent the whole framework prohibits. MLM recruitment is refused for the same structural reason plus its complaint profile.

### How to fix it

This cannot be registered. If you run your own referral programme and collected the consents yourself, describe it that way and make clear no third-party list is involved.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30951` | no |
| Twilio | `30468` | no |

---

## MSG-PHARMA — No prescription drug or controlled-substance promotion

> Campaign content must not promote prescription drugs, controlled substances, or unapproved health products.

- **Rule ID:** MSG-PHARMA
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-pharma/

### Why this rule exists

Promoting prescription medication over SMS raises both regulatory and safety exposure, and carriers refuse the category. Pharmacy operations — refill reminders and pickup notices to existing patients — remain registrable, and confusing the two is the common failure.

### How to fix it

Remove promotional drug content. Reframe as operational patient messaging — refills, pickups, appointments — which is registrable under CUSTOMER_CARE or ACCOUNT_NOTIFICATION.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30941` | no |

---

## MSG-PHISHING — Content must not solicit credentials or sensitive data

> Messages must not ask recipients for passwords, full card numbers, SSNs, or account credentials.

- **Rule ID:** MSG-PHISHING
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** CTIA, T-Mobile, Twilio, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-phishing/

### Why this rule exists

Credential solicitation over SMS is indistinguishable from smishing from the carrier’s side, and it is filtered and fined accordingly. Legitimate businesses do not need it — verification belongs behind an authenticated session, not in a text reply.

### How to fix it

Remove any request for credentials or full financial identifiers. Link to an authenticated page on your own domain instead of collecting data by reply.

---

## MSG-REAL-ESTATE-WHOLESALE — No unsolicited property-acquisition or wholesaling outreach

> Campaign content must not promote real-estate wholesaling and unsolicited property-acquisition outreach.

- **Rule ID:** MSG-REAL-ESTATE-WHOLESALE
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-real-estate-wholesale/

### Why this rule exists

"We want to buy your house" texting is sent to property owners from public records with no consent whatsoever, and it is one of the highest-complaint categories on the network. Ordinary real-estate practice with consenting clients is unaffected.

### How to fix it

Messaging property owners sourced from public records cannot be registered — there is no consent to point at. Restrict to clients who opted in directly with your brokerage.

---

## MSG-SAMPLES-DISTINCT — Sample messages must be materially different from one another

> Each sample must illustrate a genuinely different message the campaign will send, not a near-duplicate of another sample.

- **Rule ID:** MSG-SAMPLES-DISTINCT
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, Bandwidth, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-samples-distinct/

### Why this rule exists

The point of multiple samples is to show a reviewer the range of what will actually be sent. Three variations on the same sentence demonstrate nothing about the rest of the program, so reviewers read near-duplicates as padding to satisfy a field count and reject the campaign as unrepresentative. Exact-duplicate detection catches only the laziest version of this; the common failure is three messages that differ by a product name.

### How to fix it

Replace near-duplicate samples with messages covering genuinely different scenarios from the same campaign — for a marketing campaign, one promotion, one product launch, one loyalty or event message rather than three discount offers.

### Example of a compliant value

```text
1. "Acme Coffee: 20% off all beans this weekend. Shop https://acmecoffee.com/sale Reply STOP to opt out, HELP for help."
2. "Acme Coffee: your rewards balance is 240 points — enough for a free drink. Reply STOP to opt out."
3. "Acme Coffee: our Mission St store opens Saturday at 8am, first 50 customers get a free pastry. Reply STOP to opt out."
```

### Common mistakes

- Changing only a discount percentage or a product name between samples is not material difference.
- Do not solve this by making one sample an opt-out confirmation — samples must show campaign content.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen1) | `30893` | yes |

---

## MSG-SAMPLES-NOT-ONLY-ADMIN — Samples must show campaign content, not only opt-out or help replies

> The sample set must include actual campaign messages, not exclusively confirmations, HELP replies, or opt-out acknowledgements.

- **Rule ID:** MSG-SAMPLES-NOT-ONLY-ADMIN
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-samples-not-only-admin/

### Why this rule exists

Administrative auto-replies are required separately and are configured in their own fields. A sample set made only of them shows a reviewer nothing about what the campaign actually sends, which is the one thing samples exist to demonstrate.

### How to fix it

Replace administrative samples with real campaign messages. Put the HELP and STOP replies in the dedicated auto-reply fields where they belong.

### Example of a compliant value

```text
Acme Coffee: your table for 4 on Fri 7pm is confirmed. Reply STOP to opt out, HELP for help.
```

---

## MSG-SAMPLES-OPTOUT — At least one sample must show opt-out language

> Sample messages must demonstrate that recipients are told how to stop receiving messages.

- **Rule ID:** MSG-SAMPLES-OPTOUT
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, CTIA, Bandwidth, Plivo, Vonage
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-samples-optout/

### Why this rule exists

Reviewers use the samples to confirm the opt-out instruction reaches consumers in the actual message body, not just in the registration paperwork. Where every sample omits it, the reasonable inference is that live traffic omits it too.

### How to fix it

Add "Reply STOP to opt out" to your samples. Include it in every promotional sample; for transactional programs at minimum the first message in a series.

### Example of a compliant value

```text
Acme Coffee: 20% off all beans this weekend. Reply STOP to opt out, HELP for help.
```

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Bandwidth | `8100` | yes |

---

## MSG-SAMPLES-REPRESENTATIVE — Sample messages must be realistic, not placeholders

> Samples must be actual messages the campaign will send, with real brand and content specifics.

- **Rule ID:** MSG-SAMPLES-REPRESENTATIVE
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, Bandwidth, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-samples-representative/

### Why this rule exists

Reviewers compare your samples against your website and use case to decide whether the program is what it claims to be. Generic filler makes that impossible, and it correlates strongly with campaigns that later send something entirely different — which is why it is treated as a signal of bad faith rather than a formatting problem.

### How to fix it

Rewrite each sample as a message you would genuinely send tomorrow, naming your real brand, real products or services, and a real destination URL on your own domain.

### Example of a compliant value

```text
Acme Coffee: your order #4471 is ready for pickup at our Mission St store until 6pm today. Reply STOP to opt out, HELP for help.
```

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen1) | `30893` | yes |

---

## MSG-SAMPLES-USECASE — Sample messages must match the declared use case

> The content of the samples must be consistent with the campaign use case selected.

- **Rule ID:** MSG-SAMPLES-USECASE
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[] + campaign.usecase`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, Bandwidth, AWS, Sinch
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-samples-usecase/

### Why this rule exists

The use case determines the consent standard, the throughput a carrier grants, and the filtering applied to your traffic. A campaign registered as ACCOUNT_NOTIFICATION that sends promotions is receiving treatment it did not qualify for, so the mismatch is a registration integrity problem rather than a labelling error.

### How to fix it

Either change the use case to match what you actually send, or replace the off-pattern samples. If you genuinely send both promotional and transactional content, select MIXED and show both — but note that MIXED requires promotional-grade consent.

### Example of a compliant value

```text
For ACCOUNT_NOTIFICATION: "Acme Coffee: your payment of $24.50 was received. View receipt: https://acmecoffee.com/r/4471 Reply STOP to opt out."
```

### Common mistakes

- A single promotional sample inside an otherwise transactional set is enough to trigger this — Bandwidth codes it separately as 8200.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen1) | `30893` | yes |
| Bandwidth | `8200` | yes |

---

## MSG-SEO-SPAM — No unsolicited agency or SEO service pitching

> Campaign content must not promote unsolicited SEO, web design, or marketing agency solicitation.

- **Rule ID:** MSG-SEO-SPAM
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-seo-spam/

### Why this rule exists

Cold agency pitching to businesses scraped from directories is unsolicited commercial messaging with no consent behind it, and it is one of the most frequently reported patterns on the network. Messaging clients who engaged you is entirely different.

### How to fix it

Cold B2B prospecting by SMS cannot be registered — the recipients never consented. Restrict messaging to clients who opted in with you directly.

---

## MSG-SHAFT-ALCOHOL — Alcohol content requires robust age gating

> Campaign content must not promote alcohol sales or promotion.

- **Rule ID:** MSG-SHAFT-ALCOHOL
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the website — no form edit clears it
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-shaft-alcohol/

### Why this rule exists

The A in SHAFT, and the letter that genuinely has a path. Alcohol sits in a contested band: Bandwidth, Bird and Telnyx accept it behind a date-of-birth age gate, Twilio kills the rejected campaign but takes a new one once the gate exists. Because the strictest authority treats the submitted campaign as terminal we surface it as blocking, but the fix is real, and telling an operator otherwise costs them a legitimate programme.

### How to fix it

Build a 21+ age gate that collects a full date of birth — day, month and year typed in, not a yes/no prompt and not a tick-box — on the opt-in flow and on every website a message links to, then set the age-gated attribute on the campaign. Done when a visitor who enters an under-21 date is refused and cannot proceed by going back. Expect to file a NEW campaign rather than edit this one: Twilio treats the rejected campaign as spent even though it advises building exactly this gate.

### Common mistakes

- A gate that only appears on the home page does not settle it — the requirement runs to every linked destination, and reviewers test the deep link from the sample message rather than the site root.
- Age gating answers who may see the offer and nothing about what the offer says: copy that sells drinking to excess is judged separately by MSG-177 and the gate does not touch it.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30955` | no |
| Twilio (gen2) | `30956` | no |
| Bandwidth | `706` | yes |
| Telnyx | `706` | yes |
| Bird | `706` | yes |

### Notes

Providers genuinely diverge, and the divergence is in the remediability rather than the prohibition: Twilio 30955/30956 are non-resubmittable for the rejected campaign while Bandwidth DCA2 706, Telnyx 706 and Bird 706 all accept a resubmission once a DOB gate exists, and Twilio toll-free 30456 is conditional on 21+ with full date-of-birth collection. Strictest reading kept for the verdict, the workable path kept in the remediation.

---

## MSG-SHAFT-FIREARMS — No firearms sales or promotion

> Campaign content must not promote firearms, ammunition, or weapon parts.

- **Rule ID:** MSG-SHAFT-FIREARMS
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-shaft-firearms/

### Why this rule exists

The F in SHAFT, and the letter where the published guidance most tempts you into the wrong fix. T-Mobile, Verizon, Bandwidth and Bird all treat firearms as age-gateable, so a dealer reads the codes, builds the gate, and is then refused anyway by Twilio and AWS, which ban the category outright with no path. Under the strict-superset rule the ban is what the registry applies, which means the age gate is wasted work here even though it is the correct answer one letter over.

### How to fix it

Do not build an age gate for this: unlike alcohol, gating does not open a path at the strictest providers and Twilio publishes no conditional route on short code, toll-free or long code. Remove product content of every kind — complete firearms, ammunition, magazines and components — and register on services instead: range bookings, training and safety courses, membership renewals and event logistics are registrable when nothing is offered for sale. Done when no message, no description sentence and no linked page names a product with a price.

### Common mistakes

- Accessories are inside the category, not outside it — optics, magazines and ammunition are refused on the same code as the weapon, which is what catches retailers who moved their copy to "gear" and resubmitted.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30957` | no |
| Twilio | `30457` | no |
| Bandwidth | `702` | yes |
| Bird | `702` | yes |

### Notes

Discharges the catalog's remediation constraint (MSG-185) as well as the content prohibition — the withheld age-gate path is the substance of that row. MSG-185 is recorded as Twilio-conditional in the catalog; the rule is left universal because the catalog's own reconciliation resolves the divergence to the ban, and a provider tag here would hand the age-gate path back to everyone who is not on Twilio.

---

## MSG-SHAFT-HATE — No hate speech

> Campaign content must not promote hate speech or content attacking a protected group.

- **Rule ID:** MSG-SHAFT-HATE
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-shaft-hate/

### Why this rule exists

The H in SHAFT. This is one of the few categories where carriers act on a single message rather than a pattern, because the reputational exposure of carrying it is immediate. It is also the letter with the most uniform treatment — every provider that publishes a code refuses without condition, so unlike alcohol or tobacco there is no provider to shop for and nothing to build.

### How to fix it

Remove the content entirely. There is no compliant framing, no age gate and no use case that carries it, and no provider offers a conditional path — so unlike the alcohol and tobacco letters there is nothing to build and nothing to confirm with your provider first.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30954` | no |
| Bandwidth | `705` | no |
| Infobip | `7012` | no |

### Notes

Twilio codes hate and violence to one Gen-2 code (30954), so a rejection under it does not say which fired. MSG-170 holds the violence side and MSG-171 the hostility aimed at the recipient.

---

## MSG-SHAFT-SEX — No adult or sexually explicit content

> Campaign content must not promote sexually explicit or adult content.

- **Rule ID:** MSG-SHAFT-SEX
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-shaft-sex/

### Why this rule exists

The S in SHAFT, and the one letter with no path at all. Carriers treat adult content as unsuitable for a channel with no age verification at the transport layer, and Twilio codes it as not eligible for resubmission. Operators arrive here expecting the alcohol treatment — build an age gate, come back — and that expectation is the expensive part: acting on it burns a campaign that cannot be recovered, on top of the build.

### How to fix it

Do not build an age gate for this — it is not the fix, and no amount of verification makes adult content registrable on 10DLC under any use case. The only thing that clears the finding is that the content is not adult: if the campaign is a clinical or sexual-health service being read as adult, say who the recipients are and what the service does in the terms a clinician would use. Otherwise adult programmes need a different channel and a different carrier relationship entirely.

### Common mistakes

- Bandwidth's Proxy path and Infobip both publish a conditional age-gate code for sexual content, which reads as a route and is not one under the strict reading — spending a build cycle on it costs you the campaign at Twilio and gains nothing anywhere else.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30953` | no |
| Bandwidth | `703` | no |
| Telnyx | `703` | no |

### Notes

Discharges the catalog's remediation constraint (MSG-167) as well as the content prohibition: the rule exists as much to withhold the age-gate path as to detect the category. Divergence recorded — Bandwidth Proxy 7006 and Infobip 7006 are conditional on a robust age gate, while Twilio 30953, Bandwidth DCA2 703, Bird 703, Telnyx 703 and AWS all refuse outright. Canonical resolution is terminal.

---

## MSG-SHAFT-TOBACCO — No tobacco, vape, or nicotine product content

> Campaign content must not promote tobacco, vaping, or nicotine products.

- **Rule ID:** MSG-SHAFT-TOBACCO
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-shaft-tobacco/

### Why this rule exists

The T in SHAFT, and the letter that splits in two. Twilio permits tobacco on short code behind an age gate and never on long code or toll-free — which is to say never on 10DLC — while vape, e-cigarettes and e-liquid are refused on every channel including the one that carries tobacco. Retailers who sell both read the tobacco allowance and assume it covers the vape wall, and that assumption is what the rejection is usually about.

### How to fix it

Take the product out of the 10DLC campaign. The age gate that rescues alcohol reaches tobacco only on short code, which is a different registration on a different number type — and it does not reach vape, e-cigarettes, e-liquid or pods on any channel at all, so separating the vape lines out is the first thing to check. Cessation and nicotine-replacement programmes are a distinct category and stay registrable when the copy is about quitting rather than about the product.

### Common mistakes

- Splitting the vape products into a second campaign does not help — the vape ban is by channel, not by campaign, so the second campaign is refused on the same code.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen2) | `30958` | no |
| Twilio | `30458` | no |
| Bandwidth | `707` | yes |
| Telnyx | `707` | yes |

### Notes

Bandwidth ("Alcohol and Tobacco can be supported with robust age-gating and proper opt-in" on 10DLC), Telnyx 707 and Bird 707 all accept tobacco behind a date-of-birth gate, so this is a genuine divergence rather than a strictness difference. Strictest reading kept; the vape half is uniform across every source.

---

## MSG-SPAM-STYLE — Messages must not use spam-signal formatting

> Messages must avoid all-caps shouting, excessive punctuation, and obfuscated wording used to evade filters.

- **Rule ID:** MSG-SPAM-STYLE
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, T-Mobile, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-spam-style/

### Why this rule exists

Carrier filters score message shape as well as content, so these patterns reduce deliverability even on an approved campaign. Character substitution and spacing tricks are treated as deliberate filter evasion, which escalates from filtering to enforcement.

### How to fix it

Write samples in ordinary sentence case with normal punctuation, and remove any character substitution.

### Example of a compliant value

```text
Acme Coffee: 20% off all beans this weekend. Reply STOP to opt out, HELP for help.
```

### Common mistakes

- "FR€E" or "C.A.S.H" reads as deliberate filter evasion, which is worse than the word it hides.

---

## MSG-SWEEPSTAKES-DECEPTIVE — No prize or winner claims without a genuine promotion

> Campaign content must not promote prize, winner, or sweepstakes claims not backed by a real promotion.

- **Rule ID:** MSG-SWEEPSTAKES-DECEPTIVE
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-sweepstakes-deceptive/

### Why this rule exists

A "you have won" message with no underlying promotion is straightforward deception and is filtered as fraud rather than as marketing. Genuine sweepstakes are registrable under the sweepstakes use case with the required official rules.

### How to fix it

Remove prize claims unless a real promotion exists with published official rules. Where it does, register under the sweepstakes use case and link the rules from the message.

---

## MSG-TELEHEALTH-ACQUISITION — No telehealth or supplement acquisition marketing

> Campaign content must not promote telehealth acquisition marketing and unproven supplement claims.

- **Rule ID:** MSG-TELEHEALTH-ACQUISITION
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-telehealth-acquisition/

### Why this rule exists

Health-outcome marketing over SMS combines regulatory exposure with a high rate of overstated claims, and weight-loss and hormone offers in particular are screened aggressively. Clinical operations messaging to existing patients is registrable and should be framed that way.

### How to fix it

Remove acquisition and outcome-claim content. Patient operations messaging — appointments, refills, results availability — is registrable under CUSTOMER_CARE or ACCOUNT_NOTIFICATION.

---

## MSG-TIMESHARE — No timeshare or vacation-club solicitation

> Campaign content must not promote timeshare, vacation club, or holiday-ownership solicitation.

- **Rule ID:** MSG-TIMESHARE
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.description + campaign.sample[] + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** Twilio, TCR, T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-timeshare/

### Why this rule exists

Timeshare marketing has a long enforcement history for high-pressure and deceptive tactics, and carriers screen it as a category. Ordinary travel and hospitality messaging is unaffected, so the line is the ownership-sales pitch rather than the industry.

### How to fix it

Remove ownership-sales content. Reservation, itinerary and stay-service messaging to your own customers remains registrable under CUSTOMER_CARE or ACCOUNT_NOTIFICATION.

---

## MSG-URL-OWNERSHIP — Links must resolve to a domain the brand owns

> URLs in messages must point at the brand’s own domain or a dedicated branded short domain, and must identify the owner.

- **Rule ID:** MSG-URL-OWNERSHIP
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, TCR, Twilio, Bandwidth, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-url-ownership/

### Why this rule exists

Public shorteners hide the destination, so carriers cannot assess where a message leads and block them categorically. The standard is stricter than "avoid bit.ly": the shortener must be dedicated to the sender, and the destination must identify the business, because shared redirect infrastructure is what makes a link untraceable.

### How to fix it

Use full URLs on your own domain, or a short domain dedicated exclusively to your business. Confirm the destination page identifies the business by name and carries contact details.

### Example of a compliant value

```text
Shop the sale: https://acmecoffee.com/sale  —  or a dedicated short domain such as https://acme.link/sale
```

### Common mistakes

- A branded short domain on shared redirect infrastructure still fails the dedicated-IP requirement.
- The same defect is remediable under the old code and NOT resubmittable under the new one — assume the strict reading.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Twilio (gen1) | `30892` | yes |
| Twilio (gen2) | `30963` | no |

---

## MSG-VARIABLES — Template variables must use square-bracket notation

> Personalisation placeholders in samples should use [square brackets] rather than code syntax.

- **Rule ID:** MSG-VARIABLES
- **Layer:** Message content (`MESSAGE_CONTENT`)
- **Checks:** `campaign.sample[]`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/message-content/msg-variables/

### Why this rule exists

Square brackets are the convention reviewers expect, and they make clear which parts vary at send time. Raw code syntax reads as an unfinished integration and invites the reviewer to treat the sample as a placeholder rather than a real message.

### How to fix it

Convert placeholders to square-bracket notation and give them readable names describing the value.

### Example of a compliant value

```text
Acme Coffee: hi [first name], your order [order number] ships today. Reply STOP to opt out.
```

### Common mistakes

- Bracket placeholders belong in samples only — never send them in live traffic.
