Skip to main content

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

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.

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. Re-check the posture. Preview the resolved window per destination before a rollout:
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.

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. 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 to know whether the destination demands it. Re-check.
Escalate. A rejected row: read the reviewer notes, fix the cited gap, and re-submit on the pending number / Sender ID runbook.

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; the regulator’s approval is theirs to give. Re-check.
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 page — that page owns the re-submit choreography. 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. 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 — attest PHI scope, preview, e-sign by typing the name. Re-check.
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.

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.
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; 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. 3. HIPAA campaign refused. 422 HIPAA_BAA_REQUIRED — your campaign audience is PHI-adjacent and the BAA reads pending. Execute the BAA flow (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 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 calls the full packet.

Cross-reference map

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