# CON-024 — The opt-in URL must serve a certificate that verifies

> The opt-in URL must present a valid, verifiable TLS certificate — not expired, self-signed, or issued for another hostname.

- **Rule ID:** CON-024
- **Layer:** Consent flow (`CONSENT_FLOW`)
- **Checks:** `opt-in URL TLS chain`
- **Severity:** BLOCKING — Breaking this rule gets the submission rejected outright.
- **When it bites:** Gates approval — get this wrong and registration is refused
- **How it is detected:** AI judgement over the crawled website or policy page
- **Fix type:** Fix the website — no form edit clears it
- **Required by:** AWS, Bandwidth
- **Applies:** Applies to every 10DLC registration.
- **Canonical URL:** https://ekas.io/rules/10dlc/consent-flow/con-024/

## Why this rule exists

A crawler that hits a certificate error stops there and reports the opt-in as unverifiable, so the rejection reads as "we could not see your consent surface" rather than as a certificate problem. Brands lose days to that translation, because the page loads perfectly in a browser that has been clicking through the warning for months.

## How to fix it

Renew or reissue the certificate for the exact hostname in the submitted URL, including the www or bare-domain form you actually registered. Test it from outside your network — an internal proxy or a pinned certificate hides the failure from everyone inside. Done when an external SSL checker reports a complete, valid chain.

## Example of a compliant value

```text
opt_in_url: https://acmecoffee.com/checkout — certificate valid for acmecoffee.com, chain complete.
```

## Common mistakes

- A certificate valid for acmecoffee.com and not for www.acmecoffee.com fails whenever the submitted URL uses the other form, which is the most common version of this.
- An expired intermediate still lets most browsers through and fails a strict crawler — the browser test is not the test that matters.

## Provider rejection codes

| Provider | Code | Resubmission allowed |
| --- | --- | --- |
| Bandwidth/DCA | `2103` | yes |

## Notes

CRAWLER GAP, now half closed. RuleInput carries per-URL fetch outcomes (`urlFetches`), which WEB-073 and POL-015 read deterministically for the brand and policy hosts. This rule covers the opt-in URL, which is often a third address the crawler is not yet asked to fetch, so it stays judged and returns UNCLEAR until a `urlFetches` entry exists for that URL. Recorded rather than omitted: the obligation is real and the remaining gap is the fetch layer's.
