# Ekas 10DLC Rule Registry — Operational

> The 139 operational rules Ekas checks during A2P 10DLC registration.

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

---
## OPS-026 — The universal opt-out keyword set must be declared

> STOP, END, CANCEL, UNSUBSCRIBE and QUIT must all appear in the declared opt-out keyword set.

- **Rule ID:** OPS-026
- **Layer:** Operational (`OPERATIONAL`)
- **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/operational/ops-026/

### Why this rule exists

This five-word set is honoured at handset and carrier level regardless of what you configure, 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

Declare at least the universal five, and preferably the full seven-word FCC per-se set including REVOKE and OPTOUT.

### Example of a compliant value

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

### Notes

Discharges catalog CMP-184 ("optoutKeywords is populated and retains STOP") together with OPS-027, which owns the empty-list case. The split is deliberate: this rule returns UNCLEAR rather than FAIL on an empty list so that a campaign with no keywords yet is reported once, by OPS-027, instead of twice.

---

## OPS-027 — Opt-out keyword handling must be declared, not assumed

> The campaign must declare an opt-out keyword set, and that set must be the one the sending platform is configured to honour.

- **Rule ID:** OPS-027
- **Layer:** Operational (`OPERATIONAL`)
- **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:** FCC, CTIA, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-027/

### Why this rule exists

We cannot observe runtime STOP handling before a campaign exists, but we can observe whether anything was declared at all. An empty or single-keyword declaration is the reliable predictor of a platform that honours only STOP, which is narrower than the law now requires.

### How to fix it

Declare the full keyword set your platform honours, then verify in the platform that each one actually triggers an opt-out. The declaration and the configuration must match.

### Example of a compliant value

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

### Notes

Registration-side twin of the runtime obligation. Verifies the declaration, never the behaviour.

---

## OPS-029 — A revocation must survive punctuation, case and surrounding words

> Opt-out keywords must be matched case-insensitively, tolerantly of punctuation, and when the keyword is surrounded by other text in the same message.

- **Rule ID:** OPS-029
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `inbound message normalisation`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC, CTIA, T-Mobile, Aerialink
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-029/

### Why this rule exists

Consumers do not send bare keywords. They send "Stop.", "STOP!!", "stop texting me" and "you have the wrong number, stop" — and an exact-match handler treats every one of those as an ordinary reply, so the messages keep arriving from someone who plainly asked them not to. The FCC treats de minimis variance as a revocation regardless of what the handler did, which means the gap between the two is not a bug in the product, it is a violation already in progress.

### How to fix it

Normalise the inbound body before matching: upper-case it, strip punctuation and whitespace, then look for any declared keyword as a whole word anywhere in the message rather than as the entire message. Done when "Stop.", "please STOP" and "wrong number, stop" all suppress the number in a test send.

### Example of a compliant value

```text
Inbound "Please stop texting me!" → normalised "PLEASE STOP TEXTING ME" → matches STOP → suppressed.
```

### Common mistakes

- Matching a keyword as a substring rather than as a whole word turns "stopwatch giveaway" into an opt-out; match on word boundaries.

### Check this yourself

**Do "Stop.", "STOP!!", "please STOP" and "wrong number, stop" each suppress your own number in a live test?**

1. Send all four variants to your own programme after launch, from a real handset.
2. Confirm each one lands in the suppression list — not just the bare keyword.
3. Check the matcher uses word boundaries, so "stopwatch giveaway" is not read as an opt-out.

*What wrong looks like:* An exact-match handler files every one of those as an ordinary reply and the messages keep arriving. The FCC treats de minimis variance as a revocation regardless, so the gap is a violation already in progress.

### Notes

Nothing at registration time can settle this — the handler is code on the sending platform. What the user has to do is test it: send those four variants to their own number after launch and confirm each one lands in the suppression list. OPS-026 and OPS-027 check the declared keyword set, which is a different question from how the set is matched.

---

## OPS-031 — A plainly-worded opt-out counts even with no keyword in it

> Revocations phrased in ordinary language — "take me off your list", "please opt me out" — must be honoured even though they contain no declared keyword.

- **Rule ID:** OPS-031
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `inbound message intent classification`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC, CTIA, T-Mobile, AT&T, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-031/

### Why this rule exists

The federal rule is that a revocation is effective if a reasonable person would understand it as one, not if it matches a word list. So a consumer who writes "I never signed up for this, please remove me" has revoked, and a keyword-only handler files the message as an ordinary reply and keeps sending. It is the most common route to a complaint that the brand genuinely did not see coming, because the operator can point at a suppression list that never received anything.

### How to fix it

Route every inbound message that did not match a keyword through an intent check — a classifier, or a human queue if the volume is small — and suppress on anything a reasonable person would read as "stop". Done when a message with no keyword in it can still remove somebody from the list without an agent deciding to be helpful.

### Example of a compliant value

```text
Inbound "hi, I never signed up for these, can you take me off?" → no keyword match → intent = revocation → suppressed, and the raw text kept on the opt-out record.
```

### Check this yourself

**Who or what reads the inbound messages that matched no keyword, and how quickly?**

1. Name the classifier or the human queue. An unread inbox is the same as no handler.
2. Test it: send "take me off your list" with no keyword in it and confirm the number is suppressed without an agent deciding to be helpful.

*What wrong looks like:* "I never signed up for this, please remove me" is filed as an ordinary reply. The operator can point at a suppression list that never received anything, and the complaint is the first anyone hears of it.

### Notes

Undecidable before traffic exists and not settleable by configuration alone. What the user has to establish is who or what reads the non-keyword inbound messages, and how fast — an unread inbox is the same as no handler. OPS-056 covers keeping the raw text, which is what later shows the message was understood.

---

## OPS-032 — A help request containing a stop-word is not an opt-out

> An inbound message whose intent is a question must not be treated as a revocation merely because it contains a stop-word.

- **Rule ID:** OPS-032
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `inbound message intent classification`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** T-Mobile
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-032/

### Why this rule exists

This is the false-positive edge of the previous rule, and it is worth its own line because over-correcting is its own harm: "I cannot get my device to stop buzzing, can you help?" is a customer asking for support, and silently unsubscribing them loses the notifications they wanted and answers nothing. Teams tune aggressively for recall after a complaint and create this second failure a month later.

### How to fix it

Where the intent check is uncertain, prefer the interpretation the consumer can correct: answer the question and ask whether they also want to stop, rather than suppressing silently. Done when a support question containing the word "stop" produces a reply rather than a silent unsubscribe.

### Example of a compliant value

```text
Inbound "how do I stop the duplicate texts, is something broken?" → question, not revocation → HELP response plus an explicit offer to unsubscribe.
```

### Check this yourself

**Does a support question containing the word "stop" produce a reply rather than a silent unsubscribe?**

1. Send "I can't get my device to stop buzzing, can you help?" to your own programme.
2. Confirm it is answered. Where the intent check is uncertain, the safe design is to act and say so — answer the question and ask whether they also want to stop.

*What wrong looks like:* A team tunes aggressively for recall after a complaint and creates the opposite failure a month later: customers silently unsubscribed from notifications they wanted, and their question unanswered.

### Notes

The judgement lives in a classifier we cannot see. What the user has to decide is which way their handler errs and whether the consumer is told — a silent suppression is invisible to everyone, so the safe design is to act and say so.

---

## OPS-033 — STOP must never come back as an error

> A consumer who sends STOP must never receive an error message in response.

- **Rule ID:** OPS-033
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `STOP response handler`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA, MMA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-033/

### Why this rule exists

An error reply tells the consumer their opt-out failed, so they try again, then complain — and the carrier sees a subscriber who asked to stop twice and got told the system was broken. It is almost always accidental: STOP arrives on a number whose auto-reply is misconfigured, or outside the hours a handler runs, and the platform returns its generic failure text instead of the confirmation.

### How to fix it

Make the opt-out path independent of everything else in the handler: suppress first, then reply with the confirmation, and never let a downstream failure produce an error to the consumer. Done when STOP is answered correctly even with the campaign paused, the API key rotated or the CRM unavailable.

### Example of a compliant value

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

### Check this yourself

**Is STOP still answered correctly with the campaign paused, the API key rotated, or the CRM unavailable?**

1. Test the failure paths, not the happy path: send STOP while the campaign is paused, and again outside business hours.
2. Confirm the handler suppresses first and replies second, so no downstream failure can produce an error to the consumer.

*What wrong looks like:* The platform returns its generic failure text. The consumer believes their opt-out failed, tries again, and complains — and the carrier sees somebody who asked to stop twice and was told the system was broken.

### Notes

Not observable from a registration. The user has to test the failure paths themselves — send STOP while the campaign is paused, and again outside business hours — because the correct response in the happy path proves nothing about the ones that matter.

---

## OPS-034 — A programme in another language still owes the English keyword

> A programme messaging in a language other than English must honour STOP in that language, and must not return an error to the English keyword.

- **Rule ID:** OPS-034
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `per-locale keyword table`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA, MMA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-034/

### Why this rule exists

A Spanish-language programme whose handler only knows English leaves its subscribers with no working opt-out at all, which is the worst version of this failure. The mirror case is just as real: handsets, carriers and habit mean somebody will send STOP even to a Spanish programme, and answering that with an error is the defect the previous rule describes.

### How to fix it

Add the local-language revocation words to the keyword table alongside the English set rather than instead of it, and keep the confirmation in the language the consumer wrote in. Done when both ALTO and STOP suppress on the same programme.

### Example of a compliant value

```text
Keyword table for a Spanish programme: STOP, ALTO, PARAR, CANCELAR, plus the standard English set.
```

### Check this yourself

**Do both ALTO and STOP suppress on the same programme?**

1. Send the local-language revocation word and the English one to the same programme.
2. Confirm adding a locale did not replace the default keyword set — that is how most platforms model it.
3. Check the confirmation comes back in the language the consumer wrote in.

*What wrong looks like:* A Spanish-language programme whose handler only knows English leaves its subscribers with no working opt-out at all — and a subscriber who sends the English keyword out of habit gets an error.

### Notes

Only the sending platform holds the keyword table. What the user has to confirm is that adding a locale did not replace the default set, which is how most platforms model it.

---

## OPS-035 — The mandatory keywords must work over MMS too

> STOP, HELP and the rest of the mandatory keywords must be processed identically whether they arrive as SMS or MMS.

- **Rule ID:** OPS-035
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `inbound handler, per protocol`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA
- **Applies:** Applies when `mmsEnabled` is true.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-035/

### Why this rule exists

A consumer replying to a picture message often replies as MMS without knowing it, and many platforms route the two protocols through different inbound handlers — one of which was built for keywords and one of which was built for media. The opt-out then works or does not depending on what the consumer was replying to, which is invisible to everybody until the complaint.

### How to fix it

Point both inbound paths at the same keyword handler rather than duplicating the logic, and test an opt-out sent as a reply to an MMS. Done when the same reply suppresses whether or not it carries an attachment.

### Example of a compliant value

```text
Reply STOP to an MMS promotion → same handler, same suppression, same confirmation as an SMS reply.
```

### Check this yourself

**Does replying STOP to one of your own MMS sends suppress the number?**

1. Send yourself an MMS from the programme and reply STOP to it.
2. Confirm the same reply works with and without an attachment — many platforms route SMS and MMS through different inbound handlers.

*What wrong looks like:* The opt-out works or does not depending on what the consumer was replying to. That is invisible to everybody until the complaint.

### Notes

Two code paths, neither of them visible here. The user has to send the test themselves: reply STOP to one of their own MMS sends and confirm the number is suppressed.

---

## OPS-037 — On a shared address, STOP must stop everything

> Where several programmes share one application address, STOP must terminate every one of the consumer's active programmes on it, and any keyword menu must offer a STOP ALL option.

- **Rule ID:** OPS-037
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `subscription registry keyed by number and application address`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-037/

### Why this rule exists

From the consumer's side there is one number sending them things, and stopping it means stopping it. A registry keyed per programme instead honours the opt-out for whichever one they last received and leaves the others running, so the messages keep coming from the same number they just unsubscribed from — which reads as deliberate evasion even when it is a data model.

### How to fix it

Key suppression on the pair of consumer number and application address, not on the programme, so one STOP clears every subscription on that address. Where a menu offers per-programme choices, put STOP ALL in it. Done when a subscriber to two programmes on one short code receives nothing after a single STOP.

### Example of a compliant value

```text
Keyword menu: "Reply 1 to stop offers, 2 to stop order updates, or STOP ALL to stop everything."
```

### Check this yourself

**Does this application address carry more than one programme — and if so, does one STOP clear all of them?**

1. List the programmes sending from the address.
2. Ask your platform how suppression is scoped. Per programme is the common default and it is the wrong one.
3. Test it: subscribe to two programmes on the address, send one STOP, and confirm neither sends again.

*What wrong looks like:* The messages keep coming from the same number the consumer just unsubscribed from. It reads as deliberate evasion even when it is only a data model.

### Notes

Applies to shared short codes and multi-programme addresses, which no registration field identifies. What the user has to establish is whether their address carries more than one programme, and if so, how their platform scopes suppression — per programme is the common default and it is the wrong one.

---

## OPS-038 — Opt-out must not be reduced to one prescribed method

> Published opt-out instructions must not designate an exclusive revocation method — a consumer may use any reasonable channel.

- **Rule ID:** OPS-038
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + SMS terms + privacy policy`
- **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:** FCC, CTIA, T-Mobile, AT&T
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-038/

### Why this rule exists

The FCC rule is that a revocation counts however it reasonably arrives: a reply, a phone call, an email to an address the brand publishes. Copy saying "the only way to unsubscribe is to reply STOP" is not just narrower than the law, it is the sentence a plaintiff quotes — it shows the brand telling consumers their email revocation would not work, and it turns every revocation taken on another channel into an admission. Almost nobody writes it deliberately; it comes from terms boilerplate that names the mechanism the platform implements.

### How to fix it

Rewrite any "only way" wording so STOP is offered as the easiest route rather than the sole one, and name at least one non-SMS channel — the support email or phone number you already publish. Done when no sentence in the flow, the terms or the policy tells a consumer that a revocation sent another way will not be honoured.

### Example of a compliant value

```text
Reply STOP to any message to unsubscribe. You can also opt out by emailing support@acmecoffee.com or calling 415-555-0134, and we honour requests received any of these ways.
```

### Common mistakes

- Adding the extra channels to the terms while the HELP reply still says STOP is the only method leaves the exclusive sentence in the one place a consumer actually reads.

### Notes

Registration-side twin. Whether a revocation sent by email is honoured is runtime conduct we cannot observe; whether the brand has told consumers it will not be is in the submitted text, and it is the half a reviewer reads too.

---

## OPS-039 — A revocation on any channel must reach the SMS suppression list

> Revocations captured by an IVR key-press, a live agent, a designated website or number, an email or a voicemail must all be written into the same suppression list as a texted STOP.

- **Rule ID:** OPS-039
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `suppression list ingestion across channels`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-039/

### Why this rule exists

The consumer does not know your systems are separate. They tell the agent on the phone, or reply to the marketing email, and consider it done — and the FCC agrees with them: a revocation received at any address or number the brand holds out is presumed effective. What actually happens is that the CRM records a preference nobody syncs, the shared inbox is read by a team with no access to the messaging platform, and the texts continue for weeks.

### How to fix it

Give every intake channel one write path into the suppression list — an API call, a shared field the messaging platform reads, or a queue somebody works daily — and record the channel on each record. Done when a revocation left on voicemail suppresses the number without anyone re-keying it.

### Example of a compliant value

```text
Agent marks "SMS opt-out" in the CRM → nightly job (or webhook) writes the number to the messaging platform suppression list with channel=phone.
```

### Common mistakes

- A one-way sync from the messaging platform into the CRM is the common build and it is backwards — the revocations that need moving are the ones that arrive outside the messaging platform.

### Check this yourself

**Can you name every place a customer could say stop — agents, shop staff, the support inbox, social messages, voicemail — and show that each one reaches the suppression list?**

1. List the intake channels, then trace one revocation through each to the list.
2. Check the direction of any existing CRM sync: the common build is one-way out of the messaging platform, which is backwards.
3. Test the hardest one — leave a revocation on voicemail and see whether the number is suppressed without anyone re-keying it.

*What wrong looks like:* The CRM records a preference nobody syncs, the shared inbox is read by a team with no access to the messaging platform, and the texts continue for weeks. The consumer considered it done, and so does the FCC.

### Notes

Absorbs OPS-040 and OPS-041, which name the designated-channel and email or voicemail cases of the same routing duty. Nothing here is visible at registration. The user has to list every place a customer could plausibly say stop — agents, shop staff, the support inbox, social messages — and show that each one reaches the list. OPS-038 is the registration-side twin: the published instructions must not name one exclusive method.

---

## OPS-042 — Somebody has to own revocations that arrive in conversation

> A documented process must exist for capturing revocations conveyed to customer-service agents, in-store staff or social messages.

- **Rule ID:** OPS-042
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `written revocation-intake procedure`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Human check — only someone holding the document can settle it
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-042/

### Why this rule exists

The channels with no technical integration are the ones that fail quietly, because the revocation reaches a person who is not thinking about the messaging programme and has nowhere obvious to put it. A written procedure is what turns that from individual helpfulness into something the brand can show it does — and showing it is the point, since these are precisely the revocations a complainant will say they made.

### How to fix it

Write down, in the place staff actually look, what to do when somebody asks to stop receiving texts: which field to set or which address to forward to, and by when. Train it once and keep the training record. Done when a new starter can find the answer without asking.

### Example of a compliant value

```text
Support runbook: "If a customer asks to stop texts, set SMS Opt-Out on their account before ending the contact. Do not promise a timescale — it takes effect the same day."
```

### Check this yourself

**Could a new starter find out what to do when a customer asks them to stop the texts, without asking anyone?**

1. Write it down where staff actually look: which field to set or which address to forward to, and by when.
2. Train it once and keep the training record — the same filing cabinet as the internal do-not-call training record.
3. Test the question on someone who joined recently.

*What wrong looks like:* The revocation reaches a person who is not thinking about the messaging programme and has nowhere obvious to put it. These are precisely the revocations a complainant will say they made.

### Notes

A procedure inside the brand, which we never see. What the user has to do is write it and keep evidence that staff were trained on it; OPS-107 covers the training record for the internal do-not-call list, which is the same filing cabinet.

---

## OPS-043 — A revocation crosses media

> A revocation sent by text also stops robocalls to that number, and a revocation given on a call also stops texts.

- **Rule ID:** OPS-043
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `suppression list scope across voice and SMS`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-043/

### Why this rule exists

The consumer revoked consent to be contacted by an automated system, and the FCC does not slice that by medium. Brands slice it anyway because the dialler and the messaging platform are different products with different suppression lists, so a customer who told the agent to stop calling then starts receiving texts — which reads as retaliation and is one of the most reliably complained-about patterns there is.

### How to fix it

Hold one suppression list across voice and messaging, or synchronise the two in both directions on the same day. Done when a STOP text removes the number from the dialler as well as from the campaign.

### Example of a compliant value

```text
One do-not-contact table, consumed by both the dialler and the messaging platform, keyed on the number.
```

### Check this yourself

**Does a STOP text remove the number from the dialler as well as from the campaign — and does a revocation given on a call stop the texts?**

1. Check whether one suppression list covers voice and messaging, or whether two are synchronised in both directions on the same day.
2. Most brands that have a sync built it to feed the dialler and not to be fed by it. Check the direction.

*What wrong looks like:* A customer tells the agent to stop calling and then starts receiving texts. It reads as retaliation and is one of the most reliably complained-about patterns there is.

### Notes

Two systems, neither visible from a registration. What the user has to check is the direction of any existing sync — most brands that have one built it to feed the dialler and not to be fed by it.

---

## OPS-044 — Suppression is brand-wide, not per number

> An opted-out consumer must be suppressed across every sending number and every campaign belonging to the brand, not only the number that received the STOP.

- **Rule ID:** OPS-044
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `suppression list scope across the brand`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-044/

### Why this rule exists

Consumers experience a brand, not a sending number. Suppressing only the number that received the STOP means the next campaign — or the next number in the pool — reaches them anyway, and from their point of view the brand ignored them and changed number to do it. That is also exactly what filter-evasion looks like from the carrier's side, so the accidental version is punished like the deliberate one.

### How to fix it

Scope the suppression list to the brand and check it before every send on every campaign and number. Done when a STOP received on one campaign prevents a send on a different one to the same number.

### Example of a compliant value

```text
Suppression keyed on (brand_id, msisdn) rather than on (campaign_id, sending_number, msisdn).
```

### Common mistakes

- A number pool makes this worse rather than better: the next send picks a different originator, so a per-number list looks like it is working right up until the consumer complains.

### Check this yourself

**Does a STOP received on one campaign prevent a send on a different campaign, or a different number, to the same person?**

1. Ask your platform how the suppression list is scoped. Per campaign is a common default.
2. Test across two campaigns on the brand, and across a number pool if you use one.
3. Compare two campaigns' recipient lists — nothing else makes this visible.

*What wrong looks like:* The next campaign, or the next number in the pool, reaches them anyway. From the consumer's side the brand ignored them and changed number to do it, which is also what filter evasion looks like from the carrier's side.

### Notes

A property of the platform's data model. What the user has to establish is how their platform scopes suppression, because per-campaign is a common default and nothing about it is visible until somebody compares two campaigns' recipient lists.

---

## OPS-045 — Sending stops on receipt, including on a political programme

> No message may be sent to a number after a valid opt-out is received, whatever the campaign type.

- **Rule ID:** OPS-045
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `send-time suppression check`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** FCC, CTIA, T-Mobile
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-045/

### Why this rule exists

This is the obligation every other opt-out rule exists to make achievable, and the way it is breached is almost never a decision: a send was already queued, a scheduled blast was built from a list exported yesterday, or the suppression check happens at list-build time rather than at send time. Political programmes get their own line in the carrier rules because operators assume the exemptions that cover consent also cover revocation. They do not.

### How to fix it

Check the suppression list at send time, not at list-build time, and re-check anything that has been queued for more than a few minutes. Purge suppressed numbers from scheduled sends when the schedule fires rather than when it is created.

### Common mistakes

- A CSV exported for a blast is a snapshot of consent at export time; every opt-out between export and send is invisible to it unless the platform re-checks.

### Check this yourself

**Where in your send pipeline does the suppression check run — at list-build time, or at send time?**

1. Trace one scheduled send from list construction to dispatch and find the check. Build time is the common answer and it is the wrong one.
2. Confirm anything queued for more than a few minutes is re-checked before it goes.
3. Political programmes are not exempt: the exemptions that cover consent do not cover revocation.

*What wrong looks like:* A blast built from yesterday's export goes out this morning to someone who opted out overnight. Nobody decided to send it, and the recipient cannot tell the difference.

### Notes

Absorbs OPS-069 and MSG-268, which restate it for political programmes where the carriers call it out specifically. Undecidable before traffic. What the user has to verify is where in their send pipeline the suppression check sits — build time is the common answer and it is the wrong one.

---

## OPS-046 — The honouring clock starts when the revocation arrives

> The time taken to honour a revocation is measured from receipt of the revocation, not from the confirmation, and must never exceed ten business days.

- **Rule ID:** OPS-046
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `suppression latency, measured from receipt`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-046/

### Why this rule exists

Ten business days is the outer federal limit, and it is not a target — anything a platform can do instantly it must do instantly. The anchor matters because the obvious instrumentation measures from the confirmation being sent, which hides any delay in recognising the revocation at all: a message that sat unread in an inbox for a week shows as zero elapsed time on that clock.

### How to fix it

Timestamp the revocation when it arrives, not when it is processed, and report the gap between that and suppression. Done when your own reporting would show a revocation that waited three days in a queue.

### Example of a compliant value

```text
Opt-out record: received_at 2026-03-04T09:12Z, suppressed_at 2026-03-04T09:12Z, channel=SMS.
```

### Check this yourself

**Would your own reporting show a revocation that sat unread in a queue for three days?**

1. Check which timestamp the platform records — many record only the suppression, which makes the obligation unmeasurable in your own data.
2. Timestamp the revocation on arrival, and report the gap between that and suppression.
3. Ten business days is the outer federal limit, not a target.

*What wrong looks like:* The instrumentation measures from the confirmation being sent, so a message that waited a week in an inbox shows as zero elapsed time.

### Notes

A measurement across two runtime events. What the user has to check is which timestamp their platform records — many record only the suppression, which makes the obligation unmeasurable in their own data. OPS-056 covers the record this depends on.

---

## OPS-047 — A state may give you less time than the federal limit

> Where the recipient's state sets a shorter cure window for ceasing text solicitations, that window applies instead of the federal maximum.

- **Rule ID:** OPS-047
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `suppression latency against the recipient state`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** state law (FL)
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-047/

### Why this rule exists

Florida requires solicitations to cease within fifteen days of a stop reply, and its statute carries a private right of action — so the state window is not a compliance detail, it is the one with a plaintiff attached. A national programme sized to the federal ten business days is inside the law almost everywhere and outside it for a subset of recipients it cannot identify without a state lookup.

### How to fix it

Suppress immediately as the standard behaviour, which clears every state window at once, and reserve any delay for cases where a system genuinely cannot act in real time. Done when the slowest suppression path is measured in minutes rather than days.

### Check this yourself

**Is your slowest suppression path measured in minutes rather than days?**

1. Measure the slowest route — usually a manual or batch channel, not the keyword handler.
2. Suppress immediately everywhere: that clears every state window at once and is much the simpler answer.
3. The alternative is a per-state window table plus the location data to use it, and the area code is not the recipient's state.

*What wrong looks like:* A national programme sized to the federal ten business days is inside the law almost everywhere and outside it in Florida, whose fifteen-day statute carries a private right of action.

### Notes

Needs the recipient's state, which is not the area code and which we do not hold. What the user has to do is either suppress immediately everywhere — much the simpler answer — or hold a per-state window table and the location data to use it. OPS-100 is the umbrella that table belongs to.

---

## OPS-050 — The opt-out confirmation is worth sending inside five minutes

> The single permitted opt-out confirmation should reach the consumer within five minutes of the revocation.

- **Rule ID:** OPS-050
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `opt-out confirmation latency`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-050/

### Why this rule exists

A prompt confirmation is what buys the presumption that the revocation was honoured, and it is also the only signal the consumer gets that anything happened. Sent late it does the opposite work: a confirmation arriving the next day reads as another unwanted message from a programme they already left, and it is a common trigger for the complaint the confirmation was meant to prevent.

### How to fix it

Send the confirmation from the same handler that performs the suppression, synchronously, rather than from a batch job. Done when the confirmation arrives while the consumer still has the conversation open.

### Example of a compliant value

```text
STOP received 09:12:03 → suppressed 09:12:03 → confirmation delivered 09:12:05.
```

### Check this yourself

**Does the opt-out confirmation arrive while the consumer still has the conversation open?**

1. Send STOP to your own programme and time the confirmation.
2. Check it is sent synchronously by the same handler that performs the suppression, not by a batch job sharing a queue with marketing.

*What wrong looks like:* A confirmation arriving the next day reads as another unwanted message from a programme they already left — and triggers the complaint it was meant to prevent.

### Notes

A latency only measurable against real receipts. What the user has to confirm is that the confirmation is not queued behind an unrelated batch — the common cause of a slow one is that it shares a sending queue with marketing.

---

## OPS-051 — Only ask which messages to stop when there is more than one kind

> A scope-clarification question may appear in the opt-out confirmation only where the consumer consented to several distinct message categories.

- **Rule ID:** OPS-051
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.optout_message + campaign.sub_use_cases`
- **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:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-051/

### Why this rule exists

Asking "which messages would you like to stop?" of somebody who receives one kind reads as an obstacle, and the FCC treats a revocation as complete unless the consumer chose to narrow it — so the question buys nothing and delays the suppression. Where a consumer genuinely consented to two or three categories it is legitimate and useful, which is why the rule is about the mismatch rather than about the question.

### How to fix it

Where the campaign sends one category of message, make the opt-out confirmation unconditional and final. Keep a scope question only where the consent covered separately-described categories, and treat no reply to it as a full revocation. Done when the confirmation matches the number of things the consumer agreed to.

### Example of a compliant value

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

### Common mistakes

- A scope question that keeps sending until the consumer answers it inverts the rule — silence is revocation of everything, not permission to continue.

---

## OPS-052 — Silence after a scope question revokes everything

> Where a scope-clarification message is sent and the consumer does not reply, the revocation must be treated as covering all robocalls and robotexts from the sender.

- **Rule ID:** OPS-052
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `scope-clarification timeout handling`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-052/

### Why this rule exists

Asking which messages to stop is permitted, but it cannot be a way of keeping somebody subscribed by default. A consumer who said stop and then ignored a follow-up question has not narrowed anything — and a system that treats no reply as "carry on with the rest" has converted a revocation into a menu the consumer never answered.

### How to fix it

Suppress everything at the moment the revocation arrives, and treat any reply to the scope question as a request to re-subscribe to a subset. Done when no reply leaves the consumer receiving nothing.

### Example of a compliant value

```text
STOP → suppress all → "You have been unsubscribed from all Acme Coffee texts. Reply ORDERS if you would still like order updates."
```

### Common mistakes

- Suppressing only after a timeout expires leaves a window in which the programme is still sending to somebody who revoked — suppress first, ask second.

### Check this yourself

**If a consumer sends STOP and never replies to your scope question, do they receive nothing?**

1. Confirm the handler suppresses everything the moment the revocation arrives, before the question is sent.
2. Treat any reply to the scope question as a request to re-subscribe to a subset, not as permission to continue.
3. Test it: send STOP, ignore the follow-up, and check nothing else arrives.

*What wrong looks like:* Suppressing only after a timeout leaves a window in which the programme is still sending to someone who revoked, and a system that reads no reply as "carry on with the rest" has converted a revocation into a menu nobody answered.

### Notes

Only reachable once a scope question has been sent, which is a design choice the registration does not record. OPS-051 is the registration-side twin: it checks that the declared confirmation only asks a scope question where the consent covered several categories.

---

## OPS-053 — A STOP answering a scope question must not be answered with another

> A STOP sent in reply to a scope-clarification message must not trigger a second clarification message.

- **Rule ID:** OPS-053
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `scope-clarification loop guard`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-053/

### Why this rule exists

The loop is the failure: a consumer replies STOP, gets asked which messages, replies STOP again, and gets asked again — each round a message to somebody who has now revoked twice. It happens because the clarification is wired to the keyword rather than to the state, and it is the version of this family that most reliably produces a screenshot in a complaint.

### How to fix it

Track whether a clarification has already been sent to this number and never send a second one; a repeat STOP gets the plain confirmation. Done when replying STOP twice produces one clarification and one confirmation, in that order, and nothing else.

### Example of a compliant value

```text
STOP → clarification. STOP again → "You have been unsubscribed and will receive no further messages."
```

### Check this yourself

**Does replying STOP twice produce one clarification and one confirmation, in that order, and nothing else?**

1. Test the double-STOP path specifically. The single-STOP path looks correct in every demonstration.
2. Confirm the clarification is wired to the consumer's state rather than to the keyword, so a second one can never be sent.

*What wrong looks like:* STOP, asked which messages, STOP again, asked again. Each round is a message to somebody who has now revoked twice, and it is the version of this family that most reliably produces a screenshot in a complaint.

### Notes

A state machine inside the handler. What the user has to test is the double-STOP path specifically, because the single-STOP path looks correct in every demonstration.

---

## OPS-054 — Revoking against an exempt message stops everything else too

> Where a consumer revokes in direct response to an exempted informational message, all further non-emergency robocalls and robotexts must stop.

- **Rule ID:** OPS-054
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `suppression scope after a revocation`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-054/

### Why this rule exists

Some informational messages need no prior consent, and operators reason from that to "there is no consent here to revoke". The FCC settled it the other way: replying stop to an exempt message is a revocation of everything non-emergency. The practical failure is a delivery-notification programme that keeps notifying after a stop, on the grounds that notifications were never opt-in.

### How to fix it

Treat a revocation as brand-wide and category-blind unless the consumer narrowed it themselves. Done when a stop sent to a shipping notification also stops the marketing programme on the same number.

### Check this yourself

**Do your transactional and exempt flows — shipping notices, alerts, system messages — consult the suppression list before sending?**

1. Trace one exempt flow end to end and find the suppression check. Many are built as system notifications that bypass it entirely.
2. Test it: reply stop to a shipping notification and confirm the marketing programme on that number also stops.

*What wrong looks like:* Operators reason that informational messages needed no consent, so there is none to revoke. The FCC settled it the other way, and a delivery-notification programme that keeps notifying after a stop is the practical failure.

### Notes

Depends on which message a revocation answered, which only exists in the traffic. What the user has to check is whether their exempt or transactional flows consult the suppression list at all — many are built as system notifications that bypass it.

---

## OPS-055 — Revoke-all across categories has a deadline

> A suppression architecture that cannot revoke across every message category for a sender must be flagged before the federal revoke-all rule takes effect on 31 January 2027.

- **Rule ID:** OPS-055
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `suppression list data model`
- **Severity:** LOW — Best practice. Worth fixing, rarely fatal on its own.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Human check — only someone holding the document can settle it
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **In force from:** 2027-01-31
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-055/

### Why this rule exists

The rule is scheduled rather than hypothetical, and the work it implies is architectural: a brand whose consent and suppression are modelled per programme cannot become category-wide with a configuration change. Naming it now is what makes it a planned migration rather than a discovery made in the month it applies.

### How to fix it

Check now whether one revocation can suppress every category a sender operates, and if it cannot, schedule the change against the January 2027 date. Done when a single revocation demonstrably clears every programme the brand runs.

### Check this yourself

**Is suppression on your platform keyed per sender or per programme — and if per programme, is the migration scheduled against 31 January 2027?**

1. Answer the one architectural question: can a single revocation clear every category this sender operates?
2. If it cannot, schedule the change now. A per-programme consent model does not become category-wide with a configuration change.

*What wrong looks like:* The rule is scheduled rather than hypothetical, and it is discovered in the month it applies — when the work it implies is architectural rather than a setting.

### Notes

A future obligation about a system we cannot inspect, carried at LOW until it takes effect and BLOCKING after. What the user has to do is answer one question about their own platform — is suppression keyed per sender or per programme — and start the migration if the answer is the second.

---

## OPS-056 — Opt-out records must keep the words the consumer actually sent

> Every opt-out transaction must be recorded with the raw inbound text, the channel it arrived on, and the normalisation that was applied to it.

- **Rule ID:** OPS-056
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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/operational/ops-056/

### Why this rule exists

The hard opt-out cases are never "STOP". They are "stop texting me", a reply on the wrong keyword, a revocation left on a voicemail — and whether each was honoured turns on what the handler did with the exact words. A record keeping only "opted out: true" cannot show that a borderline message was read correctly, and cannot show that a missed one was missed, which is the same as having no answer when a regulator asks how revocations are recognised.

### How to fix it

Store three things per revocation: the inbound text verbatim, the channel it arrived on (SMS, call, email, agent), and the keyword or intent it was matched to. Done when you can list last month's opt-outs and read what each consumer actually wrote.

### Example of a compliant value

```text
Opt-out records store: received_at, channel=SMS, raw_text="please stop texting me", matched=STOP (natural-language), phone number.
```

### Common mistakes

- Recording the normalised keyword only ("STOP") loses exactly the evidence the rule exists for — the raw text is what shows a variant was understood.

### Notes

Absorbs OPS-220, which names the channel field this record must carry. Registration-side twin: the handler behaviour itself is not observable before traffic, but whether the programme has decided to keep the evidence is.

---

## OPS-057 — Log the sends you did not make

> Every send attempt suppressed because the number was opted out must be logged.

- **Rule ID:** OPS-057
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `suppressed-send log`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Supply evidence only you hold
- **Required by:** T-Mobile
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-057/

### Why this rule exists

The suppression list proves what you intended; the suppressed-send log proves it worked. Without it there is no evidence that the check ran at all — an empty complaint file and a suppression list with a million entries are consistent with a suppression check that has been silently failing since a deploy, and an audit asks for exactly this.

### How to fix it

Log the number, the campaign and the timestamp each time a send is dropped for suppression, and retain it for the same period as the consent records. Done when you can show how many sends the list stopped last month.

### Example of a compliant value

```text
suppressed_send: msisdn +14155550134, campaign acme-marketing, at 2026-03-04T14:22Z, reason=opted_out.
```

### Check this yourself

**Can you say how many sends your suppression list stopped last month?**

1. Check whether your platform exposes suppression events at all — several drop them silently, and where that is true the evidence has to come from a pre-send check you run yourself.
2. Log the number, the campaign and the timestamp on every dropped send.
3. Retain it for the same period as the consent records.

*What wrong looks like:* An empty complaint file and a suppression list with a million entries are equally consistent with a check that has been silently failing since a deploy. Without the log there is no evidence it ever ran.

### Notes

A log inside the sending platform. What the user has to check is whether their platform exposes suppression events at all — several drop them silently, and where that is true the evidence has to come from a pre-send check they run themselves.

---

## OPS-058 — Re-read the inbound log for opt-outs the handler missed

> Inbound message logs must be reviewed on a schedule for revocations the keyword handler did not catch, and those subscriptions terminated.

- **Rule ID:** OPS-058
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `inbound log review`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-058/

### Why this rule exists

No intent classifier catches everything, so the question is not whether some revocations are missed but whether anybody ever finds out. A scheduled sweep converts a silent miss into a caught one — and finding three a month is a working programme, while finding none usually means nobody is looking rather than that the handler is perfect.

### How to fix it

Schedule a review of inbound messages that produced no keyword match, suppress anything that reads as a revocation, and record when the review ran. Done when the review has a date, an owner and a finding count each time.

### Example of a compliant value

```text
Weekly: export unmatched inbound messages, review, suppress, record "reviewed 2026-03-06, 4 revocations found".
```

### Check this yourself

**Does the review of unmatched inbound messages have a date, an owner and a finding count each time it runs?**

1. Schedule the sweep over inbound messages that produced no keyword match.
2. Suppress anything that reads as a revocation, and record when the review ran and what it found.
3. Finding three a month is a working programme. Finding none usually means nobody is looking.

*What wrong looks like:* No classifier catches everything, so the question is whether anybody ever finds out. Without the review record, a missed revocation looks like the norm rather than an exception.

### Notes

A recurring job over data we never see. What the user has to do is own the schedule and keep its output — the review record is what shows a missed revocation was an exception rather than the norm.

---

## OPS-061 — A later form fill does not undo an earlier opt-out

> A consumer who opted out must not be re-subscribed on the strength of a subsequent form submission without a fresh, separately documented opt-in.

- **Rule ID:** OPS-061
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `consent record against opt-out record`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-061/

### Why this rule exists

Somebody who unsubscribed in March and buys something in June has given you their number for the order, not permission to restart the programme they left. Systems do it automatically because the checkout writes the number to the marketing list the same way it always did, and the result is a consumer receiving messages from a programme they explicitly quit — the pattern that produces the angriest complaints.

### How to fix it

Check the suppression list before writing any new consent, and require an explicit, separately recorded opt-in — not a pre-ticked box on a checkout — before removing a number from it. Done when a previously-opted-out number stays suppressed through an ordinary purchase.

### Example of a compliant value

```text
Checkout writes consent → suppression list hit → consent stored as pending, no messages sent, and the customer is shown the opt-in box unticked.
```

### Common mistakes

- Treating the new consent as newer and therefore controlling is the intuitive data model and the wrong one; an opt-out is a standing instruction, not a timestamped preference.

### Check this yourself

**Does a previously opted-out number stay suppressed through an ordinary purchase?**

1. Check the order of operations at every signup surface: most write consent first and reconcile later, if at all.
2. Require an explicit, separately recorded opt-in — not a pre-ticked checkout box — before removing anyone from the suppression list.
3. Test it with a number that opted out months ago.

*What wrong looks like:* Someone who unsubscribed in March buys something in June and the checkout writes their number back to the marketing list. Treating the newer record as controlling is the intuitive data model and the wrong one.

### Notes

A comparison between two records that only exist after launch. What the user has to check is the order of operations at their own signup surfaces — most write consent first and reconcile later, if at all.

---

## OPS-062 — An opted-out consumer must be able to come back

> The programme must leave a published route back for a consumer who opted out and later wants the messages again.

- **Rule ID:** OPS-062
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + campaign.optin_keywords`
- **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:** T-Mobile, Bird, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-062/

### Why this rule exists

Opting out is not meant to be permanent exile, and a consumer who wants their order alerts back should not have to phone somebody. The route matters more than it sounds: where none exists, the consumer either goes without or is re-added by staff without a fresh opt-in, which converts a support request into an unconsented enrolment. Programmes lose the route by accident, when the signup page starts checking the suppression list and silently drops the resubmission.

### How to fix it

Keep the published call-to-action open to previously-opted-out numbers, and support START (or UNSTOP) where the campaign accepts keyword opt-in, so the consumer can rejoin from the handset. Say which route exists in the message flow. Done when a number that texted STOP can rejoin without an agent touching the record.

### Example of a compliant value

```text
A consumer who opted out can rejoin at any time by texting START, or by opting in again at acmecoffee.com/signup; each rejoin is recorded as a new consent.
```

### Notes

Registration-side twin: whether START is honoured is runtime behaviour. What is decidable now is whether a route back was designed at all, and whether the flow says re-enrolment is treated as fresh consent rather than as reactivating an old record.

---

## OPS-063 — Opt-out records must not be shared onward

> The published policy must not permit sharing or forwarding opt-out records to unaffiliated parties without the consumer's prior express permission.

- **Rule ID:** OPS-063
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `privacy policy + SMS terms`
- **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 crawled website or policy page
- **Fix type:** Fix the privacy policy or SMS terms
- **Required by:** FCC, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-063/

### Why this rule exists

A suppression list is a list of people who asked a specific sender to stop, and passing it on turns a refusal into a marketing asset — the consumer discovers that saying no put them on a new list. Policies allow it by accident: a general "we may share data with partners" clause written for analytics also covers the suppression file, because nobody carved it out.

### How to fix it

Add a sentence to the SMS section stating that opt-out and suppression records are used only to stop messages and are never sold, rented or shared. Done when a general sharing clause elsewhere in the policy no longer reads as covering them.

### Example of a compliant value

```text
Opt-out requests are recorded and used solely to suppress further messages. We do not sell, rent or share opt-out records with any third party.
```

### Common mistakes

- A carve-out in the SMS section does not help if a broader sharing clause earlier in the policy is unqualified — reviewers read the permissive clause as controlling.

---

## OPS-065 — A carrier opt-out is authoritative even if your list has no record

> A delivery rejection indicating the carrier holds an opt-out for the number must be treated as a suppression event in its own right.

- **Rule ID:** OPS-065
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `delivery error stream into the suppression list`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** Bandwidth, all MNOs
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-065/

### Why this rule exists

Carriers maintain their own opt-out state, and a consumer who texted STOP to a shared originator or used a handset-level block can be opted out there while your list shows them active. Retrying that number burns delivery reputation and, more importantly, means you are trying to message somebody who has revoked — your own list not knowing about it is not a defence.

### How to fix it

Write back to the suppression list on every opt-out-class delivery error rather than counting it as a failed send. Done when a carrier-held opt-out appears in your own suppression list within a day of the first rejection.

### Example of a compliant value

```text
Delivery error 21610 (opted out) → suppress the number locally, channel=carrier, and stop retrying.
```

### Check this yourself

**Does anything in your systems consume opt-out-class delivery errors and write them to the suppression list?**

1. Ask whether the platform surfaces opt-out-class errors distinctly from other delivery failures.
2. Trace where they go. The common answer is a failure metric nobody reads.
3. Done when a carrier-held opt-out appears in your own list within a day of the first rejection.

*What wrong looks like:* A consumer opted out at the carrier or blocked the number on the handset, your list shows them active, and you retry — messaging somebody who has revoked. Your list not knowing is not a defence.

### Notes

Reaches you as a delivery code after launch. What the user has to establish is whether their platform surfaces opt-out-class errors distinctly, and whether anything consumes them — the common answer is that they land in a failure metric nobody reads.

---

## OPS-066 — Watch the opt-out rate, and act at both thresholds

> The per-campaign opt-out rate must be monitored, audited above roughly 0.5% on a send, and the campaign suspended with a root-cause analysis above 4% in 24 hours.

- **Rule ID:** OPS-066
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `per-campaign opt-out rate`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** T-Mobile, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-066/

### Why this rule exists

The opt-out rate is the earliest honest signal that a list is not what it was thought to be, and it moves before complaints do. The two thresholds mean different things: the lower one says audit where these numbers came from, the higher one says stop, because a rate that high is usually a purchased list or a consent scope nobody checked, and carriers act on it whether or not you do.

### How to fix it

Report the opt-out rate per send and per rolling day, alarm at 0.5% and 4%, and write down what each alarm triggers — a consent audit at the lower, an immediate pause and root-cause analysis at the higher. Done when the numbers have owners rather than dashboards.

### Example of a compliant value

```text
Send of 40,000 → 260 opt-outs (0.65%) → consent audit on the segment before the next send.
```

### Check this yourself

**Who is paged when the opt-out rate hits 4% in 24 hours, and do they have the authority to stop a send?**

1. Report the rate per send and per rolling day, and alarm at 0.5% and 4%.
2. Write down what each alarm triggers: a consent audit at the lower, an immediate pause and root-cause analysis at the higher.
3. Name the person now — the window in which acting helps is hours.

*What wrong looks like:* A rate that high is usually a purchased list or a consent scope nobody checked, and carriers act on it whether or not you do. Dashboards without owners are how the hours pass.

### Notes

Absorbs OPS-067, the higher threshold on the same monitor. Needs live traffic. What the user has to do is decide now who is paged at 4% and what authority they have to stop a send, because the window in which acting helps is hours.

---

## OPS-068 — STOP and HELP volumes are a standing report

> STOP and HELP response volumes must be monitored per campaign as an ongoing obligation.

- **Rule ID:** OPS-068
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `per-campaign keyword response metrics`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** T-Mobile
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-068/

### Why this rule exists

Aggregate rates hide the campaign that is going wrong. A brand running six programmes sees a healthy overall opt-out rate while one of them is generating almost all of it, and the per-campaign view is what makes that visible early enough to fix. It is also what the connectivity partner is expected to hold, so being unable to produce it is itself a finding.

### How to fix it

Break STOP and HELP counts out per campaign rather than per account, and keep the series long enough to see a trend. Done when you can answer "which campaign is driving this" without an export.

### Example of a compliant value

```text
Monthly: acme-marketing 0.4% STOP / 0.1% HELP; acme-orders 0.05% STOP / 0.3% HELP.
```

### Check this yourself

**Can you answer "which campaign is driving this" without an export?**

1. Break STOP and HELP counts out per campaign rather than per account, and keep the series long enough to see a trend.
2. Confirm the platform attributes inbound keywords to a campaign at all — where several campaigns share a number, many do not.

*What wrong looks like:* A brand running six programmes sees a healthy overall opt-out rate while one programme generates almost all of it. Being unable to produce the per-campaign view is itself a finding.

### Notes

Metrics from live traffic. What the user has to confirm is that their platform attributes inbound keywords to a campaign at all — where several campaigns share a number, many do not, and the attribution has to be rebuilt from the outbound history.

---

## OPS-070 — A referral opt-out covers everything sent through the application

> In a viral or referral programme, an opt-out must be honoured across every message sent through that application, programme or software.

- **Rule ID:** OPS-070
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `suppression scope across a viral application`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-070/

### Why this rule exists

In a referral programme the messages a consumer receives are triggered by other consumers, so per-sender suppression leaves them able to be re-invited indefinitely by anyone who has their number. From the recipient's side it is the same application messaging them again after they said stop, and no amount of "a different friend sent that one" survives a complaint.

### How to fix it

Hold suppression at the application level and check it before any referral send, whoever triggered it. Done when a number that opted out cannot be re-invited by a different referrer.

### Check this yourself

**Can a number that opted out be re-invited by a different referrer?**

1. Check whether suppression is scoped to the sender or to the application. Per-sender is the natural build and it does not satisfy this.
2. Test it: opt a number out, then have a second referrer invite the same number.

*What wrong looks like:* From the recipient's side it is the same application messaging them again after they said stop, and "a different friend sent that one" does not survive a complaint.

### Notes

Applies only to referral or viral messaging, which the registration does not record. What the user has to check is whether their suppression is scoped to the sender or to the application — per-sender is the natural build and it does not satisfy this. OPS-385 covers the registration-side prohibition on paying for forwards.

---

## OPS-071 — Group messaging needs a member opt-out and anti-abuse controls

> A group-messaging programme must let any member leave at any time, carry anti-abuse controls proportionate to the distribution size, and prevent recursive group messaging.

- **Rule ID:** OPS-071
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + campaign.description`
- **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
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-071/

### Why this rule exists

In a group thread the sender is not the only person who can reach the recipient, so the ordinary opt-out is not enough — a member who leaves can be added back by anyone else in the group, and a recursive group can amplify one message into thousands. The three controls exist together because each one alone is defeated by the other two failure modes.

### How to fix it

Describe how a member leaves and stays left, what limits the size and rate of a distribution, and what stops a group creating another group. Done when the flow answers all three without the reader inferring any of them.

### Example of a compliant value

```text
Any participant can reply STOP to leave a thread and cannot be re-added without opting in again; threads are capped at 25 participants, and participants cannot create new threads through the service.
```

### Notes

Applies only to group or multi-recipient threading, which the registration has no attribute for. The condition is carried in the criteria — the judge PASSes immediately where the campaign describes ordinary one-to-one messaging — and this note records that the applicability model could not express it.

---

## OPS-072 — The programme must not evade opt-out detection

> Content engineered to defeat opt-out or content detection — deliberate misspellings, non-standard phrasing — is prohibited.

- **Rule ID:** OPS-072
- **Layer:** Operational (`OPERATIONAL`)
- **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:** Hard stop — not remediable, resubmission will not help
- **Required by:** CTIA, T-Mobile, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-072/

### Why this rule exists

Filter evasion escalates a campaign from being filtered to being enforced against, because it demonstrates intent rather than error. It is also self-defeating: a consumer whose opt-out does not register complains to the carrier instead.

### How to fix it

Remove any deliberate misspelling, character substitution, or spacing trick. Write plainly and let the content stand on its own.

---

## OPS-073 — Toll-free keyword behaviour cannot be customised, so do not promise it

> A toll-free programme must not tell consumers that STOP, UNSTOP or START will behave in any way other than the fixed carrier behaviour.

- **Rule ID:** OPS-073
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + campaign.sample[] + auto-replies`
- **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:** AWS, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-073/

### Why this rule exists

On toll-free numbers the mandatory keywords are handled by the carrier before the message ever reaches the sender, and the behaviour cannot be changed or intercepted. Copy promising something else — "reply STOP PROMOS to leave only marketing", "text UNSTOP to resume your alerts" — describes a programme that cannot exist, so the consumer's reply does something different from what they were told and the brand looks like it ignored them.

### How to fix it

Describe only the standard behaviour: STOP stops everything on that number, START resumes it, HELP returns support information. Move any per-category preference to a link or a preference centre rather than a keyword. Done when no copy promises a keyword outcome the carrier does not implement.

### Example of a compliant value

```text
Reply STOP to unsubscribe. To choose which Acme Coffee messages you get, visit acmecoffee.com/preferences.
```

### Notes

Applies to the toll-free path only; on 10DLC long codes the keyword handler is the sender's own and custom keywords are legitimate. The applicability model has no dimension for the submission path, so the condition is carried in the criteria — the judge is told to PASS immediately unless the submission is toll-free.

---

## OPS-074 — Toll-free opt-out language is appended for you, and billed

> On toll-free traffic, expect the carrier to append opt-out language to outbound messages — it is billable, cannot be removed and can only be shortened.

- **Rule ID:** OPS-074
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `outbound toll-free message bodies`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** AT&T
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-074/

### Why this rule exists

The append lands on messages that were already at the segment boundary, so a body sized to 160 characters becomes two segments and the bill doubles with no change on your side. Teams discover it as an unexplained cost increase and go looking for a fault in their own templates, because nothing in the sending API mentions it.

### How to fix it

Size toll-free message bodies leaving room for the appended text, and include your own short opt-out line so the appended version is shortened rather than added in full. Done when a representative message still fits one segment after the append.

### Example of a compliant value

```text
Body written to ~120 characters on toll-free, with "Reply STOP to end" already present.
```

### Check this yourself

**Does a representative message still fit one segment after the carrier appends its opt-out language?**

1. Measure a real delivered message on a handset, not the body you submitted — the append is only visible there and on the invoice.
2. Include your own short opt-out line so the appended version is shortened rather than added in full.
3. Size bodies leaving room for it.

*What wrong looks like:* A body sized to 160 characters becomes two segments and the bill doubles with no change on your side. Nothing in the sending API mentions it, so the search for the fault starts in your own templates.

### Notes

Applies to the toll-free path and happens in the network. What the user has to do is measure a real delivered message rather than the one they submitted — the append is only visible on the handset and on the invoice.

---

## OPS-075 — Opt-out instructions must recur, not just appear at opt-in

> A recurring programme must carry opt-out instructions at opt-in and at regular intervals thereafter — at least monthly.

- **Rule ID:** OPS-075
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `outbound message cadence`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** T-Mobile, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-075/

### Why this rule exists

Subscribers forget what they joined and how to leave, and the reply that stops the programme is only obvious while the sign-up is recent. A programme that stops repeating the instruction converts would-be unsubscribers into complainants, because reporting the message as spam becomes the easiest available action.

### How to fix it

Carry "Reply STOP to opt out" in every message where the length allows, and at minimum in one message a month. Done when no subscriber goes a calendar month without being told how to leave.

### Example of a compliant value

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

### Check this yourself

**Does any subscriber go a calendar month without being told how to leave?**

1. Audit the templates that dropped the opt-out line for length — those are the ones that go months without it, and they are usually the highest-volume ones.
2. Carry "Reply STOP to opt out" wherever the length allows, and at minimum in one message a month.

*What wrong looks like:* Subscribers forget what they joined and how to leave, so reporting the message as spam becomes the easiest available action.

### Notes

A cadence across live traffic. What the user has to check is the templates that dropped the line for length — those are the ones that go months without it, and they are usually the highest-volume ones.

---

## OPS-076 — Customer-care contact details must recur too

> Customer-care contact instructions must be promoted at opt-in and at regular intervals thereafter, at least monthly.

- **Rule ID:** OPS-076
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `outbound message cadence`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-076/

### Why this rule exists

The opt-out is not the only thing a subscriber needs to be able to find; a consumer who does not recognise a message needs a route to a person before their only remaining option is a spam report. HELP covers it on request, but a recipient who does not know HELP exists will not send it, which is why the instruction has to appear rather than wait to be asked for.

### How to fix it

Include "Reply HELP for help" alongside the opt-out line, and put the support address or number itself into at least one message a month. Done when a subscriber can reach a person without searching for the brand.

### Example of a compliant value

```text
Acme Coffee: reply HELP for help or email support@acmecoffee.com. Reply STOP to opt out.
```

### Check this yourself

**Can a subscriber reach a person without searching for the brand — in at least one message a month?**

1. Check the monthly template rather than the sample set. Samples almost always carry both lines and live traffic often does not.
2. Include "Reply HELP for help" alongside the opt-out line, and put the support address or number itself into at least one message a month.

*What wrong looks like:* A recipient who does not recognise a message and does not know HELP exists will not send it. Their only remaining option is a spam report.

### Notes

Absorbs MSG-080, which states the same cadence from the message-content side. A property of live sends. What the user has to do is check the monthly template rather than the sample set — samples almost always carry both lines and live traffic often does not.

---

## OPS-078 — HELP is answered whoever asks

> A HELP request must always produce a response, whether or not the sender is currently subscribed and whether or not the programme is a subscription.

- **Rule ID:** OPS-078
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `HELP keyword handler`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA, MMA, Aerialink
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-078/

### Why this rule exists

The people most in need of a HELP response are the ones who are not subscribers: somebody who received a message meant for a previous holder of their number, or who cannot tell what the programme is. A handler that only answers known subscribers leaves exactly those people with silence and a number they cannot identify, which converts a fixable confusion into a carrier complaint.

### How to fix it

Answer HELP from the number that received it, without looking the sender up first. Done when HELP sent from a number that never subscribed still returns the brand name and a support route.

### Example of a compliant value

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

### Check this yourself

**Does HELP sent from a number that never subscribed still return the brand name and a support route?**

1. Test the unsubscribed case: send HELP from a number that is not on the list.
2. Confirm the handler answers from the number that received it, without looking the sender up first.

*What wrong looks like:* The people most in need of a HELP reply are the ones who are not subscribers — someone who got a message meant for a previous holder of their number. Silence turns a fixable confusion into a carrier complaint.

### Notes

Absorbs OPS-082, the same duty stated for customer-care requests generally. Not observable before traffic. What the user has to test is the unsubscribed case: send HELP from a number that is not on the list and confirm a reply comes back.

---

## OPS-079 — HELP must work in every form it arrives in

> HELP must be case-insensitive, functional over both SMS and MMS, and functional in the programme's language without erroring on the English keyword.

- **Rule ID:** OPS-079
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `HELP keyword handler`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA, MMA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-079/

### Why this rule exists

HELP is the fallback when everything else has confused somebody, so it is the last handler that should be fussy about how it is spelled or which protocol carried it. Each of these variations is a separate code path in most platforms, and the ones that fail are invariably the ones nobody tested because the happy path was obvious.

### How to fix it

Normalise the inbound body before matching, share one handler across SMS and MMS, and register the local-language help word alongside HELP rather than instead of it. Done when "help", "AYUDA" and a HELP sent as an MMS reply all return the same information.

### Example of a compliant value

```text
Keyword table: HELP, INFO, SUPPORT, AYUDA — matched case-insensitively on either protocol.
```

### Check this yourself

**Do "help", "AYUDA" and a HELP sent as an MMS reply all return the same information?**

1. Send all three to your own number after launch.
2. Confirm the local-language help word was registered alongside HELP rather than instead of it.
3. Confirm one handler serves both SMS and MMS.

*What wrong looks like:* Each variation is a separate code path in most platforms, and the ones that fail are invariably the ones nobody tested because the happy path was obvious.

### Notes

Three code paths we cannot see. What the user has to do is send the three variants to their own number after launch; OPS-081 is the registration-side twin, checking that the destinations inside the reply actually reach help.

---

## OPS-081 — The HELP reply must send people somewhere that answers

> Every destination named in the HELP reply — a phone number, a URL or an email address — must actually reach help.

- **Rule ID:** OPS-081
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.help_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; Human check — only someone holding the document can settle it
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, MMA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-081/

### Why this rule exists

HELP exists so a recipient who does not recognise a number can find out who is texting and how to make it stop. A reply pointing at a number that rings out, a mailbox nobody reads, or a URL that 404s satisfies a presence check and fails the consumer entirely, which is why the handbook names dead ends specifically. The usual cause is a support address that was retired after the auto-reply was written.

### How to fix it

Test every destination in the HELP reply the way a recipient would: dial the number, send a message to the address, open the link. Replace anything that does not reach a person who can help. Done when each destination has been exercised end to end since the reply was last edited.

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

### Common mistakes

- A support address that auto-replies "this mailbox is not monitored" is a dead end with extra steps, and reviewers treat it as one.

### Check this yourself

**Have you dialled the number, mailed the address and opened the link in the HELP reply yourself, from outside your own network, since it was last edited?**

1. Dial the number and confirm a person who can help answers.
2. Send a message to the address and confirm a human replies.
3. Open the link and confirm it loads a page that answers the question a confused recipient has.

*What wrong looks like:* A support address retired after the auto-reply was written. A mailbox that auto-replies "this mailbox is not monitored" is a dead end with extra steps, and reviewers treat it as one.

### Notes

Only partly settleable from here. We can see whether the destination belongs to the brand and whether the site corroborates it, and we can flag one that plainly does not — but whether a number is answered is not observable from a registration. The user has to place the call, send the email and open the link themselves, from outside their own network, and confirm each reaches a person.

---

## OPS-083 — Carrier deactivation files must be ingested daily

> The carrier deactivation feeds must be processed every day and the listed numbers removed from every opt-in list.

- **Rule ID:** OPS-083
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `deactivation feed ingest job`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify; Human check — only someone holding the document can settle it
- **Fix type:** Wait on an external system or a required interval
- **Required by:** T-Mobile, AT&T, CTIA, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-083/

### Why this rule exists

Around a hundred thousand US numbers are deactivated daily and most are reissued to somebody else within months. A consent record follows the number, so an unscrubbed list sends order details, appointment reminders or marketing to a stranger who never opted in — and delivery succeeds, so nothing in the sending metrics reveals it. The carriers publish the feeds specifically to make this preventable, which is why failing to consume them reads as negligence rather than bad luck.

### How to fix it

Confirm which party consumes the feeds — most CPaaS platforms offer it, several charge for it, and a few leave it entirely to the sender — then run the ingest daily and log each run with its timestamp. Done when a number deactivated on Monday is off your list on Tuesday.

### Example of a compliant value

```text
Daily 06:00: pull the T-Mobile and AT&T deactivation files, suppress the listed MDNs, log run_at and record count.
```

### Common mistakes

- Delivery failures are not a substitute. A reassigned number delivers perfectly — to the wrong person — so bounce handling never finds these.

### Check this yourself

**Is a number deactivated on Monday off your list on Tuesday — and who is running that ingest?**

1. Establish which party consumes the carrier deactivation feeds: most CPaaS platforms offer it, several charge for it, and a few leave it entirely to the sender.
2. Confirm it is enabled on your account, runs daily, and logs each run with a timestamp.
3. Check the retention window on the report objects — several platforms delete them after a few days, so a missed run cannot be replayed.

*What wrong looks like:* Around a hundred thousand US numbers are deactivated daily and most are reissued within months. Delivery to a reassigned number succeeds perfectly — to a stranger — so bounce handling never finds these.

### Notes

Absorbs OPS-084 and OPS-086, the same daily ingest against a second carrier feed and against a platform-mediated deactivation report. The feeds are carrier data we cannot see. What the user has to establish is whether their provider ingests them on their behalf, whether it is enabled on their account, and what the retention window on those report objects is — several platforms delete them after a few days, so a missed run cannot be replayed. OPS-085 is the approval-side twin: whether the programme describes doing this at all.

---

## OPS-085 — The programme must scrub deactivated numbers before sending

> The programme must describe checking carrier deactivation data before each send, and logging each ingest.

- **Rule ID:** OPS-085
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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, T-Mobile, AT&T
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-085/

### Why this rule exists

Around 100,000 US numbers change hands every day, and a consent record follows the number rather than the person. Messaging a reassigned number sends someone else's order details, or marketing, to a stranger who never opted in — the single largest source of complaints that look like consent failures and are not. The carriers publish daily deactivation files precisely so this is preventable, and a programme with no ingest described has not decided who runs it.

### How to fix it

State which deactivation feed the programme consumes — the carrier files through your provider, or the provider's own deactivation report — how often it runs, and that listed numbers are suppressed before the next send. Done when the flow names a source and a cadence rather than an intention.

### Example of a compliant value

```text
Carrier deactivation lists are ingested daily through our messaging provider; listed numbers are suppressed before any send, and each ingest run is logged with its timestamp.
```

### Common mistakes

- Relying on delivery failures to find dead numbers does not work here — a reassigned number delivers perfectly, to the wrong person.

### Notes

Registration-side twin. The daily ingest itself (OPS-083, OPS-084, OPS-086) is a scheduled job we cannot observe; what we judge is whether the programme has one.

---

## OPS-087 — The reassigned-numbers database is the only route to the safe harbour

> The FCC Reassigned Numbers Database must be queried using the date of consent, and re-queried at least every 30 days.

- **Rule ID:** OPS-087
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `reassigned-numbers query, keyed on the consent date`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-087/

### Why this rule exists

The database is the one mechanism that converts "we messaged the wrong person" from strict liability into a defence, and the defence turns entirely on querying with the date consent was obtained — a query without that date proves nothing about whether the number had already moved on. Brands skip it because it is a paid lookup that returns nothing useful most of the time, which is exactly what an insurance policy looks like.

### How to fix it

Query the database with each number and the date its consent was recorded, keep the response, and re-query at least monthly for numbers still on the list. Done when you can produce, for any number you messaged, the query that said it had not been reassigned since consent.

### Example of a compliant value

```text
Monthly: submit (msisdn, consent_date) for every active subscriber; retain the response as the safe-harbour record.
```

### Check this yourself

**For any number you messaged, can you produce a Reassigned Numbers Database query, made with the real consent date, saying it had not been reassigned?**

1. Register for access to the FCC database and budget the per-query cost.
2. Query with each number and the date its consent was recorded, and keep the response.
3. Re-query at least every 30 days for numbers still on the list.
4. Check the consent date you submit is the real one — the safe harbour is only as good as that field.

*What wrong looks like:* The lookup is skipped because it is paid and returns nothing useful most of the time, which is exactly what an insurance policy looks like. Without it, messaging the wrong person is strict liability rather than a defence.

### Notes

A paid federal lookup we cannot make on the brand's behalf. What the user has to do is register for access, budget the per-query cost, and — the part most often missed — make sure the consent date they submit is the real one, because the safe harbour is only as good as that field. OPS-199 covers keeping the date in the first place.

---

## OPS-088 — Some states make reassigned-number screening mandatory

> Where a state requires it, reassigned-number screening is an obligation rather than a safe-harbour option.

- **Rule ID:** OPS-088
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `reassigned-number screening policy`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** state law (ME)
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-088/

### Why this rule exists

Maine converts the federal safe harbour into a duty, which changes the calculus completely: skipping the lookup is no longer accepting a risk, it is a violation on its own terms. National programmes miss it because the federal framing — screen if you want the defence — is the one everybody read.

### How to fix it

Screen every number rather than maintaining a state-conditional policy — the lookup is the same one the safe harbour needs, so doing it universally satisfies both. Done when screening is unconditional rather than triggered by a state field you may not hold.

### Check this yourself

**Is reassigned-number screening unconditional, rather than triggered by a state field you may not hold?**

1. Decide between screening every number and building state-conditional logic on location data you can defend. The first is cheaper than it looks.
2. It is the same lookup the federal safe harbour needs, so doing it universally satisfies both.

*What wrong looks like:* Maine converts the federal safe harbour into a duty. National programmes miss it because the federal framing — screen if you want the defence — is the one everybody read.

### Notes

Needs the recipient state, which we do not hold and which is not the area code. What the user has to decide is whether to screen universally or to build state-conditional logic on top of location data they can defend — the first is cheaper than it looks.

---

## OPS-089 — A ported number is a new subscriber

> A fresh opt-in must be obtained when a subscriber ports their number between carriers.

- **Rule ID:** OPS-089
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `subscriber port event against consent status`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA, MMA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-089/

### Why this rule exists

Porting is one of the routes by which the person behind a number changes without any signal in the brand's own data, and short-code programmes in particular are expected to re-permission across it. Nothing in the sending platform surfaces a port, so a list treats the number as continuously consenting while the handset it reaches may have changed hands entirely.

### How to fix it

Where your platform exposes port or carrier-change events, treat one as expiring the consent and re-confirm before the next send. Where it does not, lean on the deactivation feeds and the reassigned-numbers query, which catch most of the same population. Done when a carrier change does not silently preserve consent.

### Check this yourself

**Does your provider surface porting or carrier-change events at all?**

1. Ask. Most do not.
2. Where it does, treat a port as expiring the consent and re-confirm before the next send.
3. Where it does not, lean on the deactivation feeds and the reassigned-numbers query, which catch most of the same population.

*What wrong looks like:* Nothing in the sending platform surfaces a port, so the list treats the number as continuously consenting while the handset it reaches may have changed hands entirely.

### Notes

A carrier event we never see. What the user has to check is whether their provider surfaces porting at all — most do not, and where that is true this obligation is discharged in practice by OPS-083 and OPS-087 rather than directly.

---

## OPS-090 — Check the number is a live mobile before paying to send to it

> Destination numbers should be validated as real, active mobile numbers before sending, since platforms bill accepted requests regardless of delivery.

- **Rule ID:** OPS-090
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `destination number validation`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-090/

### Why this rule exists

Billing happens on acceptance, not delivery, so a list full of landlines, disconnected numbers and typos costs money on every send and returns nothing. It is also a quality signal the carriers read: a high proportion of invalid destinations is one of the shapes that distinguishes a purchased list from an organic one, so the waste and the reputational damage arrive together.

### How to fix it

Run a lookup against the list before a large send and drop landlines, invalid formats and disconnected numbers. Done when the invalid rate on a send is measured rather than assumed.

### Example of a compliant value

```text
Pre-send lookup: 40,000 numbers → 38,900 mobile, 700 landline, 400 invalid → send to 38,900.
```

### Check this yourself

**Is the invalid rate on your sends measured, rather than assumed?**

1. Run a lookup against the list before a large send and drop landlines, invalid formats and disconnected numbers.
2. Weigh the per-number lookup cost against the per-message cost of sending to numbers that cannot receive — for a list built from typed-in phone fields it usually pays for itself on the first send.

*What wrong looks like:* Billing happens on acceptance, not delivery, so the waste is invisible in the delivery metrics. A high proportion of invalid destinations is also one of the shapes that distinguishes a purchased list from an organic one.

### Notes

A paid per-number lookup at the provider. What the user has to weigh is the lookup cost against the per-message cost of sending to numbers that cannot receive — for a list built from typed-in phone fields the lookup usually pays for itself on the first send.

---

## OPS-092 — Local time is where the recipient is, not what their area code says

> The recipient's local time must be derived from their actual location, not from the area code of their number.

- **Rule ID:** OPS-092
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `recipient location resolution`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC, state law
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-092/

### Why this rule exists

Numbers are portable and people move, so area codes stopped being geography years ago — a 212 number in Los Angeles is common, and a programme timing sends off it will message that person at 5am. This one assumption breaks every timing rule at once, and it is the default in almost every scheduler because the area code is the only location the phone number offers.

### How to fix it

Time sends from a location you actually hold — the billing or shipping address, the account's stated location, the timezone the app reports — and fall back to a conservative window rather than to the area code where you hold none. Done when a customer with an out-of-state number is messaged on their own clock.

### Example of a compliant value

```text
Schedule against profile.timezone where set; where unset, send only between 10am and 7pm Eastern, which is inside every US window.
```

### Common mistakes

- A conservative national window is a legitimate answer and often the right one — the narrow band that satisfies every state is a few hours, and most programmes do not need more.

### Check this yourself

**What location do you actually hold for each recipient — and is a customer with an out-of-state number messaged on their own clock?**

1. Decide which location data you hold and will rely on: the billing or shipping address, the account's stated location, the timezone the app reports.
2. Where you hold none, fall back to a conservative national window rather than to the area code.
3. The narrow band that satisfies every state is a few hours wide and most programmes do not need more.

*What wrong looks like:* A 212 number in Los Angeles is common, and a scheduler timing off the area code messages that person at 5am. It is the default in almost every scheduler, because the area code is the only location a phone number offers.

### Notes

Scheduler logic we cannot see. What the user has to decide is what location data they hold and are willing to rely on, because the alternative is not the area code — it is a narrower universal window.

---

## OPS-093 — Several states set a narrower quiet-hours window than the federal one

> Where the recipient's state sets a narrower window than 8am–9pm, that window applies.

- **Rule ID:** OPS-093
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `send time against the recipient state window`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** state law (FL, OK, MD, WA, OR, CT, NY, NJ, VA)
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-093/

### Why this rule exists

The federal window is the widest one available, not the operative one: Florida, Oklahoma, Maryland, Washington and Oregon close at 8pm, and Connecticut does not open until 9am — the narrowest band in the country. A national send timed to the federal window is lawful for most recipients and a statutory-damages claim for the rest, and several of these statutes carry a private right of action specifically so that it is worth bringing.

### How to fix it

Either hold a per-state window table and reliable recipient location, or send only inside the intersection of every state window — 9am to 8pm local — which needs no state data at all. Done when no send can fall outside the narrowest applicable window.

### Example of a compliant value

```text
National promotional window: 9:00am–8:00pm recipient local time, which clears every state rule at once.
```

### Check this yourself

**Can any send fall outside 9am–8pm in the recipient's local time?**

1. Choose between a per-state window table with reliable recipient location, and sending only inside the intersection of every state window — 9am to 8pm local, which needs no state data at all.
2. Florida, Oklahoma, Maryland, Washington and Oregon close at 8pm; Connecticut does not open until 9am.

*What wrong looks like:* A national send timed to the federal 8am–9pm window is lawful for most recipients and a statutory-damages claim for the rest — and several of these statutes carry a private right of action precisely so it is worth bringing.

### Notes

Absorbs OPS-094 and OPS-095, which are two more rows of the same per-state table. Needs the recipient's state, which we do not hold. What the user has to choose is between building the table and adopting the intersection — the intersection costs an hour at each end of the day and removes the whole class of failure.

---

## OPS-096 — A state may black out whole days

> Where a state enacts holiday blackout dates for solicitations, no solicitation may be sent on them.

- **Rule ID:** OPS-096
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `send date against a state holiday calendar`
- **Severity:** LOW — Best practice. Worth fixing, rarely fatal on its own.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** state law (UT)
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-096/

### Why this rule exists

A blackout is not a narrower window, it is a day on which the send must not happen at all — so a scheduler that only knows about hours will happily run a campaign into a prohibited day. These are recent and expanding statutes, which means a programme built correctly two years ago can become non-compliant without anything about it changing.

### How to fix it

Hold a blackout calendar alongside the window table and check the date as well as the time before scheduling. Done when a campaign scheduled across a blackout date skips the affected recipients rather than the whole send.

### Check this yourself

**Do you hold a current state holiday blackout calendar, and when was it last reviewed?**

1. Subscribe to a compliance feed or review the statutes annually — this is the rule most likely to have changed since anybody last looked.
2. Check the date as well as the time before scheduling, so a campaign crossing a blackout skips the affected recipients rather than the whole send.

*What wrong looks like:* A blackout is a day on which the send must not happen at all, so an hours-only scheduler runs the campaign into it. A programme built correctly two years ago becomes non-compliant with nothing about it changing.

### Notes

State calendars we do not hold, and a list that changes by legislature. What the user has to do is subscribe to a compliance feed or review the statutes annually — this is the rule most likely to have changed since anybody last looked.

---

## OPS-097 — Some states cap how often you may raise the same subject

> Where the recipient's state sets one, a per-subject frequency cap — commonly three messages per 24 hours on the same subject matter — must be enforced.

- **Rule ID:** OPS-097
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `per-recipient send count by subject, 24-hour window`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** state law (FL, OK, MD, NJ, OR)
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-097/

### Why this rule exists

The cap is per subject rather than per programme, which is the part that catches people: a cart reminder, a discount on the same item and a low-stock alert are three messages about one thing, sent by three different automations that each believe they are within their own limit. Nothing in a per-campaign frequency setting can see that.

### How to fix it

Count sends per recipient per subject across every automation rather than per campaign, and cap at three in 24 hours for the states that set one — or universally, which is simpler and rarely costs anything. Done when three automations about one product cannot all fire on the same day.

### Check this yourself

**Could three automations about one product all fire to the same person on the same day?**

1. Build a subject taxonomy first — without one there is nothing to count against, and per-campaign counters will report compliance while the cap is broken.
2. Count sends per recipient per subject across every automation, and cap at three in 24 hours universally rather than per state.

*What wrong looks like:* A cart reminder, a discount on the same item and a low-stock alert are three messages about one thing, sent by three automations that each believe they are within their own limit.

### Notes

A rolling count across systems we cannot see. What the user has to build is a subject taxonomy — without one there is nothing to count against, and per-campaign counters will report compliance while the cap is being broken.

---

## OPS-098 — There is a per-recipient daily ceiling even without a state rule

> No more than ten messages should reach one recipient in any 24-hour period without two-way engagement or explicit high-frequency consent.

- **Rule ID:** OPS-098
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `per-recipient 24-hour send count`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** Telnyx
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-098/

### Why this rule exists

Providers apply this as an acceptable-use limit regardless of state law, and crossing it reads as a malfunction rather than a campaign — which is usually what it is. The classic cause is a loop: an automation that fires on a status change, and a status that flaps.

### How to fix it

Cap per-recipient daily volume across all automations and alarm when the cap is hit, since hitting it usually means something is looping. Done when a runaway automation is stopped by the cap rather than by a complaint.

### Example of a compliant value

```text
Per-recipient limit 10 per 24h across every campaign; breach pauses the automation and pages the owner.
```

### Check this yourself

**Does your per-recipient daily cap span every campaign in the account, or sit inside one?**

1. Check where the counter lives. Per-campaign caps are the common implementation and they do not catch a loop.
2. Cap per-recipient daily volume across all automations at ten, and alarm when it is hit — hitting it usually means something is looping.

*What wrong looks like:* An automation fires on a status change and the status flaps. Crossing the ceiling reads as a malfunction rather than a campaign, which is usually exactly what it is.

### Notes

A counter across the whole account. What the user has to check is that the cap spans campaigns rather than sitting inside one — per-campaign caps are the common implementation and they do not catch the loop.

---

## OPS-099 — A state may cap monthly volume and demand the logs

> Where a state sets monthly solicitation volume caps and log-production duties, both must be met.

- **Rule ID:** OPS-099
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `monthly solicitation volume and log production`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Human check — only someone holding the document can settle it
- **Fix type:** Wait on an external system or a required interval
- **Required by:** state law (TN)
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-099/

### Why this rule exists

Tennessee caps monthly solicitations and requires call logs produced every six months, which is an obligation with a filing deadline rather than a technical control — and a programme that has never produced the logs cannot produce them retrospectively if it did not retain the fields. The volume cap is low enough that a single national campaign can exceed it in one send.

### How to fix it

Count solicitations per state per month, and retain per-message logs in a form you can hand over. Done when you could produce six months of logs for one state on request without an engineering project.

### Check this yourself

**Could you produce six months of per-message logs for one state on request, without an engineering project?**

1. Establish whether you solicit into a state with volume caps and log-production duties — Tennessee is the named one.
2. Count solicitations per state per month.
3. Check your message logs carry the fields the production requires, and retain them in a form you can hand over.

*What wrong looks like:* The volume cap is low enough that a single national campaign can exceed it in one send, and logs cannot be produced retrospectively if the fields were never retained.

### Notes

A state filing obligation. What the user has to establish is whether they solicit into the state at all, and if so, that their message logs carry the fields the production requires — OPS-216 covers the log content.

---

## OPS-100 — A national campaign needs a per-state matrix, evaluated against the strictest rule

> A per-state matrix of quiet hours, frequency caps, consent standards and retention windows must be maintained, and every national campaign evaluated against the most restrictive rule that applies to it.

- **Rule ID:** OPS-100
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `per-state rule matrix`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** state law, FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-100/

### Why this rule exists

This is the umbrella the individual state rows hang from, and without it each one is checked in isolation by whoever remembered it. A national send silently violates the narrowest state on every axis at once — window, cap, consent standard — and no single rule surfaces that, because each of them is satisfied for most recipients.

### How to fix it

Hold one table, state by state, of the window, the cap, the consent standard and the retention floor, and either apply per-state or take the strictest row as the national default. Review it against legislative changes at least annually. Done when a single table answers "may we send this, there, now".

### Common mistakes

- Taking the strictest row nationally is a legitimate and much cheaper answer — the cost is a narrower sending window, not a narrower audience.

### Check this yourself

**Does a single table answer "may we send this, there, now" — and when was it last reviewed against new legislation?**

1. Hold one table, state by state, of the window, the frequency cap, the consent standard and the retention floor.
2. Either apply per-state or take the strictest row as the national default — the cost of the second is a narrower sending window, not a narrower audience.
3. Name the source you trust and the review cadence. State mini-TCPAs are actively being enacted.

*What wrong looks like:* Each state row is checked in isolation by whoever remembered it, so a national send violates the narrowest state on every axis at once and no single rule surfaces it.

### Notes

A legal research artefact rather than a system, and it goes stale: state mini-TCPAs are actively being enacted. What the user has to own is the review cadence and the source they trust for it, because the matrix is only as current as its last update.

---

## OPS-101 — Default to daytime hours even where nothing requires it

> Sending should be restricted to normal daytime business hours in the recipient's local time as a platform default.

- **Rule ID:** OPS-101
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `default scheduled send window`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-101/

### Why this rule exists

The legal windows are the outer edges, and sending at their boundary is both lawful and a reliable way to generate complaints — a marketing message at 8:55pm is inside the federal window and reads as unacceptable to the person receiving it. Complaint volume is a carrier metric with consequences of its own, so the conservative default protects deliverability rather than only compliance.

### How to fix it

Set the platform default to business hours and require a deliberate override to send outside it. Done when sending at the edge of the legal window is a decision somebody made rather than the default.

### Example of a compliant value

```text
Platform default 10:00–19:00 recipient local; anything outside requires an explicit per-campaign override.
```

### Check this yourself

**Is sending at the edge of the legal window a decision somebody made, or your platform's default?**

1. Set the platform default to normal business hours in the recipient's local time.
2. Require a deliberate override to send outside it.

*What wrong looks like:* A marketing message at 8:55pm is inside the federal window and reads as unacceptable to the person receiving it — and complaint volume is a carrier metric with consequences of its own.

### Notes

A scheduler default we cannot see. What the user has to do is set it once — the value of this rule is that it makes every other timing rule harder to breach by accident.

---

## OPS-102 — The national do-not-call registry must be scrubbed before any solicitation

> Recipient lists must be scrubbed against the national do-not-call registry before any telephone solicitation, unless prior express written consent or an established business relationship applies.

- **Rule ID:** OPS-102
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `recipient list against the national registry`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC, FTC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-102/

### Why this rule exists

Registry violations carry per-message statutory damages and are the single most litigated part of the framework, and the exemptions are narrower than operators assume — an established business relationship expires, and "we have their number" is not express written consent. The scrub is what converts an argument about the exemption into a list that never contained the number.

### How to fix it

Subscribe to the registry for the area codes you message, scrub before every solicitation send, and keep the scrub record with its registry version date. Done when a solicitation list has been through a scrub you can evidence, not merely through a consent check.

### Common mistakes

- Relying on consent to skip the scrub is defensible only where the consent is genuinely express and written; scrubbing anyway costs little and removes the argument.

### Check this yourself

**Which of your sends are solicitations — and has each of those lists been through a national registry scrub you can evidence?**

1. Classify your sends. The classification is yours, and getting it wrong in the permissive direction is where the exposure sits.
2. Subscribe to the registry for the area codes you message, and scrub before every solicitation send.
3. Keep the scrub record with its registry version date.

*What wrong looks like:* The exemptions are narrower than operators assume — an established business relationship expires, and "we have their number" is not express written consent. Relying on consent to skip the scrub leaves an argument where a clean list would have left none.

### Notes

A federal subscription we cannot hold for the brand. What the user has to do is register for access, pay the per-area-code fee, and decide which of their sends are solicitations — the classification is theirs, and getting it wrong in the permissive direction is where the exposure sits. OPS-109 covers documenting the process.

---

## OPS-103 — A registry snapshot older than a month is not a scrub

> The national registry version used for a scrub must be no more than 31 days old at the time the message is sent.

- **Rule ID:** OPS-103
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `registry snapshot age at send time`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-103/

### Why this rule exists

The registry changes daily, so a stale snapshot removes the people who registered before your download and none of the people who registered after it — and the freshness requirement exists precisely because a scrub against a year-old file looks identical in the logs to a scrub against yesterday's. The failure mode is a pipeline that downloads once and caches indefinitely because nothing ever errors.

### How to fix it

Record the registry version date on every scrub and refuse the send when it is over 31 days old rather than warning about it. Done when an out-of-date snapshot blocks a send instead of producing a log line.

### Example of a compliant value

```text
Scrub record: registry_version 2026-03-01, scrubbed_at 2026-03-04, send_at 2026-03-04 — 3 days old, allowed.
```

### Check this yourself

**Does an out-of-date registry snapshot block a send, or only produce a log line?**

1. Record the registry version date on every scrub and refuse the send when it is over 31 days old.
2. Check the refresh is scheduled and monitored — an unmonitored download that started failing silently is the usual cause.

*What wrong looks like:* The pipeline downloads once and caches indefinitely because nothing ever errors. A scrub against a year-old file looks identical in the logs to a scrub against yesterday's, and the scrub keeps reporting success throughout.

### Notes

A property of a pipeline we cannot see. What the user has to check is whether the refresh is scheduled and monitored — an unmonitored download that started failing silently is the usual cause, and the scrub keeps reporting success throughout.

---

## OPS-104 — Several states run their own do-not-call registry

> Where a state operates a registry that is not fully merged with the federal one, recipient lists must be scrubbed against it as well.

- **Rule ID:** OPS-104
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `recipient list against state registries`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** state law (TX, AZ and others)
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-104/

### Why this rule exists

A national programme that scrubs only the federal registry is unscrubbed in the states that kept their own, and two of those states are unusually expensive: Texas carries elevated penalties, and Arizona's coverage of text messages specifically is a question worth answering before sending rather than after. The gap is invisible because the federal scrub reports success either way.

### How to fix it

List the states you message into, check which of them still run a separate registry, and add those scrubs to the same pre-send step as the federal one. Done when the scrub step names every registry it consulted rather than "the DNC list".

### Check this yourself

**Does your scrub step name every registry it consulted, rather than "the DNC list"?**

1. List the states you message into and check which still run a separate registry — Texas carries elevated penalties and Arizona's coverage of texts specifically is worth settling before sending.
2. Add those scrubs to the same pre-send step as the federal one. Each is a separate subscription with its own access process.
3. Confirm state by state whether the registry covers texts at all. It is not uniform.

*What wrong looks like:* A national programme that scrubs only the federal registry is unscrubbed in the states that kept their own — and the federal scrub reports success either way.

### Notes

Absorbs OPS-111 and OPS-112, which name Texas and Arizona specifically. Each state registry is a separate subscription with its own access process, and none of them is visible from here. What the user has to do is confirm coverage state by state — including whether the state registry covers texts at all, which is not uniform.

---

## OPS-105 — The internal do-not-call list is checked on every send

> Every send must be scrubbed against the brand's own company-specific do-not-call list.

- **Rule ID:** OPS-105
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `recipient list against the internal do-not-call list`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-105/

### Why this rule exists

The internal list holds the people who told this brand directly to stop, which makes messaging them the most obviously indefensible version of the failure — and unlike the federal registry there is no exemption, no relationship carve-out and no argument available. It gets skipped because the internal list often lives in the CRM rather than in the sending platform, so the send pipeline never consults it.

### How to fix it

Put the internal list where the send pipeline can read it, and check it at send time on every campaign — not only on solicitations. Done when a number on the internal list cannot be reached by any campaign the brand runs.

### Check this yourself

**Are the internal do-not-call list and the SMS suppression list the same list, or synchronised both ways?**

1. Find where the internal list lives. It is usually the CRM, which is why the send pipeline never consults it.
2. Put it where the pipeline can read it and check it at send time on every campaign, not only on solicitations.
3. Where the two lists are separate, establish which one is stale — one of them always is.

*What wrong looks like:* These are the people who told this brand directly to stop. There is no exemption, no relationship carve-out and no argument available.

### Notes

A list inside the brand, consulted by a pipeline we cannot see. What the user has to verify is that the internal list and the SMS suppression list are the same list, or are synchronised both ways — where they are separate, one of them is always stale. OPS-044 covers the brand-wide scope this depends on.

---

## OPS-107 — Staff have to be trained on the internal list, and it has to be evidenced

> Personnel must be trained in the existence and use of the internal do-not-call list, and the training records retained.

- **Rule ID:** OPS-107
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `training records`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Human check — only someone holding the document can settle it
- **Fix type:** Supply evidence only you hold
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-107/

### Why this rule exists

The internal list only works if the people who receive the requests know it exists and where to put them, and the training record is what turns a policy into something the brand can show it operates. In an enforcement action the absence of records is treated as the absence of training, whatever actually happened.

### How to fix it

Train everyone who takes customer contact on how to record a do-not-call request, and keep a dated record of who was trained and when. Done when you can produce the roster for any date in the last five years.

### Check this yourself

**Could you produce the training roster for any date in the last five years?**

1. Train everyone who takes customer contact on how to record a do-not-call request.
2. Keep a dated record of who was trained and when, for five years — the same period as the suppression records, because the two are asked for together.

*What wrong looks like:* In an enforcement action the absence of records is treated as the absence of training, whatever actually happened.

### Notes

Records inside the brand that we never see. What the user has to do is keep them for the same period as the suppression records themselves — five years — because the two are asked for together.

---

## OPS-108 — A do-not-call request is recorded when it is made

> A do-not-call request must be recorded, with the name and number, at the time the request is made.

- **Rule ID:** OPS-108
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `internal do-not-call write latency`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-108/

### Why this rule exists

The obligation is about latency rather than storage: a request written up at the end of the week is a week in which the number can still be messaged, and the record then shows a delay nobody can explain. It is also the moment the identifying detail is available — the person is on the phone — and reconstructing a name from a number afterwards is exactly what does not happen.

### How to fix it

Make the request recordable during the contact — a field the agent sets before ending the call, not a form filed later — and write the name and number together. Done when the record timestamp matches the contact timestamp.

### Example of a compliant value

```text
Agent sets Do Not Call on the account during the call: name, number, request received 2026-03-04T11:02Z.
```

### Check this yourself

**Does the record timestamp on a do-not-call request match the contact timestamp?**

1. Trace the workflow: is anyone asked to enter these after the fact? Batch entry at the end of a shift is common and it is what creates the latency.
2. Make the request recordable during the contact — a field the agent sets before ending the call — and capture the name and number together.

*What wrong looks like:* A request written up at the end of the week is a week in which the number can still be messaged. The name is available while the person is on the phone and is never reconstructed afterwards.

### Notes

A workflow inside the brand. What the user has to check is whether their process asks anybody to do this after the fact; batch entry at the end of a shift is common and it is what creates the latency this rule is about.

---

## OPS-109 — The scrub process needs writing down, version dates included

> The registry access and scrub process must be documented, including the registry version date used for each scrub.

- **Rule ID:** OPS-109
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `scrub process documentation`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Human check — only someone holding the document can settle it
- **Fix type:** Supply evidence only you hold
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-109/

### Why this rule exists

The defence to a registry claim is the scrub, and a scrub with no record of which registry version it used cannot answer the only question that matters — whether the number was on the list at the time. Documenting the process is also what makes the freshness requirement auditable rather than aspirational.

### How to fix it

Write down who holds the registry subscription, how often it is refreshed, where the scrub runs in the send pipeline, and store the version date with every scrub result. Done when any past send can be tied to the registry version that cleared it.

### Example of a compliant value

```text
Scrub log: send acme-2026-03-04, registry_version 2026-03-01, 40,000 in, 312 removed.
```

### Check this yourself

**Can any past send be tied to the registry version that cleared it?**

1. Write down who holds the registry subscription, how often it is refreshed, and where the scrub runs in the send pipeline.
2. Store the version date with every scrub result — most scrub tooling logs a result and a count and drops the version.

*What wrong looks like:* A scrub with no record of which registry version it used cannot answer the only question that matters: whether the number was on the list at the time.

### Notes

Documentation and logs inside the brand. What the user has to do is keep the version date specifically — most scrub tooling logs a result and a count and drops the version, which leaves the record unable to answer the question it exists for.

---

## OPS-110 — Some states require the seller to register before texting residents

> Before texting a state's residents, determine whether the seller must register with that state and post a bond.

- **Rule ID:** OPS-110
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `state seller registration`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** state law (TX)
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-110/

### Why this rule exists

Texas requires telephone solicitors to register with the Secretary of State, per location, with a bond — an obligation that has nothing to do with the carriers and that no part of the 10DLC process mentions. It is discovered through an enforcement letter rather than a rejection, and the registration cannot be applied retrospectively to the sends already made.

### How to fix it

Check the seller-registration requirement for every state you solicit into before the first send, and register where it applies or exclude the state until you have. Done when the states you message are the states you are permitted to solicit in.

### Check this yourself

**For every state you solicit into, have you checked whether the seller must register and post a bond there?**

1. Take legal advice on which of your sends count as solicitations and which states they reach.
2. Texas requires telephone solicitors to register with the Secretary of State, per location, with a bond.
3. Register where it applies, or exclude the state until you have.

*What wrong looks like:* No part of the 10DLC process mentions it, so it arrives as an enforcement letter rather than a rejection — and the registration cannot be applied retrospectively to sends already made.

### Notes

A state filing, entirely outside the messaging stack. What the user has to do is take legal advice on which of their sends count as solicitations and which states they reach — carrier approval says nothing about either, and this is the clearest case in the framework where approval is not permission.

---

## OPS-113 — A state may impose its own opt-out and identification duties

> Where a state requires it, opt-out replies must be honoured and accurate sender identification maintained under that state's own rules.

- **Rule ID:** OPS-113
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `opt-out handling and sender identification, per state`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Human check — only someone holding the document can settle it
- **Fix type:** Wait on an external system or a required interval
- **Required by:** state law (VA)
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-113/

### Why this rule exists

Virginia and states like it restate obligations the federal rules already impose, which sounds redundant and is not: the state version comes with its own enforcement route and its own penalties, so a failure is actionable twice. It matters most for sender identification, where the federal framing is a carrier expectation and the state framing is a statute.

### How to fix it

Identify the brand in every message and honour every opt-out immediately, which satisfies the state rules and the federal ones together. Done when no message leaves without the brand name in it.

### Check this yourself

**Does every message leaving your programme carry the brand name, and is every opt-out honoured immediately?**

1. Treat the strictest state as the standard rather than maintaining per-state behaviour: identification and immediate opt-out are cheap universally.
2. Read a real delivered message and confirm the brand is identifiable in it.

*What wrong looks like:* Virginia and states like it restate federal duties with their own enforcement route and penalties, so one failure is actionable twice.

### Notes

State law applied to traffic we cannot see. What the user has to do is treat the strictest state as the standard rather than maintaining per-state behaviour — the identification and opt-out duties are cheap to satisfy universally and expensive to get wrong once.

---

## OPS-114 — A programme relying on the delivery exemption still owes an opt-out

> A campaign relying on the package-delivery exemption must offer an opt-out and honour it within six business days.

- **Rule ID:** OPS-114
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `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:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-114/

### Why this rule exists

The exemption removes the need for prior express consent, and brands read that as removing the consumer's ability to refuse — which is the one thing it does not do. The FCC attached conditions to every exemption it granted, and the opt-out is the condition that gets dropped, because a delivery notification feels like something nobody would want to stop.

### How to fix it

Carry opt-out instructions in the exempt messages themselves and state the honouring window in the flow. Done when a delivery notification tells the recipient how to stop and the flow says how quickly that takes effect.

### Example of a compliant value

```text
Acme Coffee: your order #4471 ships today, track at acmecoffee.com/t/4471. Reply STOP to stop delivery texts.
```

### Notes

Applies only where a campaign claims one of the FCC's exempted categories, which the registration has no attribute for. The condition sits in the criteria, and the note records that: a campaign that never invokes an exemption is not failed by this rule.

---

## OPS-115 — An exempt message must not cost the recipient anything

> Where an exemption requires it, exempted informational messages must not be charged to the called party or counted against their plan limits.

- **Rule ID:** OPS-115
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `billing treatment of exempt messages`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Human check — only someone holding the document can settle it
- **Fix type:** Wait on an external system or a required interval
- **Required by:** FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-115/

### Why this rule exists

Several of the FCC exemptions are conditional on the message being free to the recipient, and a programme relying on the exemption while sending billable messages has not met the condition — so the exemption does not apply and the messages needed consent after all. It is a condition nobody controls from the sending side, which is exactly why it has to be checked rather than assumed.

### How to fix it

Confirm with the carrier or provider whether the traffic is free-to-end-user where the exemption requires it, and stop relying on that exemption where it is not. Done when the exemption you are relying on has had each of its conditions checked rather than only its category.

### Check this yourself

**For the exemption you are relying on, has each of its conditions been checked — including whether the message is free to the recipient?**

1. Read the conditions attached to the specific exemption, not just its category. The category is the famous part and the conditions are where these fail.
2. Confirm with the carrier or provider whether the traffic is free-to-end-user where the exemption requires it.
3. Stop relying on that exemption where it is not.

*What wrong looks like:* The programme sends billable messages under an exemption conditional on them being free. The condition is unmet, so the exemption does not apply and the messages needed consent after all.

### Notes

Determined by the carrier and the recipient's plan, neither of which we see. What the user has to do is read the conditions attached to the specific exemption they are claiming — the category is the famous part and the conditions are where these fail.

---

## OPS-116 — Carrier approval is not legal cover

> Litigation exposure must be sized separately for state regimes with a private right of action, and carrier approval must not be treated as legal compliance.

- **Rule ID:** OPS-116
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `compliance posture and risk model`
- **Severity:** LOW — Best practice. Worth fixing, rarely fatal on its own.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Human check — only someone holding the document can settle it
- **Fix type:** Wait on an external system or a required interval
- **Required by:** state law (GA, WA and others), courts
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-116/

### Why this rule exists

The two systems are decided by different bodies against different standards: carriers decide whether traffic is carried, courts decide whether it was lawful, and an approved campaign is routinely both. States with private rights of action and statutory damages per message turn a modest programme into a material liability, and the approval that arrived first is not evidence of anything in that forum.

### How to fix it

Size the exposure per state — messages sent, statutory damages, class exposure — and treat that as the compliance driver rather than the carrier verdict. Done when somebody can state the worst-case number for the states you message into.

### Check this yourself

**Can somebody state the worst-case statutory-damages number for the states you message into?**

1. Size the exposure per state: messages sent, statutory damages per message, class exposure.
2. Get legal advice on the states you reach, and keep that conversation separate from anything about registration.
3. Treat that number as the compliance driver rather than the carrier verdict.

*What wrong looks like:* Carriers decide whether traffic is carried and courts decide whether it was lawful. An approved campaign is routinely both, and approval feels like permission when it is not.

### Notes

A legal assessment rather than a check. What the user has to do is get advice on the states they reach, and separate that conversation from anything about registration — the two get conflated because approval feels like permission and is not.

---

## OPS-123 — Every message needs a valid carrier message-class tag

> Every 10DLC A2P message must carry a valid, authorised carrier message class tag.

- **Rule ID:** OPS-123
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `outbound message class tag`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** AT&T, Telnyx
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-123/

### Why this rule exists

The class tag is how AT&T decides what throughput the message gets and whether it is carried at all, and it is assigned to the campaign rather than chosen per send — so traffic sent with the wrong tag, or none, fails in a way that looks like a throughput problem rather than a tagging one. It is set by the platform, which is why the sender rarely knows it exists until delivery is unexplainably poor.

### How to fix it

Confirm with your provider which class the campaign was assigned and that outbound traffic carries it. Done when you can state your campaign's message class and it matches what the provider registered.

### Check this yourself

**Can you state your campaign's carrier message class, and does the outbound traffic carry it?**

1. Look the class up in the campaign record at your provider — it is assigned to the campaign, not chosen per send.
2. Confirm with them that outbound traffic carries it.
3. Mismatches are diagnosed there rather than in any error code.

*What wrong looks like:* The wrong tag, or none, fails in a way that looks like a throughput problem rather than a tagging one — and it is set by the platform, so the sender rarely knows it exists until delivery is unexplainably poor.

### Notes

Applied in the sending path. What the user has to do is ask — the class is visible in the campaign record at the provider, and mismatches between the assigned class and the traffic are diagnosed there rather than in any error code.

---

## OPS-124 — Unregistered and P2P-classified traffic has a hard per-number ceiling

> Traffic classified as P2P or unregistered is limited to roughly fifteen messages or segments per number per minute.

- **Rule ID:** OPS-124
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `per-number per-minute send rate`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** AT&T
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-124/

### Why this rule exists

The ceiling is low enough that any real campaign hits it immediately, which is the point: it is what makes registration the only viable path. Senders meet it while testing before their campaign is approved and conclude the platform is slow, then build a sending schedule around a limit that would have gone away.

### How to fix it

Do not size a programme against unregistered throughput. Wait for the campaign to be approved and provisioned before measuring what the number can do. Done when the rate you planned against is the registered one.

### Check this yourself

**Were the numbers you benchmarked throughput on attached to an approved campaign at the time?**

1. Check when the benchmark was taken against when the campaign was provisioned.
2. Unregistered and P2P-classified traffic is capped at roughly fifteen messages or segments per number per minute — low enough that any real campaign hits it immediately.
3. Re-measure after provisioning, and plan against that number.

*What wrong looks like:* A team tests before approval, concludes the platform is slow, and builds a sending schedule around a limit that would have gone away.

### Notes

A carrier-applied rate we cannot observe. What the user has to check is whether the numbers they benchmarked on were attached to an approved campaign at the time — benchmarks taken before provisioning are the usual source of a wrong plan.

---

## OPS-126 — A low-volume campaign has a ceiling, not a warning

> Low-volume campaigns must stay under their published ceiling, or be upgraded to a standard registration.

- **Rule ID:** OPS-126
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign volume against the use-case ceiling`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** T-Mobile, TCR, Telnyx, Bird
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-126/

### Why this rule exists

The tier is priced for genuinely small programmes, and exceeding it does not throttle politely — the traffic above the ceiling is unregistered for the purposes of the carriers who applied it. Programmes grow into this without noticing, because the registration that was right at launch says nothing when the list doubles.

### How to fix it

Track monthly volume against the tier ceiling and upgrade before crossing it rather than after. Done when the registration matches the traffic the programme is actually sending this quarter.

### Check this yourself

**Does your low-volume registration still match the traffic the programme is sending this quarter?**

1. Track monthly volume against the tier ceiling and own the review — nothing prompts an upgrade.
2. Upgrade before crossing it rather than after.

*What wrong looks like:* The registration that was right at launch says nothing when the list doubles. Traffic above the ceiling is unregistered for the purposes of the carriers who applied it, rather than politely throttled.

### Notes

Volume against a published ceiling. What the user has to own is the review — nothing prompts an upgrade, and the registration keeps looking correct while the traffic outgrows it. OPS-VOLUME-PLAUSIBLE checks the declaration at registration time.

---

## OPS-127 — UCaaS low-volume carries restrictions beyond the volume

> A UCaaS low-volume registration is limited to a low daily ceiling, a restricted throughput class, one number per human user, and no API or automated traffic.

- **Rule ID:** OPS-127
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `UCaaS traffic pattern against the tier conditions`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** T-Mobile, AT&T, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-127/

### Why this rule exists

The tier exists for individual humans typing messages, and the conditions enforce that rather than merely the volume — so a business that stays under the daily cap but sends through an API has still breached it. It is chosen for the low cost and the conditions are discovered afterwards.

### How to fix it

Use this tier only for human-sent, one-number-per-person messaging. Register a standard campaign for anything automated, however low the volume. Done when no API traffic runs on a UCaaS registration.

### Check this yourself

**Does anything automated touch the numbers on your UCaaS low-volume registration?**

1. Look for API traffic, integrations and scheduled sends on those numbers — an integration somebody added later is the usual breach, and it is invisible in the volume figures.
2. The tier requires human-sent messages, one number per person, no automation — staying under the daily cap is not sufficient.
3. Register a standard campaign for anything automated, however low the volume.

*What wrong looks like:* A business well under the daily ceiling has still breached the tier because it sends through an API. The tier was chosen for the price and the conditions were read afterwards.

### Notes

Tier conditions applied by the carriers. What the user has to confirm is that nothing automated touches the numbers on this tier — an integration somebody added later is the usual breach, and it is invisible in the volume figures.

---

## OPS-128 — Registering and vetting a brand does not raise the platform rate limit

> Brand registration and vetting alone do not raise the sending platform's own default per-number rate; a separate increase must be requested.

- **Rule ID:** OPS-128
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `platform account sending rate`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-128/

### Why this rule exists

There are two ceilings — the carrier's and the platform's — and vetting moves only the first. Teams complete an expensive vet, see no change in throughput, and conclude the vet failed or the carrier is ignoring it, when the constraint is a default on their own account that nobody has asked to change.

### How to fix it

Raise a rate-increase request with the platform as a separate task from vetting, and check the account limit before diagnosing a throughput problem as a carrier one. Done when the platform limit is above the throughput the campaign was granted.

### Check this yourself

**Have you checked your platform's own per-number rate limit before blaming the carrier — or before buying a vet for throughput?**

1. Look up the account limit at your provider. There are two ceilings, the carrier's and the platform's, and vetting moves only the first.
2. Raise a rate-increase request with the platform as a separate task from vetting.
3. Done when the platform limit is above the throughput the campaign was granted.

*What wrong looks like:* An expensive vet completes, throughput does not move, and the team concludes the vet failed — when the binding constraint was a default on their own account that nobody asked to change.

### Notes

An account limit at the provider. What the user has to do is look it up before spending on a vet for throughput reasons — the platform default is frequently the binding constraint and much cheaper to move.

---

## OPS-130 — Tax-exempt status is not a political vet

> Uncapped political throughput requires a valid political vetting artefact; 501(c) tax-exempt status alone yields only standard terms.

- **Rule ID:** OPS-130
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `political vetting artefact against throughput terms`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** T-Mobile, TCR
- **Applies:** Applies when the use case is POLITICAL.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-130/

### Why this rule exists

Both facts sit on the brand record and one of them looks like the other, so a non-profit running a political programme reasonably expects its tax status to carry the throughput. It does not: the carriers want independent verification that the sender is who they claim, and a tax exemption verifies something else entirely.

### How to fix it

Obtain a political vet — Campaign Verify or an equivalent both carriers accept — and import it, if the programme needs uncapped throughput. Done when the throughput you planned against is backed by the artefact that grants it.

### Check this yourself

**Which artefact does the brand actually hold — a political vet, or 501(c) tax-exempt status?**

1. Read the brand record. Both facts sit there and one looks like the other.
2. Only a political vet — Campaign Verify or an equivalent both carriers accept — grants uncapped political throughput.
3. Obtain and import one if the programme needs that volume.

*What wrong looks like:* A non-profit running a political programme expects its tax status to carry the throughput. The carriers want independent verification that the sender is who they claim, and a tax exemption verifies something else entirely.

### Notes

Throughput terms granted by the carriers. What the user has to do is check which artefact their brand actually holds before planning volume; XBC-003 refuses a political campaign with no vetting at all, which is the approval-side question rather than this one.

---

## OPS-131 — A validity period shorter than the queue drops messages silently

> The message validity period must be long enough for the message to survive queueing at the sender's actual throughput.

- **Rule ID:** OPS-131
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `message validity period against queue depth`
- **Severity:** LOW — Best practice. Worth fixing, rarely fatal on its own.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-131/

### Why this rule exists

Validity period is a per-message expiry, so a large send at a modest throughput will have messages expire in the queue before they are ever attempted — and they are discarded rather than failed, so the delivery report shows nothing wrong. The default is short relative to the time a hundred-thousand-message send takes at fifteen a second.

### How to fix it

Divide the send size by the granted throughput to get the drain time, and set the validity period comfortably above it. Done when the last message in a large send is still valid when its turn arrives.

### Example of a compliant value

```text
200,000 messages at 60/second ≈ 56 minutes to drain → validity period 4 hours, not the 15-minute default.
```

### Check this yourself

**At your granted throughput, will the last message of your largest send still be valid when its turn arrives?**

1. Do the arithmetic: send size divided by granted throughput is the drain time.
2. Set the validity period comfortably above it. The default is fine for small sends, which is why this only appears at scale.

*What wrong looks like:* Messages expire in the queue before they are attempted and are discarded rather than failed, so the delivery report shows nothing wrong at all.

### Notes

A per-message parameter in the sending API. What the user has to check is the arithmetic for their largest send — the default is fine for small ones, which is why the problem only appears at scale.

---

## OPS-132 — The consumer-traffic thresholds are where P2P stops

> Traffic above the published consumer-operation reference thresholds is classified as non-consumer, whatever the sender intends.

- **Rule ID:** OPS-132
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `per-number traffic shape`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-132/

### Why this rule exists

The thresholds — a rough messages-per-minute band, around a thousand a day, one number per person, a hundred recipients per message, roughly balanced two-way traffic, and a limit on repeated identical messages — define the boundary in practice. A sender operating just above them without an A2P registration is not in a grey area; they are unregistered A2P traffic, and it is blocked outright rather than throttled.

### How to fix it

Measure your own traffic against the thresholds and register A2P if you are near any of them. The two-way ratio is the one people miss — traffic that is overwhelmingly outbound is non-consumer whatever the volume.

### Check this yourself

**What is the outgoing-to-incoming ratio on your numbers?**

1. Measure it. Traffic that is overwhelmingly outbound is non-consumer whatever the volume, and it is the threshold people miss.
2. Check the others too: messages per minute, roughly a thousand a day, one number per person, a hundred recipients per message, repeated identical messages.
3. Register A2P if you are near any of them.

*What wrong looks like:* A sender just above the thresholds without an A2P registration is not in a grey area — they are unregistered A2P traffic, and it is blocked outright rather than throttled.

### Notes

Traffic shape we cannot see. What the user has to check is the outgoing-to-incoming ratio on their numbers, since it reclassifies traffic that is well under every volume threshold.

---

## OPS-133 — A P2P exemption has conditions, all of them

> A P2P exemption may only be registered where every published condition holds — no business sending, not a cloud communications suite, human-written messages, traffic symmetry no worse than one to three, and a clean compliance history.

- **Rule ID:** OPS-133
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `P2P exemption application`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Human check — only someone holding the document can settle it
- **Fix type:** Wait on an external system or a required interval
- **Required by:** Telnyx
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-133/

### Why this rule exists

The exemption is attractive because it removes registration entirely, so it attracts applications from senders who meet most of the conditions. Meeting most of them is meeting none: the exemption is withdrawn on any one, and the traffic that ran under it retrospectively becomes unregistered A2P.

### How to fix it

Check every condition honestly before applying, particularly the traffic-symmetry and human-written ones. Where any fails, register instead — the cost of the registration is far below the cost of a withdrawn exemption.

### Check this yourself

**Have you measured your traffic symmetry against the one-to-three condition before applying for a P2P exemption?**

1. Measure the ratio first. It is the condition most often assumed and least often met.
2. Then check every other condition honestly: no business sending, not a cloud communications suite, human-written messages, clean compliance history.
3. Where any fails, register instead.

*What wrong looks like:* Meeting most of the conditions is meeting none. The exemption is withdrawn on any one of them, and the traffic that ran under it retrospectively becomes unregistered A2P.

### Notes

An application to the provider. What the user has to do is measure their own traffic symmetry first, because it is the condition most often assumed and least often met.

---

## OPS-134 — The registry has API rate limits of its own

> Integrations must stay within the registry's published API rate limits.

- **Rule ID:** OPS-134
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `API request rate to the registry`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-134/

### Why this rule exists

A polling integration built without regard to the limits will hit them during exactly the operations that matter — a bulk registration, a status reconciliation after an outage — and the failures look like registry problems rather than client ones. The fix is architectural rather than a retry, which is why it belongs before the integration is written.

### How to fix it

Back off on rate-limit responses, and replace polling with the status webhooks the registry publishes. Done when a bulk operation completes without a single rate-limit error.

### Check this yourself

**Does your platform poll the registry for status, rather than consuming its webhooks?**

1. Ask, or read the integration. Most poll, and it is the usual cause.
2. Back off on rate-limit responses and replace polling with the published status webhooks.
3. Done when a bulk operation completes without a single rate-limit error.

*What wrong looks like:* The limits are hit during exactly the operations that matter — a bulk registration, a reconciliation after an outage — and the failures read as registry problems rather than client ones.

### Notes

Integration behaviour at the registry. What the user has to establish is whether their platform polls — most do, and it is the usual cause. OPS-347 covers the webhook alternative.

---

## OPS-135 — Do not spread one message across many numbers

> Similar or identical content must not be distributed across many sending numbers to dilute per-number reputation or evade filtering.

- **Rule ID:** OPS-135
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `outbound traffic distribution across numbers`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** T-Mobile, AT&T, CTIA, Twilio, Telnyx, AWS, Vonage, Sinch, Plivo
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-135/

### Why this rule exists

Filtering is scored per originator, so splitting a send across ten numbers gives each one a tenth of the complaint rate and a tenth of the volume — which is the entire mechanism, and the carriers named it before anybody built a product around it. The innocent version is indistinguishable from the outside: a brand whose sends were slow buys more numbers to go faster, and is now doing exactly what the rule prohibits. It carries a four-figure pass-through fee rather than a rejection, so the first signal is an invoice.

### How to fix it

Route similar content through one registered originator, or request an approved number pool for the campaign so the distribution is declared rather than discovered. Where throughput is the real constraint, raise it through vetting rather than through number count.

### Common mistakes

- Needing more throughput is a legitimate problem with a legitimate answer — a registered number pool, or a higher-tier brand vet — and neither of them is more numbers quietly added to a campaign.

### Check this yourself

**How many numbers does this campaign actually send from, and was a pool ever approved for it?**

1. Count the originators on the campaign, then ask your provider whether an approved number pool is on record.
2. Where throughput is the real constraint, raise it through vetting rather than through number count.
3. Route similar content through one registered originator otherwise.

*What wrong looks like:* A brand whose sends were slow buys more numbers to go faster and is now doing exactly what the rule prohibits. It carries a four-figure pass-through fee rather than a rejection, so the first signal is an invoice.

### Notes

Absorbs MSG-138, the same prohibition from the message-content side. A traffic shape we cannot observe. What the user has to check is how many numbers their campaign actually sends from and whether a pool was ever approved for it — OPS-POOL-DECLARED covers the registration-side declaration, and OPS-136 catches the duplicate-campaign version of the same pattern before submission.

---

## OPS-136 — The campaign must not duplicate another campaign on the account

> A campaign whose description, name, website, message flow and samples all match an existing campaign is a snowshoeing signal.

- **Rule ID:** OPS-136
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign fields across the account`
- **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, T-Mobile, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-136/

### Why this rule exists

Duplicate campaigns spread identical content across multiple registrations and numbers, which is the definition of snowshoeing and carries a four-figure pass-through fee rather than a rejection. Legitimate multi-campaign brands differentiate by audience or content.

### How to fix it

Consolidate duplicates into one campaign, or differentiate them by genuine audience and content. Where you need more numbers for volume, request a number pool on one campaign rather than cloning it.

### Example of a compliant value

```text
One MARKETING campaign with a number pool, rather than four identical MARKETING campaigns.
```

### Notes

Fully decidable only against other campaigns on the account; today we judge self-similarity within the submission.

---

## OPS-137 — Do not burn numbers and replace them

> Numbers must not be cycled — used until deliverability degrades and then discarded, or freshly provisioned to escape a suspension.

- **Rule ID:** OPS-137
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `number provisioning and retirement pattern`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** T-Mobile, Vonage, Plivo, Telnyx
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-137/

### Why this rule exists

A number whose delivery is falling is telling you something about the traffic, and replacing it discards the signal rather than the cause. Carriers treat the pattern as deliberate because it is the standard playbook of senders who intend to keep sending regardless — and provisioning a new number while a suspension is open escalates from a campaign problem to an account one.

### How to fix it

Treat degrading delivery as a content or consent problem and fix that. Keep the number: recovering its reputation is slow but possible, and a fresh number inherits the same traffic and degrades the same way.

### Check this yourself

**What has your number churn been over the last quarter — how many numbers were retired and replaced?**

1. Pull the provisioning history and count retirements. A pattern nobody planned, emerging from individually reasonable decisions, is the usual finding.
2. For each retirement, ask what prompted it. Falling delivery is a content or consent signal, not a number fault.
3. Never provision a fresh number while a suspension is open — that escalates a campaign problem to an account one.

*What wrong looks like:* The number is discarded and the traffic that degraded it is not, so the replacement inherits the same content and degrades the same way. Carriers read the pattern as the standard playbook of senders who intend to keep sending regardless.

### Notes

Visible only in provisioning history over time. What the user has to look at is their own number churn over the last quarter — a pattern nobody planned but that has emerged from individual reasonable decisions is the usual finding.

---

## OPS-138 — A blocked number must not be automatically replaced

> A number blocked by a receiving network must never be auto-replaced with a fresh one, and a permanent block code must be treated as a programme defect rather than a replacement trigger.

- **Rule ID:** OPS-138
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `blocked-number remediation logic`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** T-Mobile, AT&T, Telnyx
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-138/

### Why this rule exists

Automatically swapping a blocked originator is filter-evasion assistance, and it is named as such — the carrier blocked the number to stop the traffic, and replacing it defeats a control the network applied deliberately. It is almost always built with good intentions, as failover: delivery dropped, so the system routed around it, exactly as it would around a hardware fault.

### How to fix it

Make a permanent block stop the campaign and page a human rather than trigger failover. Investigate the content and the consent behind the traffic that earned the block before any number is provisioned.

### Check this yourself

**What does your failover configuration do when a receiving network permanently blocks a number?**

1. Read the failover rules in your platform and your runbook. Look specifically for a rule that treats a block the way it treats an outage — it is a sensible-looking line and it is the defect.
2. Make a permanent block stop the campaign and page a human instead.
3. Confirm the investigation starts with the content and the consent behind the blocked traffic, before any number is provisioned.

*What wrong looks like:* Delivery dropped, so the system routed around it — exactly as it would around a hardware fault. The carrier blocked that number deliberately, and swapping it is named as filter-evasion assistance.

### Notes

Absorbs MSG-139, which states the same rule and adds the dynamic-routing case. Logic inside the sending platform. What the user has to audit is their own failover configuration — a rule that treats a block like an outage is the specific thing to look for, and it is a sensible-looking line in a runbook.

---

## OPS-139 — One number, one static route

> Each 10DLC, short code or toll-free number must use a single static route; dynamic routing is permitted only for major network outages.

- **Rule ID:** OPS-139
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `route configuration per number`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Human check — only someone holding the document can settle it
- **Fix type:** Wait on an external system or a required interval
- **Required by:** T-Mobile, AT&T, Vonage, Telnyx
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-139/

### Why this rule exists

Static routing is what makes traffic attributable — carriers trace a complaint back through the route, and a number whose path changes per message cannot be traced or trusted. Dynamic routing is also how grey routes get used without anybody choosing one, since a least-cost router will find them on its own.

### How to fix it

Pin each number to one authorised route and disable least-cost or failover routing except during a declared outage. Done when the path a message takes is the same one every time and you can name it.

### Check this yourself

**Is least-cost or failover routing enabled on your account — and can you name the single route each number takes?**

1. Ask your provider directly whether least-cost routing is on. It often is by default.
2. Pin each number to one authorised route and disable failover except during a declared outage.
3. Done when the path a message takes is the same one every time and you can name it.

*What wrong looks like:* A least-cost router finds a grey route on its own, so nobody chose one and the traffic is on it anyway. A number whose path changes per message cannot be traced back from a complaint.

### Notes

Carrier-side routing configuration. What the user has to ask their provider is whether least-cost routing is enabled on their account — it often is by default, and it is the mechanism behind the grey-route rule below.

---

## OPS-140 — Grey routes are not a price advantage

> A2P traffic must not be carried over any path or setting not authorised by the service providers for non-consumer messaging.

- **Rule ID:** OPS-140
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `termination path for A2P traffic`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** CTIA, T-Mobile, all MNOs
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-140/

### Why this rule exists

A grey route is a path that delivers commercial traffic through consumer-priced channels, and the carriers price it per message once they detect it — at ten dollars a message on at least one network, which turns a saving into a bill nobody budgeted. Senders rarely choose one knowingly: it arrives as a cheap termination option from an intermediary, or as the output of a least-cost router.

### How to fix it

Send A2P traffic only over the authorised A2P path your provider registers for the campaign, and refuse termination offers priced materially below the market. Ask your provider, in writing, which route your traffic takes.

### Check this yourself

**Has your provider confirmed in writing which route your A2P traffic takes — and does your per-message price look like the going rate?**

1. Ask for the route in writing. Senders rarely choose a grey route knowingly: it arrives as a cheap termination option or as the output of a least-cost router.
2. Compare your per-message price against the market. An unexplained discount is the signal.
3. Refuse termination offers priced materially below it.

*What wrong looks like:* The answer arrives as a surcharge rather than a rejection — up to ten dollars a message on at least one network, which turns the saving into a bill nobody budgeted.

### Notes

A network path we cannot see. What the user has to do is ask their provider to confirm the route in writing and compare their per-message price against the going rate — an unexplained discount is the signal, and the answer arrives as a surcharge rather than as a rejection.

---

## OPS-141 — One approved number is controlled by one party

> Sub-aggregation is prohibited: no more than one party may control the content sent from, or the numbers receiving on, a single approved number.

- **Rule ID:** OPS-141
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `number to content-provider mapping`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **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, Verizon, CTIA, Bird, Vonage
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-141/

### Why this rule exists

The registration says who is behind a number, and sub-aggregation makes that untrue — the consumer receives messages from an entity that was never vetted, and a complaint traces back to a brand that did not send it. It also breaks the one-opt-in-per-message-sender rule underneath, because consent given to one party is being used by another. Agencies and franchise groups arrive here honestly, by provisioning centrally and letting each client send.

### How to fix it

Register a separate brand and campaign for each party whose content goes out, and give each its own numbers. Where a shared arrangement is genuinely needed, get it approved and keep the sender register OPS-142 describes rather than operating it informally.

### Notes

Absorbs OPS-266 and MSG-140, which state the same prohibition from the shared-number and message-content sides. Partly visible in what a submission describes and not settleable from it — the arrangement lives in an operating model rather than in a field. What the user has to establish is who can send from each number today, and register a separate brand per party where the answer is more than one. OPS-367 is the ISV form of the same requirement.

---

## OPS-142 — A legitimately shared number needs a register of who sends on it

> Where a number or short code is shared under an approved arrangement, documented records of every message sender operating on it must be immediately available.

- **Rule ID:** OPS-142
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `shared-number sender register`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Supply evidence only you hold
- **Required by:** T-Mobile, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-142/

### Why this rule exists

Sharing is permitted only where it can be unpicked, and the register is what unpicks it: a complaint about one message has to resolve to one sender within the time a carrier gives you, which is short. Without it a shared arrangement is indistinguishable from the sub-aggregation the previous rule prohibits, and it will be treated as such.

### How to fix it

Keep a current list of every sender on the shared number, with the approval that permits the arrangement, somewhere you can produce it the same day. Done when a message can be attributed to a sender without asking anybody.

### Check this yourself

**If a number you send from is shared, was the arrangement approved — and could you attribute one message to one sender the same day?**

1. Confirm the sharing arrangement was approved in the first place. An undocumented one is a different and worse finding.
2. Keep a current list of every sender on the number, with the approval that permits it, where you can produce it same-day.
3. Test it: pick a message and attribute it without asking anybody.

*What wrong looks like:* A complaint has to resolve to one sender inside the short window a carrier gives you. Without the register, a permitted shared arrangement is indistinguishable from prohibited sub-aggregation and gets treated as such.

### Notes

A register inside the operator, and no registration field even says the number is shared. What the user has to confirm is that the sharing arrangement was approved in the first place — an undocumented one is OPS-141, not this rule.

---

## OPS-143 — Distributing like content across several numbers needs an arrangement

> Any use case that genuinely needs multiple numbers to distribute similar content requires special arrangements with the service providers.

- **Rule ID:** OPS-143
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `multi-number distribution arrangement`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-143/

### Why this rule exists

Some programmes really do need it — regional franchises, multi-location retail — and the answer is not that they cannot, but that it has to be agreed rather than assumed. The arrangement is what separates the legitimate case from snowshoeing, and without it the two are the same traffic shape and get the same treatment.

### How to fix it

Describe the distribution to the provider before building it and get the arrangement — usually an approved number pool, sometimes a per-location campaign — in writing. Done when the number count on the campaign is one somebody approved.

### Check this yourself

**If your programme genuinely needs several numbers, is the arrangement agreed with your provider in writing?**

1. Describe the distribution to the provider before building it — regional franchises and multi-location retail are the real cases.
2. Get the arrangement in writing: usually an approved number pool, sometimes a per-location campaign.
3. Raise it before scaling. Providers are generally willing where the case is real, and unwilling once the traffic has been flagged.

*What wrong looks like:* Without the arrangement, a legitimate multi-location programme and snowshoeing are the same traffic shape and get the same treatment — which arrives as a four-figure fee rather than a conversation.

### Notes

The arrangement is made with the provider and we never see it. What the user has to do is raise it before scaling rather than after the fee: providers are generally willing where the case is real, and unwilling once the traffic has already been flagged.

---

## OPS-144 — Do not rotate domains across a bulk send

> Multiple fully-qualified domains, or multiple public URL shorteners, must not be cycled across bulk messages carrying similar content.

- **Rule ID:** OPS-144
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `domains used across a bulk send`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** T-Mobile, AT&T, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-144/

### Why this rule exists

URL rotation is the content-side twin of snowshoeing: the domain is what a filter scores, so spreading one campaign across several defeats the scoring in exactly the way the numbers version does. The innocent case is per-channel tracking domains, which is a reasonable analytics decision that produces an identical fingerprint.

### How to fix it

Use one branded domain you control for every link in a campaign, and carry tracking in the path or the query rather than in the hostname.

### Check this yourself

**Does your marketing platform issue a different link domain per campaign or per channel?**

1. Look at the links in two recent campaigns and compare the hostnames. Several platforms rotate automatically, and the pattern is indistinguishable from deliberate evasion.
2. Use one branded domain you control for every link.
3. Carry tracking in the path or the query string rather than in the hostname.

*What wrong looks like:* Per-channel tracking domains are a reasonable analytics decision that produces exactly the fingerprint of URL rotation — the content-side twin of snowshoeing.

### Notes

Absorbs MSG-109, the same detection stated from the message-content side. Visible only across a real send. What the user has to check is whether their marketing platform issues per-campaign or per-channel domains automatically — several do, and the resulting pattern is indistinguishable from deliberate rotation.

---

## OPS-145 — Consecutive number ranges are a volume signal

> Consecutive number ranges must not be purchased to support higher-volume sending.

- **Rule ID:** OPS-145
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `provisioned number contiguity`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** Telnyx
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-145/

### Why this rule exists

A block of sequential numbers is the cheapest way to buy capacity and the most obvious pattern to detect, so it functions as a declaration that the intent was volume rather than presence. It is also snowshoeing with a paper trail, which makes the intent argument harder to have.

### How to fix it

Buy numbers as the programme genuinely needs them, and take throughput from vetting and an approved pool rather than from number count. Done when the numbers on a campaign are not a contiguous block.

### Check this yourself

**Are the numbers on this campaign a contiguous block?**

1. List them and look. A bulk order fulfilled from one range is the common cause and nobody chose it deliberately.
2. Buy numbers as the programme genuinely needs them, and take throughput from vetting and an approved pool rather than from number count.

*What wrong looks like:* A sequential block is the cheapest way to buy capacity and the most obvious pattern to detect. It reads as a declaration that the intent was volume rather than presence, which makes the intent argument much harder to have.

### Notes

Number inventory at the provider. What the user has to check is how their numbers were purchased — a bulk order fulfilled from one range is the common cause and nobody chose it deliberately.

---

## OPS-146 — Identical bodies across a bulk send fingerprint the campaign

> Message body wording should vary across a bulk send rather than being byte-identical to every recipient.

- **Rule ID:** OPS-146
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `body variance across a bulk send`
- **Severity:** LOW — Best practice. Worth fixing, rarely fatal on its own.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** Plivo, Vonage
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-146/

### Why this rule exists

Filters fingerprint exact bodies, so a million identical messages are one signature seen a million times and a single spam report can suppress the lot. Varying the wording is not evasion — it is the difference between a campaign that degrades gracefully under a complaint and one that stops entirely.

### How to fix it

Personalise at least one element per message — the recipient name, the item, the store — so bodies differ while the offer does not. Done when no two messages in a send are byte-identical.

### Example of a compliant value

```text
Acme Coffee: {{first_name}}, 20% off {{last_bought}} this weekend at {{store}}. Reply STOP to opt out.
```

### Common mistakes

- Random character insertion or deliberate misspelling is evasion rather than variance, and it is prohibited outright — vary the content, not the spelling. OPS-072 covers that line.

### Check this yourself

**Does your template contain any per-recipient field at all?**

1. Open the template and look for a merge field — the recipient name, the item, the store.
2. A template with none produces byte-identical bodies however sophisticated the platform is.
3. Vary the content, never the spelling: random characters or deliberate misspellings are evasion and prohibited outright.

*What wrong looks like:* A million identical messages are one signature seen a million times, so a single spam report suppresses the lot rather than degrading the campaign gracefully.

### Notes

A property of a real send. What the user has to check is whether their template has any per-recipient field at all — a template with none produces identical bodies however sophisticated the platform is.

---

## OPS-149 — Live content has to keep matching the registration

> Traffic must continue to match the registered use case and the registered samples, not merely have matched them at approval.

- **Rule ID:** OPS-149
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `live traffic against the registered use case and samples`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** TCR, T-Mobile, Twilio, Telnyx, Vonage
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-149/

### Why this rule exists

The samples are a promise about the programme, and programmes drift: a transactional campaign starts carrying a seasonal offer, an account-notification campaign adds a survey. Nobody re-reads the registration when writing a new template, so the drift is gradual and nothing flags it until the traffic no longer resembles what was approved.

### How to fix it

Review live templates against the registered samples on a schedule, and register a new campaign — or change the use case — before sending a category the registration does not describe. Done when every template in production would be recognised by somebody reading the registration.

### Check this yourself

**Would somebody reading your registration recognise every template now in production?**

1. Put the live templates next to the registered samples and read them together, on a schedule.
2. Register a new campaign — or change the use case — before sending a category the registration does not describe.
3. Nobody re-reads the registration when writing a new template, so the drift is gradual and nothing flags it.

*What wrong looks like:* A transactional campaign starts carrying a seasonal offer; an account-notification campaign adds a survey. The samples were a promise about the programme, and the traffic no longer resembles what was approved.

### Notes

Absorbs MSG-279, the same duty from the message-content side. Requires the live templates. What the user has to own is the review: the approval-side rules — MSG-141 and OPS-USECASE-SCOPE — check what was submitted, and neither of them sees what was added afterwards.

---

## OPS-150 — Send only the message types the subscriber agreed to

> Message types the subscriber did not consent to must not be sent — a survey to an OTP-only list, marketing to a transactional opt-in.

- **Rule ID:** OPS-150
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `message type against the consent record scope`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** AWS, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-150/

### Why this rule exists

Consent has a scope, and the scope is the category described at opt-in, not the sending platform's idea of a contact list. Sending outside it is unconsented messaging however carefully the original opt-in was collected, and it is the failure that turns a well-run programme into a complaint source, because the recipients did opt in — to something else.

### How to fix it

Store the consent scope on the record and check it before a send rather than segmenting by list membership. Done when a marketing send cannot include numbers whose consent was transactional.

### Check this yourself

**Is the consent scope stored on each record — or is consent a boolean?**

1. Look at the consent record itself. Where consent is a boolean, this rule cannot be satisfied by any amount of care at send time.
2. Check the scope before a send rather than segmenting by list membership.
3. Done when a marketing send cannot include numbers whose consent was transactional.

*What wrong looks like:* A survey to an OTP-only list. The recipients did opt in — to something else — which is what turns a carefully run programme into a complaint source.

### Notes

A comparison between a send and a stored scope. What the user has to check is whether the scope is stored at all — where consent is a boolean, this rule cannot be satisfied by any amount of care at send time. OPS-209 and OPS-199 cover recording it.

---

## OPS-151 — Separate marketing traffic once volume matters

> At medium-to-high volume, marketing traffic should sit on its own campaign and number set, with a separate short code per brand and per message type.

- **Rule ID:** OPS-151
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign and number segmentation by traffic type`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Human check — only someone holding the document can settle it
- **Fix type:** Wait on an external system or a required interval
- **Required by:** Bird, SignalWire, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-151/

### Why this rule exists

Marketing is what draws complaints and filtering, and mixing it with transactional traffic means a filtering event takes the order confirmations down with the promotions. Separation limits the blast radius: the campaign that gets throttled is the one that earned it, and the messages customers actually need keep arriving.

### How to fix it

Register marketing and transactional traffic as separate campaigns on separate numbers once volume justifies the second registration. Done when a filtering event on promotions cannot affect order updates.

### Check this yourself

**Could a filtering event on your promotions take your order confirmations down with it?**

1. Check whether marketing and transactional traffic share a campaign and a number set.
2. Weigh the cost of a second registration against the cost of transactional traffic being filtered alongside marketing — the second is usually much larger and arrives much later.
3. Separate them once volume justifies it.

*What wrong looks like:* Marketing is what draws complaints and filtering. Mixed traffic means the throttle lands on the order updates customers actually need.

### Notes

An architecture decision inside the sending account. What the user has to weigh is the cost of a second registration against the cost of transactional traffic being filtered alongside marketing — the second is usually much larger and much later.

---

## OPS-152 — One recognisable number per programme

> A business or programme should send from one primary, recognisable source number.

- **Rule ID:** OPS-152
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `programme to source number mapping`
- **Severity:** MEDIUM — Usually survives review, but lowers your trust score or invites manual review.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** T-Mobile
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-152/

### Why this rule exists

Recognition is the consumer's only defence against smishing: somebody who knows the number their pharmacy texts from can tell a fake from a real one. A programme that sends from a rotating set trains its own customers to accept messages from unfamiliar numbers, which is precisely the habit the industry is trying to break.

### How to fix it

Send each programme from one number and publish it, so customers can recognise and save it. Done when a customer could tell you which number your texts come from.

### Check this yourself

**Could a customer tell you which number your texts come from?**

1. Send each programme from one primary number and publish it so customers can recognise and save it.
2. Reconcile this against any pool you operate: a pool is legitimate for capacity and still argues for one primary number per programme rather than a rotating presentation.

*What wrong looks like:* A programme sending from a rotating set trains its own customers to accept messages from unfamiliar numbers — precisely the habit that makes smishing work.

### Notes

Sending configuration. What the user has to reconcile is this against any pool they operate — a pool is legitimate for capacity and still argues for one primary number per programme rather than a rotating presentation.

---

## OPS-153 — The sender must be who the message says it is

> The message number and sender name must not be spoofed or substituted in any way that misleads a consumer.

- **Rule ID:** OPS-153
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `outbound sender identity`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** CTIA, all MNOs
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-153/

### Why this rule exists

Sender identity is the only thing a recipient has to judge a message by, and misrepresenting it is the mechanic behind every smishing campaign — which is why the prohibition is absolute rather than proportionate. Legitimate substitution exists, for failover or for a shared brand, and it requires an arrangement with the provider rather than a configuration change.

### How to fix it

Send from the numbers registered to the campaign, presented as themselves. Where a substitution is genuinely needed, arrange it with the provider in advance rather than configuring it.

### Check this yourself

**Does any part of your stack rewrite the originating number or sender name?**

1. Ask your provider and check any aggregation layer between your application and the carrier — some rewrite the originator for routing reasons.
2. Confirm messages arrive from the numbers registered to the campaign, presented as themselves.
3. Where a substitution is genuinely needed, arrange it with the provider in advance rather than configuring it.

*What wrong looks like:* A routing layer substitutes the originator without anybody choosing it. Sender identity is the only thing a recipient can judge a message by, and the sender is accountable for the result either way.

### Notes

Wire-level behaviour. What the user has to confirm is that no part of their stack rewrites the originator — some aggregation layers do it for routing reasons, and the sender is accountable for the result either way.

---

## OPS-154 — Where the numbers came from matters

> Volume must not originate from SIM boxes, SIM farms, or disposable, rental or temporary telephone numbers.

- **Rule ID:** OPS-154
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `originating number provenance`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **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/operational/ops-154/

### Why this rule exists

These are the origination methods that exist to be untraceable, so their presence is treated as evidence about the sender rather than about the traffic. The industry watches for ten or more activations by one party in a short window and a single location, which means a legitimate business scaling quickly through the wrong supplier can trip a fraud signal it never knew existed.

### How to fix it

Provision numbers through a licensed carrier or CPaaS in the brand's own name, and keep the assignment records. Refuse any supplier that cannot say who the numbers are registered to.

### Check this yourself

**Who are your sending numbers registered to, and how were they obtained?**

1. Get the assignment records from whoever provisioned them.
2. Refuse any supplier that cannot say who the numbers are registered to — that answer is the whole check.
3. Provision through a licensed carrier or CPaaS in the brand's own name.

*What wrong looks like:* Ten or more activations by one party in a short window from a single location is the industry's fraud signature. A legitimate business scaling quickly through the wrong supplier trips it without ever knowing it existed.

### Notes

Provenance held by whoever assigned the numbers. What the user has to establish is exactly that — who the numbers are registered to and how they were obtained — before volume makes the question urgent. OPS-021 is the ownership-documentation half.

---

## OPS-155 — Sending through a provider you have no relationship with is a red flag

> A message sender with no business relationship with the CPaaS or wireless provider carrying its traffic must be treated as a compromised-system indicator.

- **Rule ID:** OPS-155
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `the contractual chain behind the traffic`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** External record we cannot query — reported as a warning to verify
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-155/

### Why this rule exists

Every legitimate sender has a contract with somebody in the chain. Traffic arriving without one usually means compromised API credentials or a resold account, and the industry treats it as a compromise signal rather than as an unusual commercial arrangement — so a brand whose traffic reaches a carrier through an intermediary it has never heard of is indistinguishable from a breach.

### How to fix it

Know every party in your sending chain and hold a contract with the one you send through. Done when you can name the provider, the aggregator and the terminating carrier for your own traffic.

### Check this yourself

**Can you name the provider, the aggregator and the terminating carrier for your own traffic — and do you hold a contract with the one you send through?**

1. Map the chain end to end. Resold accounts and white-labelled platforms make this genuinely unclear, and unclear is the state this rule is about.
2. Confirm there is a contract with the party you send through.

*What wrong looks like:* Traffic reaching a carrier through an intermediary you have never heard of is indistinguishable from compromised API credentials, and it is treated as a compromise signal rather than as an unusual commercial arrangement.

### Notes

A commercial fact outside the registration. What the user has to do is map their own chain — resold accounts and white-labelled platforms make this genuinely unclear, and unclear is the state this rule is about.

---

## OPS-156 — Watch for traffic that is being pumped

> Content and traffic patterns consistent with artificially inflated traffic must be detected and rejected.

- **Rule ID:** OPS-156
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `traffic pattern and destination distribution`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** Twilio, Telnyx
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-156/

### Why this rule exists

Artificially inflated traffic is fraud committed through your account rather than by you: an attacker drives OTP or verification sends to number ranges that pay them a share of the termination fee, and the bill is yours. The signature is a destination distribution that does not look like your customers — sudden concentration in unusual ranges or countries — and it costs real money for as long as nobody is watching.

### How to fix it

Rate-limit verification and OTP endpoints per source, alarm on shifts in destination distribution, and cap spend per hour so a pumping attack is bounded. Done when an unexpected concentration of destinations pages somebody within the hour.

### Common mistakes

- A CAPTCHA on the form does not stop this — the attack drives the API behind it, so the control has to sit at the send.

### Check this yourself

**Is there a spend cap and a destination-distribution alarm on every endpoint a stranger can trigger?**

1. List the endpoints that send without a logged-in user — verification and OTP are the usual ones.
2. Rate-limit per source, cap spend per hour, and alarm on shifts in destination distribution.
3. A CAPTCHA on the form does not stop this: the attack drives the API behind it, so the control has to sit at the send.

*What wrong looks like:* An attacker drives OTP sends to number ranges that pay them a share of the termination fee. It is fraud committed through your account rather than by you, the bill is yours, and the exposure is unbounded until a cap exists.

### Notes

A pattern in live traffic. What the user has to do is put a spend cap and a distribution alarm on any endpoint a stranger can trigger, because the exposure is unbounded until one exists.

---

## OPS-157 — A provider can block anything its risk assessment dislikes

> Service providers may block any message a reasonable risk assessment suggests is unwanted, and the triggers include compromised credentials, grey routes, missing authentication and a pattern of abusing best practices.

- **Rule ID:** OPS-157
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `overall sending posture`
- **Severity:** HIGH — Rejected by at least one carrier or provider, and a common cause of failure at the rest.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** CTIA, all service providers
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-157/

### Why this rule exists

This is the discretion behind every other rule in the folder, and it matters because it is not appealable in the way a rejection is: the traffic simply stops. Understanding that the assessment looks at posture rather than at individual messages is what makes the rest of the family worth acting on before anything goes wrong.

### How to fix it

Treat the posture as the thing being judged: authenticated sending, one static route, credentials under control, complaint and opt-out rates monitored. Done when nothing about your traffic requires explaining.

### Check this yourself

**Do you know who to call at your provider before traffic is blocked, rather than after?**

1. Get the name and escalation path now. There is no threshold to comply with here — the assessment looks at posture, not at individual messages, and the traffic simply stops.
2. Work the posture instead: authenticated sending, one static route, credentials under control, complaint and opt-out rates monitored.
3. Done when nothing about your traffic requires explaining.

*What wrong looks like:* Not appealable in the way a rejection is. Delivery stops, no code explains it, and the conversation starts from scratch with somebody you have never spoken to.

### Notes

A judgement made by somebody else about traffic we cannot see. What the user has to accept is that there is no threshold to comply with here — the mitigation is the rest of this folder, and the practical step is knowing who to call at the provider before it happens.

---

## OPS-159 — A registered campaign must expect to carry traffic

> A campaign should be registered only when it will actually send; sustained inactivity triggers dormancy suspension.

- **Rule ID:** OPS-159
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.description`
- **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, T-Mobile
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-159/

### Why this rule exists

Registering ahead of a programme that does not exist yet wastes a non-refundable vetting fee and risks a dormancy suspension after roughly two weeks of silence. It also produces the empty-shell registrations that make reviewers stricter with everyone.

### How to fix it

Register when you have subscribers and a send schedule. If the programme is seasonal, plan at least occasional traffic to avoid dormancy suspension.

### Example of a compliant value

```text
Weekly promotional sends beginning the week of approval.
```

---

## OPS-161 — Campaign auto-renewal must be set deliberately

> The autoRenewal setting must be chosen deliberately — true renews monthly, false deactivates at cycle end.

- **Rule ID:** OPS-161
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.auto_renewal`
- **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
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-161/

### Why this rule exists

Left unconsidered, this setting either bills you monthly forever or silently deactivates a live campaign at the end of its cycle, taking your traffic down with no rejection to explain it. It is one of the few settings whose default choice has an ongoing cost either way.

### How to fix it

Set auto-renewal true for an ongoing programme so it does not deactivate mid-flight, and false only for a genuinely time-boxed campaign you intend to end.

### Example of a compliant value

```text
Ongoing marketing programme → autoRenewal: true.
```

---

## OPS-180 — Approved samples do not license prohibited content

> Prohibited content must not appear in live traffic regardless of what the approved samples showed.

- **Rule ID:** OPS-180
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `live message content`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** T-Mobile, AT&T, CTIA, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-180/

### Why this rule exists

Approval is granted against the samples, and operators read it as approval of the campaign — so a programme whose samples were clean starts sending content the category prohibits, on the basis that the campaign was approved. Carriers scan live traffic, and a violation there is enforced against the account rather than the campaign.

### How to fix it

Apply the prohibited-content rules to every template before it goes live, not only to the ones submitted for registration. Treat the registered samples as examples of a standard rather than as the extent of it.

### Check this yourself

**Is there a review step that applies the prohibited-content rules to new templates, not just to the ones submitted for registration?**

1. Find the step. Approval was granted against the samples, and operators read it as approval of the campaign.
2. Apply the MESSAGE_CONTENT prohibited-content categories to every template before it goes live.
3. Treat the registered samples as examples of a standard rather than as the extent of it.

*What wrong looks like:* A programme whose samples were clean starts sending content the category prohibits, on the basis that the campaign was approved. Carriers scan live traffic and enforce against the account rather than the campaign.

### Notes

Live content we never see. What the user has to put in place is a review step on new templates — the MESSAGE_CONTENT prohibited-content family states the categories, and this rule is the reminder that approval did not exempt anything from them.

---

## OPS-199 — Consent records must capture all seven required fields

> The programme must retain a consent record holding the number, timestamp, medium, a capture of the consent experience, the campaign, an IP or call identifier, and the consenting party.

- **Rule ID:** OPS-199
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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, FCC, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-199/

### Why this rule exists

CTIA enumerates these seven fields specifically, and the reason is evidentiary: when a complaint arrives eighteen months later, "opted in: true" proves nothing about what the consumer actually agreed to. The capture-of-experience field is the one almost everybody omits, and it is the one that matters most — it is the only record of the wording shown at the moment of consent.

### How to fix it

Store all seven fields per opt-in, and version the disclosure text so you can reproduce exactly what a given consumer saw. Describe this in the message flow — a reviewer treats an undescribed record-keeping practice as an absent one.

### Example of a compliant value

```text
For each opt-in we store: phone number, UTC timestamp, acquisition medium, the versioned disclosure text shown, the campaign, the originating IP (or call ID for phone consent), and the account or session identity that consented.
```

### Common mistakes

- Storing a boolean flag with a date is the most common shortfall — it cannot answer "what did they agree to?".

---

## OPS-201 — The consent experience itself must be versioned and retained

> A capture of the exact language and action used to secure consent must be retained and versioned per consumer.

- **Rule ID:** OPS-201
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `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:** CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-201/

### Why this rule exists

Disclosure wording changes over time, so a single current screenshot cannot evidence a consent given two revisions ago. Versioning is what lets you answer which text a specific consumer saw, and it is the only defence when the wording has since improved.

### How to fix it

Version the disclosure text and store the version identifier on each consent record, so any past consent can be replayed exactly as the consumer saw it.

### Example of a compliant value

```text
Each opt-in stores disclosure_version=2026-03-a alongside the timestamp; we retain the full text of every version.
```

---

## OPS-204 — Verbal consent records must substitute a call identifier for the IP address

> Where consent was verbal or via IVR, a call identifier must replace the IP-address field in the consent record.

- **Rule ID:** OPS-204
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow`
- **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, FCC
- **Applies:** Applies when consent was collected by live verbal and IVR.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-204/

### Why this rule exists

The IP field is meaningless for phone consent, and leaving it empty produces a record that looks incomplete rather than method-appropriate. A call ID, recording ID, or agent identifier is the equivalent evidence and is what a reviewer expects for that method.

### How to fix it

Store a call ID, recording ID, or agent extension on verbal consent records in place of the IP address, and say so in the message flow.

### Example of a compliant value

```text
Verbal opt-ins store the call UCID, the agent ID, and the script version read, in place of an IP address.
```

---

## OPS-207 — The consent record must name the page the opt-in came from

> Every consent record must carry the source URL of the consent surface.

- **Rule ID:** OPS-207
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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, Telnyx
- **Applies:** Applies when consent was collected by web form, checkout, account settings, third party, chat, social, email and QR code.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-207/

### Why this rule exists

A brand usually has several places a consumer can opt in — a footer form, a checkout box, a landing page for one campaign — and they carry different disclosure wording. Storing only "web" makes every one of those records identical, so when a reviewer asks which page a specific consumer used, nobody can answer. The innocent cause is that the form posts to one endpoint, and the endpoint records itself rather than the page that called it.

### How to fix it

Store the full URL of the page the opt-in was submitted from — path and query included — on each consent record, and describe that in the message flow. Done when you can take any consent record and open the exact page that produced it.

### Example of a compliant value

```text
Each opt-in stores source_url: https://acmecoffee.com/signup?src=instore-qr, alongside the timestamp and IP.
```

### Common mistakes

- Storing the form-handler endpoint rather than the referring page produces one URL for every record, which is the same failure with a longer string in it.

### Notes

Registration-side twin: we judge whether the programme describes storing the field, never whether the stored record exists.

---

## OPS-208 — The consent record should carry the browser user agent

> Every consent record must carry the device or browser user agent behind the submission.

- **Rule ID:** OPS-208
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** CTIA, mytcrplus
- **Applies:** Applies when consent was collected by web form, checkout, account settings, third party, chat, social, email and QR code.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-208/

### Why this rule exists

When a consumer says they never filled in the form, the IP and timestamp establish that something was submitted and nothing more. The user agent is the one field on the record that speaks to how it was submitted — a real browser on a phone reads differently from a scripted post — and it is free to capture, since the header arrives with every request.

### How to fix it

Capture the User-Agent header alongside the IP address at submission and store it on the consent record. Done when a record shows the browser and device as well as the address it came from.

### Example of a compliant value

```text
Each web opt-in stores user_agent: "Mozilla/5.0 (iPhone; CPU iPhone OS 18_2 like Mac OS X) …" beside the IP.
```

### Notes

Registration-side twin: we judge whether the programme describes storing the field, never whether the stored record exists.

---

## OPS-209 — The consent record must say which act gave consent

> Every consent record must carry the confirmation method used — a ticked box, a click, or a replied keyword.

- **Rule ID:** OPS-209
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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, mytcrplus
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-209/

### Why this rule exists

Two records can agree on number, timestamp and campaign and still describe completely different events: one consumer ticked an unchecked box, another replied YES to a text, a third was added by an agent. Those are not equally strong evidence, and a record that does not say which act happened cannot be graded — which is exactly the moment, months later, when it needs to be.

### How to fix it

Store the specific act on each record — checkbox, button click, SMS reply, keypress, agent entry — rather than a boolean. Done when reading one record tells you what the consumer physically did.

### Example of a compliant value

```text
Each opt-in stores confirmation_method: checkbox_ticked (or sms_reply_yes for double opt-ins).
```

### Notes

Registration-side twin: we judge whether the programme describes storing the field, never whether the stored record exists.

---

## OPS-210 — Telemarketing consent must retain the request, its purpose and the answer

> Where the Telemarketing Sales Rule applies, the programme must retain the consent request as it was presented, the purpose consent was sought for, and the consent actually given with its date and the consenting party.

- **Rule ID:** OPS-210
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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:** FTC
- **Applies:** Applies when the use case is MARKETING, MIXED, SWEEPSTAKE and LOW_VOLUME.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-210/

### Why this rule exists

The TSR is stricter than the carrier framework and is enforced by a different body, so a brand can satisfy every 10DLC requirement and still be exposed. What it adds is the request: the FTC wants the ask preserved in the same form the consumer met it, because a permissive record of the answer says nothing about what the question was. The rule also settles a common shortcut explicitly — an IP address plus a timestamp is not a record of consent.

### How to fix it

Retain three things per consumer: a copy of the consent request in the format it was presented, the purpose it was sought for, and the consent given with its date, the consenting person and their number. Done when a record answers "what were they asked, what for, and what did they say" without anybody reconstructing it.

### Example of a compliant value

```text
Each marketing opt-in stores: the rendered disclosure as shown (disclosure_version 2026-03-a), purpose="recurring promotional offers from Acme Coffee", and the consent event — 2026-03-04, Jane Doe, +1 415-555-0134, checkbox ticked.
```

### Common mistakes

- Storing the current disclosure text rather than the version shown at the time satisfies neither half — the request must be the one that consumer met.

### Notes

Absorbs OPS-211 (purpose), OPS-212 (the consent, date, name and number) and OPS-213, which states the sufficiency test rather than a fourth field. Tagged to the marketing-style use cases because the TSR reaches telemarketing; a transactional programme outside its scope is not failed for the absence.

---

## OPS-214 — Telemarketing consent taken by phone must retain the recording of both halves

> Where the Telemarketing Sales Rule applies and consent was spoken, a recording of both the request and the consent given must be retained, making the purpose clear.

- **Rule ID:** OPS-214
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `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:** Supply evidence only you hold
- **Required by:** FTC
- **Applies:** Applies when consent was collected by live verbal and IVR, and the use case is MARKETING, MIXED, SWEEPSTAKE and LOW_VOLUME.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-214/

### Why this rule exists

A recording that starts at "do you agree?" preserves the answer and loses the question, which is the half the FTC actually cares about — it is where the purpose is stated and where a leading or truncated ask would show. Contact centres cut it this way because the recording is triggered by the consent step rather than covering the disclosure that precedes it.

### How to fix it

Record the disclosure and the answer as one continuous recording, and retain it against the consumer record. Done when playing a single recording gives you the purpose, the ask and the agreement without a second file.

### Example of a compliant value

```text
Verbal marketing opt-ins retain one recording per consent covering the full disclosure and the consumer's answer, indexed by call UCID.
```

### Common mistakes

- Starting the recording at the consent question is the common configuration and it is the failure: the purpose is stated in the sentence before it.

### Notes

Where recording is not possible — the consumer declines, or an all-party-consent state applies — OPS-239 describes the fallback the programme must have instead. This rule is about what is retained, not about whether a recording satisfies the written-consent standard, which is CON-156.

---

## OPS-215 — Express written consent must name the specific number and bear a signature

> The retained consent agreement must identify the specific telephone number consented for and bear the consumer's signature.

- **Rule ID:** OPS-215
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `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:** FCC
- **Applies:** Applies when the use case is MARKETING, MIXED, SWEEPSTAKE and LOW_VOLUME.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-215/

### Why this rule exists

TCPA express written consent is a signed agreement naming the number, and an electronic signature under E-SIGN qualifies — a ticked box with a stored identity and timestamp satisfies it. What does not satisfy it is a record that cannot tie a signature to a specific number.

### How to fix it

Ensure the consent record ties an identifiable signature — including an E-SIGN electronic one — to the specific number, and describe that linkage in the message flow.

### Example of a compliant value

```text
The checkbox action, the entered phone number, the consenting account identity and the timestamp are stored together as the signed agreement.
```

---

## OPS-217 — Consent must be tracked per consumer, not per list

> Consent must be recorded against the individual consumer rather than at list level.

- **Rule ID:** OPS-217
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `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:** CTIA, FCC, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-217/

### Why this rule exists

List-level consent cannot answer whether a specific person agreed, which is the only question that matters in a complaint. It is also structurally how purchased lists get laundered into a programme — a list marked "consented" with no per-number provenance.

### How to fix it

Record consent per phone number with its own timestamp and source, never as a property of a list or segment.

### Example of a compliant value

```text
Each number carries its own consent timestamp, medium and disclosure version.
```

---

## OPS-219 — Opt-out records must be retained alongside opt-ins

> Revocation requests must be retained for the same period as opt-ins, with the channel recorded.

- **Rule ID:** OPS-219
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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, FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-219/

### Why this rule exists

Proving someone opted in is only half the defence — the other half is proving you stopped when they asked, and when. Revocations arrive by text, call and email, so the channel matters: a revocation taken by a phone agent must reach the same suppression list as a texted STOP.

### How to fix it

Retain revocations for the same period as consents, record the channel each arrived on, and route revocations captured by agents or IVR into the same suppression list as texted opt-outs.

### Example of a compliant value

```text
Opt-outs are stored with the number, timestamp, and channel (SMS, phone, email), retained for four years alongside consent records.
```

---

## OPS-221 — The retention period must clear the longest window that applies

> The stated retention period for consent and opt-out records must be the maximum of every applicable window, not the first one the brand found.

- **Rule ID:** OPS-221
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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:** FTC, FCC, CTIA, state law
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-221/

### Why this rule exists

Five separate floors sit under this, set by five different bodies: the telemarketing rule's five years, the four-year TCPA limitation period, the five-year internal do-not-call floor, the short-code handbook's opt-in-until-six-months-after-opt-out, and any longer state rule — Virginia sets ten years for suppression records. They are not alternatives. A brand that reads one source and retains for the period it names is under-retained against the others, and finds out when a claim arrives in year four against records deleted in year two.

### How to fix it

Set one retention period for consent and opt-out records at the longest window that reaches you, and state that period rather than a rule reference. Five years clears the telemarketing rule, the TCPA limitation period and the short-code floor together; check whether a state you message into is longer. Done when the stated number is a single figure you can defend against every source above.

### Example of a compliant value

```text
We retain consent and opt-out records for five years from the last message sent in reliance on that consent.
```

### Common mistakes

- Citing an authority instead of a number ("we retain records as required by law") leaves the period undefined, and an undefined period is administered by whichever system deletes first.

### Notes

Absorbs OPS-222 (four-year TCPA), OPS-059 (the five-year internal do-not-call floor), OPS-224 (short-code opt-in and opt-out floors), OPS-225 (the resolution rule itself), and the state rows OPS-060 and OPS-226. They are inputs to one resolver, and implementing any one alone under-retains — which is why they are one rule rather than six. Only the retention half of OPS-059 and OPS-060 is settled here; honouring a suppression record is runtime behaviour and is not claimed. The state check needs a jurisdiction we do not hold, so the criteria ask the model to report it as a residual rather than settle it.

---

## OPS-223 — The retention clock starts at the last message, not the opt-in

> The retention period must be measured from the last message sent in reliance on the consent, not from the date the consent was collected.

- **Rule ID:** OPS-223
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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:** FCC, PossibleNOW
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-223/

### Why this rule exists

A limitation period runs from the act complained of, which is a message, not a signup. Anchoring at collection shortens every window by the life of the subscription: a consumer who opted in five years ago and was messaged last month has a record that a collection-anchored policy deleted years before the message that will be complained about. It is a one-line difference in a retention policy and almost nobody writes it deliberately.

### How to fix it

Write the anchor into the retention sentence: measure from the last message sent in reliance on that consent, and re-arm the clock on every send. Done when a long-standing subscriber's record survives as long after their most recent message as a new subscriber's does after their first.

### Example of a compliant value

```text
Consent records are retained for five years from the last message sent in reliance on that consent.
```

---

## OPS-232 — A spoken opt-in needs a per-consumer artifact, not just a script

> Verbal consent must be evidenced per consumer by a recording, a transcript, or documented contemporaneous notes — never by the script alone.

- **Rule ID:** OPS-232
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `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:** FTC, practice
- **Applies:** Applies when consent was collected by live verbal and IVR.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-232/

### Why this rule exists

The script proves what the programme intends to say. It is silent about any particular call, so a brand holding only a script has one document and no evidence, and finds that out when a single complaint asks about a single consumer. The transcript or the note is the substitute a reviewer accepts when a recording does not exist, which is why the rule names three acceptable forms rather than demanding audio.

### How to fix it

Name in the message flow which artifact is kept per consumer — recording, transcript, or a contemporaneous CRM note carrying the verbatim assent — and keep it against the number. Done when the flow says what exists for one named consumer, not what the agents are told to say.

### Example of a compliant value

```text
Each phone opt-in retains the call recording; where the consumer declines recording, the agent stores the verbatim assent and the script version in the CRM against the number.
```

### Notes

Absorbs OPS-234, which states the transcript fallback inside the same record requirement. Whether a recording can stand as WRITTEN consent for a marketing programme is a different question and is judged by CON-156; this rule asks only whether any per-consumer artifact exists.

---

## OPS-233 — A spoken consent record must name the agent who took it

> Every consent record must carry the identifier of the agent who read the consent script.

- **Rule ID:** OPS-233
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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:** FTC, practice
- **Applies:** Applies when consent was collected by live verbal.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-233/

### Why this rule exists

A verbal opt-in has no artifact the consumer touched, so the whole evidentiary weight sits on the call. Naming the agent is what makes the record investigable: it is how a brand finds out that one agent has been paraphrasing the script, and how it shows a regulator that it looked. Contact centres omit it because the CRM records the account owner rather than whoever was on the call.

### How to fix it

Store the agent identifier — the login, extension or badge number of the person who read the script — on each verbal consent record. Done when any consent record names a specific person, not a team or a queue.

### Example of a compliant value

```text
Verbal opt-ins store agent_id: acme-cs-0142 with the call UCID and the script version read.
```

### Notes

Registration-side twin: we judge whether the programme describes storing the field, never whether the stored record exists.

---

## OPS-235 — A spoken consent record must pin the script version that was read

> Every consent record must carry the version and effective date of the consent script read to the consumer.

- **Rule ID:** OPS-235
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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:** FTC, CTIA, practice
- **Applies:** Applies when consent was collected by live verbal, IVR and point of sale.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-235/

### Why this rule exists

Scripts get improved, and every improvement makes the previous wording unprovable unless the record says which one was in force. This is the verbal twin of the capture-of-experience field, and it is the difference between "our script says X" — which a regulator reads as what you say today — and "this consumer heard version 3, effective 12 January". Brands miss it because the script lives in a document nobody versions.

### How to fix it

Version the consent script, give each version an effective date, and store the version identifier on every consent taken while it was live. Done when you can pick any past consent and reproduce the exact words that consumer heard.

### Example of a compliant value

```text
Verbal opt-ins store script_version: 2026-03-a (effective 2026-03-01) with the agent ID and call UCID.
```

### Common mistakes

- Attaching the current script to the registration proves what is read today. It is silent about the consents already taken, which are the ones a complaint will be about.

### Notes

Registration-side twin: we judge whether the programme describes storing the field, never whether the stored record exists.

---

## OPS-236 — An IVR opt-in must log the prompt, the keypress, the time and the call

> Every consent record must carry the prompt version played, the digit or spoken answer captured, the timestamp and the call identifier.

- **Rule ID:** OPS-236
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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:** FTC, CTIA, practice
- **Applies:** Applies when consent was collected by IVR.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-236/

### Why this rule exists

An IVR consent leaves no human witness on either side, so the log is the entire record — and unlike a live agent, an IVR can be misconfigured to accept any keypress as agreement and will do it identically to everyone who calls. All four fields are needed together: the prompt says what was asked, the captured input says what was answered, and the call identifier is what ties the pair to a person.

### How to fix it

Log all four values on every IVR consent: the prompt version played, the DTMF digit or recognised phrase captured, the timestamp, and the call identifier. Done when one log line lets you replay what was asked and what was pressed.

### Example of a compliant value

```text
IVR opt-ins log: prompt_version=ivr-optin-v4, captured_input=DTMF 1, captured_at=2026-03-04T14:22:11Z, call_id=UCID-88213004.
```

### Notes

Registration-side twin of a runtime log. We judge the description of the log, never the log. The four elements are one record judged in one pass rather than four rules, because they fail together: a log missing any one of them cannot reconstruct a single consent.

---

## OPS-239 — Declining to be recorded must not block the opt-in

> A programme taking spoken consent must have a documented no-recording evidence path, and must never refuse a consumer the opt-in because they declined recording.

- **Rule ID:** OPS-239
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `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:** FTC, practice
- **Applies:** Applies when consent was collected by live verbal.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-239/

### Why this rule exists

Recording is not always available — the consumer says no, or the call crosses into an all-party-consent state — and a contact centre with no fallback does one of two harmful things: it drops the opt-in the consumer asked for, or it takes it with no evidence at all. Both are avoidable with an attestation that carries the agent, the timestamp and the script version, which is what reviewers accept in place of audio.

### How to fix it

Describe the fallback: a contemporaneous CRM attestation carrying the agent ID, the timestamp, the script version and the consumer's verbatim assent. Done when the flow says what happens when a consumer declines recording, and the answer is not "we cannot enrol them".

### Example of a compliant value

```text
If the consumer declines recording, the agent stores the verbatim assent, agent ID, timestamp and script version in the CRM; the opt-in proceeds on that record.
```

### Common mistakes

- A fallback that only records "consent given: yes" is the same evidentiary gap the recording was there to close.

---

## OPS-240 — Recordings must outlive the consent records they evidence

> Call recordings must be retained at least as long as the consent records they are the evidence for.

- **Rule ID:** OPS-240
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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:** FTC, CTIA, practice
- **Applies:** Applies when consent was collected by live verbal and IVR.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-240/

### Why this rule exists

Recording retention is usually set by the telephony platform for quality-monitoring reasons — thirty or ninety days is a common default — while consent records are kept for years. The result is a consent record that points at a recording which was deleted long before anyone asked for it, and nobody notices because both systems are behaving exactly as configured.

### How to fix it

Raise the recording retention on the telephony platform to match the consent retention window, or export the consent calls into the consent store. Done when the recording retention setting is at least as long as the period stated for consent records.

### Example of a compliant value

```text
Consent-call recordings are retained for four years, matching the consent-record retention period.
```

### Common mistakes

- A blanket increase across every call is expensive and usually unnecessary — tag the consent calls and retain those, rather than the whole queue.

---

## OPS-251 — Consent left unused for a month must be reconfirmed

> Where no message is sent within 30 days of collecting consent, the programme must reconfirm by double opt-in before its first send.

- **Rule ID:** OPS-251
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `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:** T-Mobile, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-251/

### Why this rule exists

A consumer who signed up and heard nothing for a month has usually forgotten, changed number, or moved on, and the first message they eventually get reads as unsolicited — which is how it gets reported. The 30-day rule exists because that first message is also the one most likely to arrive at a reassigned number. Programmes hit it by launching a signup form months before the messaging goes live, which is the ordinary way to build a list and the exact shape the rule is about.

### How to fix it

Describe the reconfirmation: numbers with no message inside 30 days of opt-in receive a single confirmation asking them to reply YES, and are not messaged further until they do. Done when the flow says what happens to a signup that goes unmessaged for a month.

### Example of a compliant value

```text
Numbers not messaged within 30 days of opt-in are sent one reconfirmation ("Reply YES to confirm you still want Acme Coffee texts") and receive nothing further unless they reply.
```

### Common mistakes

- Sending the delayed first message with an opt-out line attached is not reconfirmation — the consumer is being messaged on stale consent, and the opt-out arrives after the message they did not expect.

### Notes

Registration-side twin: whether the 30-day clock is honoured is runtime behaviour. What is decidable now is whether the programme has a rule for the case, which matters most for a list built before launch.

---

## OPS-252 — Consent collected away from the handset should be confirmed on it

> Where consent is collected outside the SMS channel — web, phone, point of sale or paper — the programme should send a double opt-in confirmation before recurring messages.

- **Rule ID:** OPS-252
- **Layer:** Operational (`OPERATIONAL`)
- **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:** T-Mobile, CTIA
- **Applies:** Applies when consent was NOT collected by text-to-join keyword.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-252/

### Why this rule exists

Off-channel opt-ins are the ones where the number can be wrong: mistyped on a form, misheard on a call, or written illegibly on a card. A confirmation text is the only step that proves the number reached the person who agreed, and it converts a typo from a stranger receiving your marketing into a message nobody answers. It is also what a carrier looks for when a programme built from paper forms starts generating complaints.

### How to fix it

Send one confirmation to the number as collected, asking for a reply to activate, and enrol only on that reply. Where a full double opt-in is not workable, at minimum send a single confirmation that names the brand and how to stop before any other message. Done when the flow says what the number receives first.

### Example of a compliant value

```text
After a checkout opt-in we text: "Acme Coffee: reply YES to confirm you want offers and order updates. Msg&data rates may apply. Reply STOP to cancel." Numbers are enrolled only on YES.
```

### Notes

Not tagged away from paper, point-of-sale or verbal methods — those are the cases it exists for. It is excluded only where consent arrived on the handset itself, as an SMS keyword, since the number is already proven there.

---

## OPS-256 — A recurring programme should expire consent that has gone quiet

> A recurring programme should describe expiring an opt-in after a long period of subscriber inactivity, with one final notification permitted.

- **Rule ID:** OPS-256
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow`
- **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, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-256/

### Why this rule exists

A subscriber list that only grows eventually consists mostly of numbers that have changed hands, and every one of those is an unconsented message waiting to be sent. Expiry is the cheap version of the reassigned-number problem: it removes the numbers nobody has heard from, which is the same population, without a database lookup. Brands resist it because it shrinks a number they report on.

### How to fix it

State an inactivity window after which an opt-in expires — eighteen months is the published figure — and describe the single final message that may be sent before removal. Done when the flow says what happens to a subscriber who never engages.

### Example of a compliant value

```text
Subscribers with no engagement for 18 months receive one final notice and are then removed from the programme.
```

### Notes

Registration-side twin: the expiry job runs long after approval. What we judge is whether the programme has a policy for it, which is the part a reviewer can also see.

---

## OPS-261 — Only the charity may use the numbers a charity collects

> A charitable programme must let no entity other than the charity use the collected subscriber data, and only for the campaign it was collected for.

- **Rule ID:** OPS-261
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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/operational/ops-261/

### Why this rule exists

Charitable messaging gets favourable treatment because donors are giving to a cause, not entering a marketing relationship — and the data is unusually valuable precisely because it identifies people who give. The restriction is absolute for that reason: no agency, no fundraising partner, no affiliated foundation. It is broken innocently when the campaign is run by an agency whose own platform holds the list.

### How to fix it

State that subscriber data collected by the programme is used only by the charity and only for this campaign, and that no partner, agency or affiliate uses any part of it. Where an agency operates the sending, say it processes the data for the charity and holds no independent right to it. Done when the flow and the policy agree that the charity is the only user.

### Example of a compliant value

```text
Numbers collected by Riverside Shelter's text programme are used only by Riverside Shelter and only for this campaign; our messaging agency processes them on our behalf and may not use them for anything else.
```

### Common mistakes

- Naming an agency as a joint controller, or a parent foundation as a permitted recipient, breaks the restriction even where both are non-profits.

---

## OPS-292 — Evidence screenshots must say when and where they were taken

> Every submitted evidence image must carry its capture timestamp, the source URL, and enough provenance to tie it to the live surface.

- **Rule ID:** OPS-292
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.consent_artifact[]`
- **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:** Supply evidence only you hold
- **Required by:** CTIA, researcher recommendation
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-292/

### Why this rule exists

A screenshot with no provenance is a picture of a form, and a reviewer cannot tell whether it is the live page, a staging build, or a mock-up made for the submission — so the cautious ones reject it and the rest approve something they did not verify. Adding the URL and the date costs one line in the upload and turns the image into evidence, which is the difference the brand is actually being asked for.

### How to fix it

Capture the browser address bar in the screenshot, or caption each image with the full URL and the capture date where the surface is not a web page. Done when the image alone tells a reviewer which page it is and when it was taken.

### Example of a compliant value

```text
Screenshot filename optin-signup-2026-03-04.png, captioned "https://acmecoffee.com/signup — captured 4 March 2026, 1440×900", with the address bar visible in the image.
```

### Common mistakes

- Cropping to the consent block removes the address bar, which is usually the only provenance the image had.

---

## OPS-323 — An identity appeal has a window, and it runs from brand creation

> An identity-status appeal must be submitted within 45 calendar days of the brand being created, not of the decision being received.

- **Rule ID:** OPS-323
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `brand appeal submission vs brand creation date`
- **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:** Not knowable before submission — reported with its deadline
- **Fix type:** Wait on an external system or a required interval
- **Required by:** TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-323/

### Why this rule exists

The clock is the surprising part: it starts when the brand record is created, so a registration that sat in review for three weeks and was refused has already spent most of its appeal window before anybody saw the refusal. Teams plan the appeal around the rejection date, gather the CP-575, and file after the window shut — at which point the only route left is a new brand and a second set of fees.

### How to fix it

Diarise the appeal deadline as 45 days from the day the brand was created, and gather the federal tax documentation while the review is still running rather than after a refusal. Done when the appeal is filed inside that window, with every page of the CP-575 or 147C attached.

### Check this yourself

**What date was this brand created, and is today inside the 45 days that run from it?**

1. Look the brand's creation date up in the registry console — not the date of the refusal, which is what everyone plans around.
2. Add 45 calendar days and compare that to today.
3. Gather the federal tax documentation while the review is still running, so an appeal can be filed the day a refusal lands.

*What wrong looks like:* A registration sat in review for three weeks and was refused, so most of the appeal window was spent before anyone saw the decision. Filing late leaves only a new brand and a second set of fees.

### Notes

Not decidable here: no submitted field carries the brand creation date, so the registry cannot compute the deadline. Surfaced as a warning with the check the user has to run themselves — look up the brand's creation date in the registry console, add 45 days, and compare that to today before planning any appeal. BRD-260 and BRD-258 cover what the appeal must contain once you are inside the window.

---

## OPS-324 — An appeal is void if you edit the identity you are appealing

> Legal name, entity type, tax ID and tax ID issuing country must not be updated before an appeal is filed, and no brand update may be submitted while one is in flight.

- **Rule ID:** OPS-324
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `brand.appeal + brand.brand_changes`
- **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
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-324/

### Why this rule exists

An appeal argues that the registry got the existing record wrong, so editing that record first removes the thing being argued about — the registry treats the brand as a fresh claim and refuses the appeal, and the appeal window keeps running. The instinct after a rejection is to fix the data and appeal in the same sitting, which is the exact order that destroys the appeal: resubmitting corrected data and appealing an unchanged record are two different remedies and you get to use one.

### How to fix it

Decide first which remedy applies: resubmit when the data was wrong, appeal when the data is right and the decision is not. If you are appealing, leave legal name, entity type, tax ID and issuing country exactly as submitted until the appeal completes. Done when the appeal is filed against a record that has not been touched since the decision.

### Example of a compliant value

```text
Appealing: brandChanges is empty — the record stays exactly as the registry refused it.
```

### Common mistakes

- The lock covers the appeal window as well as the moment before it: an update sent while the appeal is open is refused, and support cannot reopen it for you.

### Notes

Absorbs OPS-325, which states the during-appeal half of the same lock; the fix is identical for both. Distinct from BRD-044, which reports what an identity edit costs on any brand — this rule reports what it destroys on an appealing one, and only fires when an appeal is part of the submission.

---

## OPS-344 — A brand carrying live work cannot have its identity edited at all

> Legal name, entity type, tax ID and tax ID issuing country cannot be edited while the brand has an active campaign or a vet in progress.

- **Rule ID:** OPS-344
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `brand.brand_changes + brand.active_campaign_count + brand.vetting`
- **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
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-344/

### Why this rule exists

On a bare brand these four fields are expensive to change; on a brand with a campaign or a vet behind it they are not changeable at all, and the API refuses rather than queues. The reason is that both the campaign and the vet were granted against the identity as it stood, so changing it would leave live traffic authorised by a record that no longer exists. Teams meet this while correcting a typo that has been in the legal name since day one, and the refusal does not say which of the two blockers is in the way.

### How to fix it

Clear the blocker before the edit: deactivate the campaigns on the brand, or wait for the vet to reach a final state, then make the identity change and expect the brand to re-verify. Where the campaigns must stay live, register the corrected identity as a new brand and migrate rather than editing this one. Done when the brand has no active campaign and no vet in flight at the moment the edit is sent.

### Example of a compliant value

```text
Correcting the legal name: deactivate the one live campaign first, edit, re-verify, then re-register the campaign.
```

### Notes

BRD-044 reports what an identity edit costs on any brand — the fee, the reset, the expired vet. This rule reports the case where it is refused outright, which is a different answer and a different fix, so it fires only when a campaign or a vet is actually in the way.

---

## OPS-384 — Nothing goes out before the opt-in

> Messages may be sent only after the consumer has opted in; the single opt-out acknowledgement is the only permitted exception.

- **Rule ID:** OPS-384
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `send-time consent check`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Falls due after approval, once you are live and sending
- **How it is detected:** Not knowable before submission — reported with its deadline
- **Fix type:** Hard stop — not remediable, resubmission will not help
- **Required by:** CTIA, FCC, all MNOs
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-384/

### Why this rule exists

This is the obligation the whole framework exists to enforce, and it is worth stating separately because the failure is rarely a decision to send unsolicited messages — it is a list imported without provenance, a form that wrote consent before the box was ticked, or a test send to a colleague's number that went to the whole file. The consequence does not scale with the intent.

### How to fix it

Check consent at send time against a per-number record, never against list membership, and make an unconsented number impossible to include rather than unlikely.

### Check this yourself

**Does your send path check a per-number consent record, or does it check list membership?**

1. Trace one send to the thing it actually reads. Segments are built by people; consent records are not.
2. Make an unconsented number impossible to include rather than unlikely.
3. The single opt-out acknowledgement is the only message permitted without a prior opt-in.

*What wrong looks like:* A list imported without provenance, a form that wrote consent before the box was ticked, or a test send to a colleague that went to the whole file. The consequence does not scale with the intent.

### Notes

The runtime form of everything the CONSENT_FLOW layer checks at registration. What the user has to verify is that their send path reads a consent record rather than a segment — segments are built by people and consent records are not.

---

## OPS-385 — A referral programme must not pay people to forward messages

> Consumers who send viral or referral messages must receive nothing of value for doing so.

- **Rule ID:** OPS-385
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.description + campaign.message_flow + 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 to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-385/

### Why this rule exists

Paying for forwards turns the sender's friends into a purchased audience: the recipient gets a message from someone they trust, sent for a reward rather than because it was relevant, and there is no consent anywhere in the chain. It is the one part of referral marketing the industry prohibits outright, and it is easy to walk into — a discount for a successful invite is exactly the mechanic every growth playbook recommends.

### How to fix it

Remove the incentive from the forwarding step. Reward the new subscriber's own opt-in if you want a referral mechanic at all, and have the invitee opt in on your own surface rather than receiving a message the referrer triggered. Done when nothing of value depends on a consumer sending a message to somebody else.

### Example of a compliant value

```text
Share Acme Coffee with a friend — when they sign up at acmecoffee.com/join they get 20% off their first order. (The reward goes to the new customer, not to the referrer.)
```

### Common mistakes

- Sweepstake entries, loyalty points and account credit all count as something of value; the prohibition is not limited to cash.

### Notes

Applies only to viral and referral programmes, which the registration has no attribute for. The judge is told to PASS immediately where the campaign describes no forwarding mechanic, and this note records the carve-out the applicability model cannot express.

---

## OPS-FREQ-COHERENT — Declared frequency must be consistent everywhere it appears

> The message frequency stated in the consent disclosure, the SMS terms, and the campaign description must agree.

- **Rule ID:** OPS-FREQ-COHERENT
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `consent disclosure + terms + campaign.description`
- **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/operational/ops-freq-coherent/

### Why this rule exists

Frequency appears in at least three places, and each is written at a different time by a different person. A disclosure promising "up to 4 per month" beside terms saying "frequency varies" beside a description mentioning daily deals gives a reviewer three different programmes to choose between, and they choose the one that fails.

### How to fix it

Pick one frequency statement and use it verbatim in all three places. "Message frequency varies" is the safest when volume is irregular, because a numeric cap becomes a promise you are held to.

### Example of a compliant value

```text
All three read: "Message frequency varies."
```

---

## OPS-HELP-ONE-TIME — HELP must be supported even on one-time programmes

> HELP keyword support is required regardless of whether the programme sends recurring messages.

- **Rule ID:** OPS-HELP-ONE-TIME
- **Layer:** Operational (`OPERATIONAL`)
- **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
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-help-one-time/

### Why this rule exists

CTIA requires HELP to produce a response whether or not the requester is subscribed and whether or not the programme is a subscription. One-time programmes routinely omit it on the reasoning that there is nothing to unsubscribe from, which leaves a recipient unable to identify the sender at all.

### How to fix it

Declare HELP support and configure a reply, even for a single-message programme. The reply must name the brand and give a support route.

### Example of a compliant value

```text
Help keywords: HELP, INFO
```

---

## OPS-OPTOUT-CONF-ONLY — Opt-out confirmation must be the only message sent after revocation

> The campaign must declare a single opt-out confirmation and nothing further after a consumer revokes.

- **Rule ID:** OPS-OPTOUT-CONF-ONLY
- **Layer:** Operational (`OPERATIONAL`)
- **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:** FCC, CTIA, TCR
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-optout-conf-only/

### Why this rule exists

One final confirmation is permitted; anything after it is messaging someone who has revoked consent, which is both the clearest TCPA violation available and a carrier fee event. Declaring a confirmation is fine — declaring a follow-up sequence is a self-reported violation.

### How to fix it

Configure exactly one opt-out confirmation, keep it non-promotional, and make sure no other automation can fire at a revoked number afterwards.

### Example of a compliant value

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

---

## OPS-POOL-DECLARED — Number pooling must be declared consistently with the campaign scale

> The number-pool attribute must reflect whether the campaign will actually send from multiple numbers.

- **Rule ID:** OPS-POOL-DECLARED
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.number_pool`
- **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, T-Mobile, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-pool-declared/

### Why this rule exists

Number pooling is a filtering signal: sending similar content across many numbers without declaring a pool is the definition of snowshoeing, which carries a four-figure pass-through fee. Declaring a pool you do not use is harmless by comparison, so the asymmetry favours declaring.

### How to fix it

Set the number-pool attribute true if the campaign will send from more than one number. Never spread similar content across undeclared numbers — that is snowshoeing and it is fined rather than rejected.

### Example of a compliant value

```text
Sending from 5 numbers → number pool: true.
```

---

## OPS-QUIET-HOURS-DISCLOSED — Quiet-hours handling should be disclosed for promotional programmes

> A promotional campaign should indicate that sending respects recipient-local quiet hours.

- **Rule ID:** OPS-QUIET-HOURS-DISCLOSED
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.description + campaign.message_flow`
- **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:** FCC, state law
- **Applies:** Applies when the use case is MARKETING, MIXED, SWEEPSTAKE and LOW_VOLUME.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-quiet-hours-disclosed/

### Why this rule exists

Several US state mini-TCPAs impose quiet-hours windows measured in the recipient's local time, and violations are litigated rather than merely filtered. A national campaign that never mentions time-of-day handling is the profile plaintiffs' firms look for, so disclosing it is cheap insurance.

### How to fix it

State that promotional sends are restricted to daytime hours in the recipient's local time zone, and configure your platform to enforce it per-recipient rather than per-server.

### Example of a compliant value

```text
Promotional messages are sent between 9am and 8pm in the recipient's local time zone, and are suppressed in states with stricter windows.
```

### Notes

Registration-side twin — we verify the disclosure, not the send-time behaviour.

---

## OPS-RETENTION-STATED — Consent record retention period should be stated

> The programme should state how long consent and opt-out records are retained.

- **Rule ID:** OPS-RETENTION-STATED
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.message_flow + privacy policy`
- **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, FCC
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-retention-stated/

### Why this rule exists

Retention is what lets you answer a complaint eighteen months later, and CTIA sets a floor of six months after opt-out while TCPA exposure runs to four years. A programme that never says how long it keeps records usually has not decided, which is the same as not retaining.

### How to fix it

State a retention period covering both consent and opt-out records. Four years matches the TCPA statute of limitations and comfortably exceeds the CTIA floor.

### Example of a compliant value

```text
We retain consent and opt-out records for four years from the date of collection or revocation.
```

---

## OPS-USECASE-SCOPE — The campaign must not describe content it is not registered to send

> The description must not mention message categories outside the declared use case.

- **Rule ID:** OPS-USECASE-SCOPE
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.description + campaign.usecase`
- **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, T-Mobile
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-usecase-scope/

### Why this rule exists

Live traffic must match the registered use case, and the description is where a mismatch is visible before it becomes a filtering problem. A description promising "and occasional special offers" under a transactional use case has pre-announced the violation.

### How to fix it

Remove out-of-scope categories from the description, or change the use case to MIXED and collect promotional-grade consent to cover them.

### Example of a compliant value

```text
ACCOUNT_NOTIFICATION description should describe only account and order messaging, with no promotional aside.
```

---

## OPS-VOLUME-PLAUSIBLE — Declared volume must be plausible for the business

> The message volume the campaign implies should be consistent with the size of the business described.

- **Rule ID:** OPS-VOLUME-PLAUSIBLE
- **Layer:** Operational (`OPERATIONAL`)
- **Checks:** `campaign.description + 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, T-Mobile, AT&T
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/operational/ops-volume-plausible/

### Why this rule exists

A two-location coffee shop declaring a million messages a month is either mis-declaring or fronting for someone else's traffic, and volume mismatch is a signal reviewers use to detect resold registrations. Under-declaring is also a problem, since throughput is granted against the declaration.

### How to fix it

Declare volume consistent with your actual subscriber base. If you expect rapid growth, register at current scale and request an increase later rather than over-declaring now.

### Example of a compliant value

```text
A single-location retailer with ~5,000 subscribers should not declare enterprise-tier volume.
```
