# Ekas 10DLC Rule Registry — Brand ↔ campaign

> The 13 brand ↔ campaign rules Ekas checks during A2P 10DLC registration.

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

---
## XBC-001 — Sole proprietor brands may only run the sole proprietor use case

> A SOLE_PROPRIETOR brand must register its campaign under the SOLE_PROPRIETOR use case; standard campaign types are unavailable to that tier.

- **Rule ID:** XBC-001
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.entity_type + campaign.usecase`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** 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 when the brand is a sole proprietor.
- **Depends on:** BRD-065
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-001/

### Why this rule exists

The sole proprietor tier exists as a low-volume path for individuals with no EIN, and it comes with its own throughput caps and a single-number limit. Standard use cases assume a vetted registered entity behind them, so the platform refuses the combination rather than granting an individual standard-tier treatment.

### How to fix it

Select the Sole Proprietor use case for this campaign. If you need a standard use case such as Marketing, obtain an EIN and re-register the brand as a standard entity first — the tier, not the campaign, is what limits you.

### Example of a compliant value

```text
Use case: SOLE_PROPRIETOR
```

### Notes

Catalog BRD-089. The most common failure after a sole proprietor brand is itself accepted.

---

## XBC-002 — Charity use case requires a verified 501(c)(3) non-profit brand

> The CHARITY use case is restricted to a NON_PROFIT brand holding verified 501(c)(3) tax-exempt status.

- **Rule ID:** XBC-002
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.entity_type + brand.tax_exempt_status + campaign.usecase`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** 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, Infobip
- **Applies:** Applies when the use case is CHARITY.
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-002/

### Why this rule exists

Charitable messaging gets favourable treatment — better throughput and more tolerance for solicitation content — so eligibility is verified against the brand record rather than taken on trust. 501(c)(4), (5) and (6) organisations are tax-exempt but are NOT charities for this purpose, which is where most rejections come from.

### How to fix it

Register the brand as NON_PROFIT with its 501(c)(3) EIN and declare the tax-exempt status on the brand record. The EIN must appear in the IRS Tax-Exempt Organization Search. If the organisation is a 501(c)(4) or (6), choose a different use case.

### Example of a compliant value

```text
Entity type: NON_PROFIT · Tax exempt status: 501(c)(3) · Use case: CHARITY
```

---

## XBC-003 — Political use case requires a non-profit brand with political vetting

> The POLITICAL use case must sit on a NON_PROFIT brand carrying external political vetting recognised by both AT&T and T-Mobile.

- **Rule ID:** XBC-003
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.entity_type + campaign.usecase`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Wait on an external system or a required interval
- **Required by:** TCR, AT&T, T-Mobile
- **Applies:** Applies when the use case is POLITICAL.
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-003/

### Why this rule exists

Political messaging is the most scrutinised category on the network, and both major carriers require independent verification that the sender is who they claim to be before granting throughput. Vetting is imported into TCR from an external provider, so it cannot be satisfied by anything you type into the form.

### How to fix it

Register the brand as NON_PROFIT, then obtain political vetting (Campaign Verify or an equivalent both carriers accept) and import it into TCR before submitting the campaign. Do not order a political vet for a brand that already holds 501(c)(3/4/5/6) status — that combination is disallowed.

### Check this yourself

**Is political vetting already imported and visible on the brand, rather than ordered, in progress, or held only as a certificate you have not uploaded?**

1. Open the brand at your provider and confirm a political vet (Campaign Verify, or an equivalent both AT&T and T-Mobile accept) is listed against it.
2. Confirm the brand's entity type is NON_PROFIT, and that it does not also hold 501(c)(3/4/5/6) status — that combination is disallowed.

*What wrong looks like:* The certificate is sitting in an inbox rather than in TCR. Nothing on the campaign form says the vetting is missing, and the campaign is refused for a brand that looks complete.

### Notes

Off-platform: only the entity type is checkable here. The vetting itself is bought from an external provider and imported into TCR, so the user must obtain it themselves and confirm the import landed before submitting — we can never return anything better than UNCLEAR on that half, and a PASS on entity type is not a prediction that the campaign will be approved.

---

## XBC-004 — Emergency and public-safety use cases exclude sole proprietors

> Public-safety and emergency use cases are not available to a SOLE_PROPRIETOR brand.

- **Rule ID:** XBC-004
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.entity_type + campaign.usecase`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** 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 when the brand is a sole proprietor.
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-004/

### Why this rule exists

Emergency messaging bypasses filtering that protects consumers from everything else, so it is restricted to registered entities that can be held accountable for misuse. An individual with no EIN cannot be vetted to that standard.

### How to fix it

Register the organisation as a standard entity with its EIN. If the messaging is genuinely operational rather than emergency, choose CUSTOMER_CARE or ACCOUNT_NOTIFICATION instead.

### Example of a compliant value

```text
Entity type: PRIVATE_PROFIT or GOVERNMENT · Use case: EMERGENCY
```

---

## XBC-005 — Sole proprietor brand and campaign both require a reference ID

> referenceId is mandatory — not optional — on both the brand and the campaign for the sole proprietor tier.

- **Rule ID:** XBC-005
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.reference_id + campaign.reference_id`
- **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 when the brand is a sole proprietor.
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-005/

### Why this rule exists

The reference ID is how the sole proprietor tier ties a brand and campaign to the verified mobile number behind them, which is the only identity check that tier has. It is optional everywhere else, so integrations built against the standard flow omit it and fail here.

### How to fix it

Populate referenceId on both the brand and the campaign with your own stable identifier for this customer.

### Example of a compliant value

```text
referenceId: acme-sp-2026-0041
```

### Notes

Catalog BRD-077 / CMP-022.

---

## XBC-006 — The brand must be verified before its campaign is submitted

> A campaign must not be submitted until the brand reaches an approved, verified identity status.

- **Rule ID:** XBC-006
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.identity_status + campaign submission`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Wait on an external system or a required interval
- **Required by:** TCR, AWS, Twilio
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-006/

### Why this rule exists

A campaign is judged against the brand as it stands the moment it arrives, so one submitted against an unverified brand is refused — and the refusal names the campaign. Teams then rewrite the description, the samples and the flow, none of which was the problem, and resubmit into the same wall. It happens because the brand call returns 200 with a pending status and looks like success.

### How to fix it

Hold the campaign until the brand identity status reads VERIFIED or VETTED_VERIFIED, and sequence the two submissions off the brand status event rather than off a timer. Done when the brand is in a final verified state at the moment the campaign is sent.

### Check this yourself

**Does the brand read VERIFIED or VETTED_VERIFIED at the moment the campaign is submitted, rather than PENDING?**

1. Fetch the brand immediately before submitting the campaign and read the identity status — do not rely on the 200 the create call returned, which succeeds while the status is still pending.
2. Sequence the campaign off the brand status webhook rather than off a timer, so the campaign leaves only once the status is final.

*What wrong looks like:* The campaign is refused and the error names the campaign, so the description, samples and flow are rewritten and resubmitted into the same wall — while the brand was the thing that was not ready.

### Notes

The wait is at the registry and nothing here shortens it. What the user has to do is order the two submissions — brand first, campaign only once the status is final — because a campaign refused for this reason still consumes a submission and, at some providers, a fee. An UNVERIFIED status is not a brand defect on its own: it is the state a brand sits in while the check runs.

---

## XBC-007 — A public company must finish two-factor identity before any campaign

> A PUBLIC_PROFIT brand must complete its Authentication+ two-factor identity step before a campaign is created against it.

- **Rule ID:** XBC-007
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.entity_type + brand.vetting + campaign submission`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Wait on an external system or a required interval
- **Required by:** TCR
- **Applies:** Applies when the brand is a public company.
- **Depends on:** XBC-006
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-007/

### Why this rule exists

Publicly traded brands carry an extra identity step that no other entity type has, and it is the one gate that produces no error while it is outstanding: the brand verifies, looks healthy, and every campaign against it is refused. The two-factor mail goes to the business contact address, so it is routinely missed by the person doing the registration, who is rarely the person on that mailbox.

### How to fix it

Order the Authentication+ vet explicitly after the identity check, watch the business contact mailbox for the two-factor mail, and hold the campaign until the vet is recorded on the brand. Done when the brand shows an Authentication+ vet before the campaign is submitted.

### Check this yourself

**Do you know who receives mail at the business contact address, and that they are expecting the Authentication+ two-factor message?**

1. Name the person on the business contact mailbox out loud. It is rarely the person doing the registration.
2. Tell them the two-factor mail is coming and what to do with it, then confirm the completed vet appears on the brand before submitting the campaign.

*What wrong looks like:* The brand verifies and looks healthy, every campaign against it is refused, and the two-factor mail is unopened in a shared inbox nobody watches.

### Notes

The vet is an action at the registry, not a field on the submission, and the PIN arrives by mail on the registry's schedule. What the user has to do is confirm who receives the business contact mail and that they know to expect it — BRD-225 covers ordering the vet, BRD-226 the window it must be completed in; this rule is the campaign-side consequence of either being outstanding.

---

## XBC-008 — A sole proprietor gets one campaign and one number

> A SOLE_PROPRIETOR brand may hold exactly one campaign, and that campaign exactly one telephone number.

- **Rule ID:** XBC-008
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.entity_type + campaign count + campaign.number_pool`
- **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, T-Mobile, Twilio
- **Applies:** Applies when the brand is a sole proprietor.
- **Depends on:** XBC-001
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-008/

### Why this rule exists

The sole proprietor tier is a low-volume path for individuals with no EIN, and the single-campaign, single-number limit is what the carriers accept in exchange for the reduced vetting. A second campaign is refused rather than queued, so somebody who registers a marketing campaign beside their appointment reminders loses the fee and the time. Pooling is the same limit stated the other way: there is only ever one number to pool.

### How to fix it

Fold everything the programme sends into the one sole-proprietor campaign, on one number, and turn number pooling off. If the business genuinely needs a second campaign or more throughput, obtain an EIN and re-register as a standard entity — the tier is the limit, not the campaign.

### Example of a compliant value

```text
Sole proprietor: 1 campaign · 1 phone number · numberPool: false
```

### Common mistakes

- Registering the second campaign under a second sole-proprietor brand does not work either: the tier caps the mobile number behind the brands as well, so the same person cannot hold an unlimited number of them.

---

## XBC-010 — Every sample message must identify the registered brand

> Each sample must contain the registered brand name or DBA, matching the brand record rather than a marketing alias.

- **Rule ID:** XBC-010
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.display_name + campaign.sample[]`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** Bandwidth, TCR, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-010/

### Why this rule exists

A consumer receiving a text from an unfamiliar number decides in about a second whether it is legitimate or spam, and the sender name is the only signal they have. Carriers therefore require the brand to identify itself in the message body, and Bandwidth checks every sample rather than just one.

### How to fix it

Start every sample with the registered brand name followed by a colon. Use the name on the brand record — a marketing alias the reviewer cannot match to the registration reads as a mismatch.

### Example of a compliant value

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

### Common mistakes

- Twilio accepts the name in at least one sample; Bandwidth requires it in all of them. We apply the stricter rule.

### Provider rejection codes

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

---

## XBC-011 — Opt-in description must carry the registered brand name

> The CTA / message-flow field must name the brand, matching the registered Brand or DBA.

- **Rule ID:** XBC-011
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.display_name + campaign.message_flow`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** Bandwidth, Telnyx, AWS
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-011/

### Why this rule exists

The reviewer reads the message flow to confirm the consent a consumer gave was consent to hear from THIS brand. A flow describing an anonymous opt-in cannot establish that, and it is also the exact pattern a reseller registering someone else’s traffic would produce.

### How to fix it

Name the brand explicitly in the opt-in description, and quote the consent wording the consumer agrees to — that wording should name the brand too.

### Example of a compliant value

```text
Customers opt in at acmecoffee.com/signup by ticking an unchecked box agreeing to receive recurring automated marketing texts from Acme Coffee.
```

---

## XBC-012 — HELP reply must identify the brand

> The HELP auto-reply must contain the registered brand name.

- **Rule ID:** XBC-012
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.display_name + campaign.help_message`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** TCR, Twilio, CTIA
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-012/

### Why this rule exists

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

### How to fix it

Put the brand name at the start of the HELP reply and add a support contact a person can actually reach. CTIA expects contact information beyond the bare name.

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

---

## XBC-013 — Brand, website and campaign content must describe the same business

> The registered brand name, the brand website, and what the campaign says it sends must be coherent.

- **Rule ID:** XBC-013
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.company_name + brand.website + campaign.description`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the submitted form
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** Twilio, TCR, AWS, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-013/

### Why this rule exists

Reviewers open the website and compare it against the campaign before approving anything. A mismatch — a pest-control site behind a campaign describing salon appointment reminders — is the classic signature of a reseller registering under a borrowed brand, so it is treated as an integrity failure rather than a copy problem.

### How to fix it

Make the campaign description describe the business the website actually presents, under the name the brand is registered with. If the website belongs to a parent or agency rather than the sender, register the brand that owns the customer relationship instead.

### Example of a compliant value

```text
Website acmecoffee.com sells coffee subscriptions; description: "Acme Coffee sends order updates and promotional offers to subscription customers who opted in at checkout."
```

### Provider rejection codes

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

---

## XBC-014 — The description must name the registered business

> The campaign description must name the registered legal name or the registered DBA.

- **Rule ID:** XBC-014
- **Layer:** Brand ↔ campaign (`CROSS`)
- **Checks:** `brand.company_name + campaign.description`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** Deterministic (settled in code from the submitted values)
- **Fix type:** Fix the field — a better value in the form clears it
- **Required by:** Bandwidth, Infobip, AWS, Sinch, Plivo
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/cross/xbc-014/

### Why this rule exists

The description is where a reviewer decides which business they are vetting, and one that never names the registrant leaves them matching a programme against a brand record on trust. It is the same defect as a wrong name and reads worse: a description naming nobody offers nothing to reconcile, so there is no way to establish that this campaign belongs to this brand at all.

### How to fix it

Open the description with the registered name — the one on the brand record, not a product or campaign nickname — and keep it there. Done when the first sentence names the same business the brand record does.

### Example of a compliant value

```text
Acme Coffee sends weekly promotional offers to customers who opted in at checkout — not "We send weekly promotional offers to our customers".
```

### Common mistakes

- A product or programme name is not the registered name: "Acme Rewards" does not match a brand registered as Acme Coffee Co, LLC unless Acme Rewards is the registered DBA.

### Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Bandwidth | `2006` | yes |
| Infobip | `603` | yes |

### Notes

The catalog grades this DETERMINISTIC + EXTERNAL_DATA because the strict form matches the description against the authoritative registry record. That lookup is not available here, so this rule settles the half that is: whether the description names the business the submission itself declares. A description agreeing with a brand record that is itself wrong is XBC-010 and CMP-037's territory.
