> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Compliance send-gate error codes — decide the gate, own the fix, re-verify

> One decision surface for every pre-send compliance error code — sender registration, quiet hours, DNC, HIPAA BAA, policy scan, DLT, NOM-184, erasure, and compliance-profile gates — with the tenant-owned fix, a re-check curl, and the escalation path per code.

# Compliance send-gate error codes

When a send refuses before dispatch, Orbit answers with a
machine-readable envelope — an `error.code` plus HTTP status and
`details` — naming the exact gate that fired. This page is the single
routing surface for those codes: read the symptom table first to sort
the code by the gate family, then drop into the per-error entry for the
root cause, the tenant-owned control to change, a curl that re-checks
the posture, and the escalation path when a re-submit is owed.

<Note>
  Every control on this page is tenant-owned — you enable the gate,
  register the sender, execute the BAA, or lift the override. The one
  platform-owned control on this page (the US TCPA federal voice
  window) is called out per code. Orbit enforces the gates; approvals
  always come from the carrier or regulator reviewing your packet.
</Note>

<Warning>
  This page describes Orbit's platform controls. It is **not legal
  advice.** Which laws apply to your traffic, and what posture is
  adequate, depends on your jurisdiction, your recipients, and what you
  send. Confirm with qualified counsel.
</Warning>

***

## 1. Symptom table — map the code to the gate

Sort the envelope's `error.code` by family. The deep-dive link is the
per-error walkthrough below or the page that owns the topic.

| Code                                                               | HTTP      | Gate family                                                          | Deep dive                                                                                                                     |
| ------------------------------------------------------------------ | --------- | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
| `SENDER_ID_NOT_REGISTERED`                                         | 422       | Sender identity (alphanumeric `from`)                                | [Sender identity gates](#3-sender-identity-gates) · [alphanumeric sender rejected](/troubleshooting/sender-id-not-registered) |
| `SENDER_ID_NOT_APPROVED`                                           | 422       | Sender identity                                                      | Same                                                                                                                          |
| `SENDER_ID_CHECK_UNAVAILABLE`                                      | 503       | Sender identity (transient)                                          | Same                                                                                                                          |
| `NO_SENDER_CONFIGURED` / `SENDER_REQUIRED`                         | 422       | Sender identity (no usable sender at all)                            | [Sender identity gates](#3-sender-identity-gates)                                                                             |
| `MESSAGING_BR_SENDER_NOT_REGISTERED`, `…_SA_…`, `…_AE_…`, `…_SG_…` | 422       | Regional sender registration (BR Anatel, SA CITC, AE TDRA, SG SGNIC) | [Regional gates](#4-regional-gates) · [country matrix](/guides/sender-id-country-matrix)                                      |
| `TCPA_QUIET_HOURS` / `TCPA_DIALING_WINDOW_BLOCKED`                 | 422       | Voice quiet hours (tenant gate)                                      | [Quiet hours](#2-quiet-hours) · [dialing-window blocked calls](/troubleshooting/tcpa-window-blocked-calls)                    |
| `TCPA_FEDERAL_DIALING_WINDOW_BLOCKED`                              | 422       | Voice quiet hours (federal guard — always on)                        | [Quiet hours](#2-quiet-hours) · [federal voice guard](/concepts/tcpa-federal-voice-guard)                                     |
| `TCPA_STATE_DIALING_WINDOW_BLOCKED`                                | 422       | Voice quiet hours (state overlay)                                    | [Quiet hours](#2-quiet-hours) · [state mini-TCPA blocked calls](/troubleshooting/tcpa-state-mini-tcpa-window-blocked-calls)   |
| `TCPA_TIMEZONE_UNKNOWN`                                            | 422       | Voice quiet hours (unresolved recipient timezone)                    | [Quiet hours](#2-quiet-hours)                                                                                                 |
| `QUIET_HOURS_BLOCKED` / `QUIET_HOURS_TIMEZONE_UNKNOWN`             | 422       | Messaging quiet hours (tenant gate)                                  | [Quiet hours](#2-quiet-hours)                                                                                                 |
| `DNC_CONTACT` / `DNC_NUMBER`                                       | 422       | DNC scrub (opt-in)                                                   | [DNC scrub](#5-dnc-scrub)                                                                                                     |
| `DNC_SYNC_NOT_ENABLED`                                             | 403       | DNC pre-flight (feed not synced)                                     | [DNC scrub](#5-dnc-scrub) · [DNC check gated](/troubleshooting/dnc-check-gated)                                               |
| `HIPAA_BAA_REQUIRED`                                               | 422       | HIPAA mode (BAA not executed)                                        | [HIPAA BAA](#6-hipaa-baa) · [HIPAA\_BAA\_REQUIRED deep dive](/troubleshooting/phi-audience-baa-required)                      |
| `HIPAA_BAA_GATE_DB_FAIL`                                           | 500       | HIPAA mode (transient, fail-closed)                                  | [HIPAA BAA](#6-hipaa-baa)                                                                                                     |
| `POLICY_VIOLATION`                                                 | 422       | Pre-send policy scanner                                              | [Policy scan](#7-policy-scan)                                                                                                 |
| `POLICY_SCAN_MODE_LOOKUP_FAILED`                                   | 503       | Pre-send policy scanner (transient)                                  | [Policy scan](#7-policy-scan)                                                                                                 |
| `COMPLIANCE_CHECK_UNAVAILABLE`                                     | 500       | Any compliance gate (transient, fail-closed)                         | [When nothing fits](#when-nothing-fits)                                                                                       |
| `MESSAGING_IN_DLT_TEMPLATE_REQUIRED` / `…_CONTENT_MISMATCH`        | 422       | India DLT                                                            | [Regional gates](#4-regional-gates) · [IN DLT gates](/troubleshooting/in-dlt-gates)                                           |
| `MESSAGING_MX_NOM184_CONSENT_MISSING`                              | 422       | Mexico NOM-184 consent                                               | [Regional gates](#4-regional-gates)                                                                                           |
| `CONTACT_ERASURE_PENDING` / `ERASURE_COOLING_OFF_ACTIVE`           | 422 / 409 | Erasure ownership                                                    | [erasure-ownership gates](/troubleshooting/pending-compliance-and-erasure-gates)                                              |
| `COMPLIANCE_PROFILE_REQUIRED` / `…_NOT_APPROVED`                   | 422       | Compliance profile                                                   | [compliance profile lifecycle](/compliance/compliance-profile-lifecycle-errors)                                               |
| `COMPLIANCE_PROFILE_LOCKED` / `…_IN_USE`                           | 409       | Compliance profile                                                   | Same                                                                                                                          |

***

## 2. Quiet hours

Quiet hours hold sends until the recipient-local window opens. Voice
and SMS resolve the same recipient-local clock; the envelope carries an
absolute `next_allowed_at` UTC instant you schedule against directly.

### `QUIET_HOURS_BLOCKED` / `TCPA_QUIET_HOURS` / `TCPA_DIALING_WINDOW_BLOCKED` — 422

**Root cause.** Your own quiet-hours posture window (Settings →
Timezone Policy) refuses the send; on voice the same gate emits the
`TCPA_` spelling.

**Tenant control.** Widen, narrow, or disable the window under
Settings → Timezone Policy — this gate is opt-in per
[Send Gates](/compliance/send-gates).

**Re-check the posture.** Preview the resolved window per destination
before a rollout:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/quiet-hours/preview?destination=+13125550100" \
  -H "X-API-Key: dv_live_sk_..."
```

The preview answers "would this send be held, and until when?" —
schedule at the returned instant instead of polling.

**Escalate.** Never owed: reschedule at `next_allowed_at`, or adjust
your own window. Open a ticket only if the returned `next_allowed_at`
contradicts the window you configured.

### `TCPA_FEDERAL_DIALING_WINDOW_BLOCKED` — 422 (platform-owned)

**Root cause.** The sole platform-global guard: campaign and dialer
voice to US (+1) recipients outside 8 AM–9 PM recipient-local is
hard-blocked. No tenant toggle widens it — the statutory exposure is
not yours to waive.

**Tenant control.** None. Recovery is scheduling at `next_allowed_at`.

**Escalate.** A false timezone resolution is the only ticket class —
when the recipient's number resolves to a region it is not in. The full
guard is on [The TCPA federal voice guard](/concepts/tcpa-federal-voice-guard).

### `TCPA_STATE_DIALING_WINDOW_BLOCKED` — 422 (platform-owned)

**Root cause.** A stricter state overlay (Florida's Sunday ban,
Mississippi's early close, and the OK / LA / AL / AR / WV windows) sits
on top of the federal rail on a most-restrictive-wins rule.

**Tenant control.** None — schedule inside the state window. The
overlay map is on
[US state calling windows](/compliance/state-calling-windows).

**Escalate.** Same class as the federal guard — a recipient-local
mis-resolution with the payload's resolved state named.

### `TCPA_TIMEZONE_UNKNOWN` / `QUIET_HOURS_TIMEZONE_UNKNOWN` — 422

**Root cause.** The recipient's timezone could not be resolved (neither
NANP area-code nor E.164 country prefix matched). Voice fails closed by
default to bound TCPA exposure; messaging defaults to fail open
(`skip`).

**Tenant control.** The org-level `unknown_timezone_policy` knob —
`skip` (allow) or `deny` (fail closed). Voice operators opting into
`skip` unblock unresolved recipients; messaging tenants opting into
`deny` start blocking them.

**Re-check.** The same
`GET /compliance/quiet-hours/preview?destination=…` shows whether a
destination resolves.

**Escalate.** If a real E.164 number fails to resolve, open a ticket
with the destination and the `meta.request_id` from the envelope.

***

## 3. Sender identity gates

These gates run before the message is accepted — nothing queues.

### `SENDER_ID_NOT_REGISTERED` / `SENDER_ID_NOT_APPROVED` — 422

**Root cause.** The `from` value is a custom alphanumeric sender ID
with no registration row on the account, or a row stuck at `pending` /
`rejected` / `expired`. E.164 numbers, the platform default sender, and
the shared pool never raise this — only named alphanumerics fire it.

**Tenant control.** Register the sender under Settings → Sender IDs,
and read the country's `registration` field on
[`GET /api/v1/compliance/country-requirements`](/compliance/country-requirements)
to know whether the destination demands it.

**Re-check.**

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/country-requirements" \
  -H "X-API-Key: dv_live_sk_..."
```

**Escalate.** A `rejected` row: read the reviewer notes, fix the cited
gap, and re-submit on the
[pending number / Sender ID runbook](/compliance/troubleshooting-pending-gated-surfaces).

### `NO_SENDER_CONFIGURED` / `SENDER_REQUIRED` — 422

**Root cause.** `NO_SENDER_CONFIGURED` — the account has no usable
sender at all (no `from`, no default sender, no owned number, no trial
pool assignment). `SENDER_REQUIRED` — a direct API send simply did not
name any sender selector.

**Tenant control.** Claim a number (the dashboard CTA deep-links into
/numbers) or set a default sender; for `SENDER_REQUIRED`, send `from`
or one of the sender selectors.

**Escalate.** Never — both fix in your own settings.

***

## 4. Regional gates

These gates are opt-in per market — your organization enables them per
country; tenants not operating in the region skip the probes entirely.

### `MESSAGING_BR_SENDER_NOT_REGISTERED` / `…_SA_…` / `…_AE_…` / `…_SG_…` — 422

**Root cause.** For an **alphabetic** sender, the destination country
(BR — Anatel, SA — CITC, AE — TDRA, SG — SGNIC) demands an
`approved` country-registration entry for that sender, and none exists.
Numeric senders skip this probe — carriers provision them at purchase
time.

**Tenant control.** Registrations are filed per-sender on
[Sender-ID Registration](/compliance/sender-id-registration); the
regulator's approval is theirs to give.

**Re-check.**

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/country-requirements" \
  -H "X-API-Key: dv_live_sk_..."
```

**Escalate.** A rejected region registration re-submits the same way as
a sender-ID row — read the reviewer notes, fix, re-submit.

### `MESSAGING_IN_DLT_TEMPLATE_REQUIRED` / `…_CONTENT_MISMATCH` — 422

**Root cause.** The send to India carries no `dlt_template_id`
(REQUIRED), or carries one whose registered content template you now
mismatched — body drifted or sender ≠ registered header (MISMATCH,
enforced only when the template is locally registered as approved).

**Tenant control.** Always pass `metadata.dlt_template_id` (or
`metadata.dlt.template_id`) on IN sends; keep the body matching the
registered content and send from the registered header.

**Escalate.** Register the template in-country or lift the org-level
gate scope per the
[Troubleshoot India DLT gate](/troubleshooting/in-dlt-gates) page —
that page owns the re-submit choreography.

### `MESSAGING_MX_NOM184_CONSENT_MISSING` — 422

**Root cause.** A promotional A2P SMS to MX without an opt-in
`consent_records` row stamped `nom184=true` for the recipient phone.

**Tenant control.** Record NOM-184 consent on the contact (Contacts →
Consent), or send transactional traffic with
`metadata.nom184_exempt=true` — use that flag responsibly; the audit
trail records it.

**Escalate.** Never — the fix lives in your consent ledger.

***

## 5. DNC scrub

### `DNC_CONTACT` / `DNC_NUMBER` — 422

**Root cause.** The recipient's contact row carries `dnc=true`, or the
number sits in the scrubbed list. This is fail-closed **only once you
opt in** (`dnc_sync_enabled`) — otherwise the gate is not there.

**Tenant control.** The org opt-in `dnc_sync_enabled`; per-row list
sources on [DNC Scrubbing](/compliance/dnc-scrub).

**Escalate.** Never — either lift the recipient from the DNC list with
a documented reason, or don't send.

### `DNC_SYNC_NOT_ENABLED` — 403

**Root cause.** The pre-flight `GET /dnc/check` / `POST /dnc/scrub`
refuses because the org never enabled the scrub or the sync feed is
not yet synced.

**Tenant control.** Enable `dnc_sync_enabled`; a synced snapshot
retires the gate.

**Escalate.** If the feed stays `synced: false` past a re-enable, open
a ticket with the check response payload.

***

## 6. HIPAA BAA

### `HIPAA_BAA_REQUIRED` — 422

**Root cause.** HIPAA mode is opted-in and the send's audience or
content matched PHI — the workspace refuses PHI-bearing traffic until
your Business Associate Agreement is `executed` and in-term.

**Tenant control.** The BAA execution flow on
[BAA](/compliance/baa) — attest PHI scope, preview, e-sign by typing
the name.

**Re-check.**

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/baa" \
  -H "X-API-Key: dv_live_sk_..."
```

Anything but `executed` means no current agreement, and HIPAA mode
itself stays off until then.

**Escalate.** For a workspace-role block on the BAA flow itself, the
403 path is on
[Troubleshooting: HIPAA enable blocked](/troubleshooting/hipaa-enable-baa-not-executed).

### `HIPAA_BAA_GATE_DB_FAIL` — 500

**Root cause.** The gate's own read failed — a family the gate refuses
to guess, so it fails closed.

**Tenant control.** Retry with backoff; if it persists, this is a
platform issue — open a ticket with `meta.request_id`.

***

## 7. Policy scan

### `POLICY_VIOLATION` — 422

**Root cause.** The pre-send scanner (TCPA / SHAFT / GDPR topic rules)
blocked the message body. Your org's scan duty `policy_scan_mode`
decides: `off` logs only, `warn` surfaces the verdict, `block` refuses
the send.

**Tenant control.** The `policy_scan_mode` duty on the compliance
settings surface (API `PATCH /settings/compliance/policy-scan-mode`),
with `warn` as the default.

**Re-check.**

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/settings/compliance/policy-scan-mode" \
  -H "X-API-Key: dv_live_sk_..."
```

`block` plus a `WARN`-shaped verdict is the *worked path*: lift the
duty to `warn` and re-send.

**Escalate.** Never — the scanner names the legislation family in
`details`; honour it or fix the copy.

### `POLICY_SCAN_MODE_LOOKUP_FAILED` — 503

**Root cause.** The mode resolver could not read your org's current
duty and the cache is cold — it refuses to fall back to `warn` for a
block-duty tenant.

**Tenant control.** Retry with backoff; this is transient by design
and `Retry-After` friendly.

***

## Worked flows

**1. Brazil SMS blocked at send.** Envelope:
`422 MESSAGING_BR_SENDER_NOT_REGISTERED`. You opted into the BR gate
and your branded sender lacks an approved Anatel registration row.
File it on [Sender-ID Registration](/compliance/sender-id-registration);
re-check with `GET /compliance/country-requirements`. Until approval
lands, numeric senders keep sending.

**2. India SMS rejected twice.** First `422
MESSAGING_IN_DLT_TEMPLATE_REQUIRED` (no `dlt_template_id`); after you
add one, `422 MESSAGING_IN_DLT_CONTENT_MISMATCH` with
`details.mismatch_type: body` — the registered template is precise.
Match the body to the registered content exactly, or
[walk the IN DLT resubmit](/troubleshooting/in-dlt-gates).

**3. HIPAA campaign refused.** `422 HIPAA_BAA_REQUIRED` — your campaign
audience is PHI-adjacent and the BAA reads `pending`. Execute the BAA
flow ([BAA](/compliance/baa)), re-read it with
`GET /compliance/baa`, then relaunch. A wizard-side PHI designation you
honestly never intended lifts to `none`; the
[PHI deep dive](/troubleshooting/phi-audience-baa-required) owns both
paths.

**4. Voice window blocked.** `422 TCPA_DIALING_WINDOW_BLOCKED` at
10 PM recipient-local. `FEDERAL` absent from the code → this is **your**
quiet-hours window, so either reschedule at `next_allowed_at` or widen
the window. Codes carrying `FEDERAL` are the one platform-owned control
— schedule; no toggle exists.

**5. Scanner blocks on `warn`-shaped copy.** `422 POLICY_VIOLATION`
because duty was `block`. Read `policy_scan_mode` with the curl above,
decide, re-send.

***

## When nothing fits

Any 5xx-class code (`COMPLIANCE_CHECK_UNAVAILABLE`,
`HIPAA_BAA_GATE_DB_FAIL`, `POLICY_SCAN_MODE_LOOKUP_FAILED`,
`SENDER_ID_CHECK_UNAVAILABLE`) is transient — retry with backoff before
touching posture. Any 4xx/409 class means a posture change is owed and
retrying the same request burns rate-limit budget without moving the
state.

If a 422 persists past the posture fix, open a ticket carrying the
code, the HTTP status, the `meta.request_id` from the envelope, the
referencing asset id (sender id / campaign id / profile id), and the
destination country — the same payload the
[lifecycle-errors page](/compliance/compliance-profile-lifecycle-errors)
calls the full packet.

***

## Cross-reference map

Each per-code topic here links out to the page that owns the deep
choreography:

* [Send Gates](/compliance/send-gates) — the canonical pre-send gate inventory.
* [Sender-ID Registration](/compliance/sender-id-registration) and the
  [country matrix](/guides/sender-id-country-matrix) — registration snippets and statuses.
* [HIPAA](/compliance/hipaa) and [BAA](/compliance/baa) — the BAA state machine, the e-sign flow, and the PHI vocabulary.
* [DNC Scrubbing](/compliance/dnc-scrub) — sources, freshness, the check endpoint.
* [TCPA Known-Litigator Gate](/compliance/tcpa-known-litigator) — the consented-bypass companion to the window family.
* [DLT-India Onboarding](/compliance/dlt-india) and
  [IN DLT gates](/troubleshooting/in-dlt-gates) — Principal Entity, headers, content templates.
* [RMD Filing Lifecycle](/compliance/rmd-registration) — the FCC filing states the voice gates respect.
* [Compliance profile lifecycle errors](/compliance/compliance-profile-lifecycle-errors) — the attach/mutate/delete 422/409 codes the send gates defer to.
* [Pending numbers and Sender IDs](/compliance/troubleshooting-pending-gated-surfaces) — re-submission choreography for `rejected` registrations.
