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

# Troubleshoot a 'blocked' send — map the code to the gate

> A one-hop routing surface from every 'blocked'-class send error code to the gate that owns it — suppression, consent-false, quiet hours, DNC/RND pre-flight, and the HIPAA BAA lifecycle 422 — with the tenant-owned fix and the re-check curl for each.

# Troubleshoot a `blocked` send

A send that returns a `blocked`-class error was refused by a
pre-dispatch compliance gate before it reached the carrier. Each
code names the gate family that fired; the fix lives on a different,
deeper page that owns the full lifecycle of that gate. This page is
the single routing surface between the two — read the code here, then
drop one hop into the page that owns the control.

<Note>
  Every control on this page is tenant-owned — you enable the gate,
  record the consent, widen the window, enable the scrub, or execute
  the BAA. The one platform-owned control (the US TCPA federal voice
  window) is called out where it applies. 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. Map the code to the gate

Sort the envelope's `error.code` by the gate family. The "Go to" link
is the page that owns the gate's full lifecycle; the rest of this page
is the one-paragraph diagnosis for each code.

| Code | HTTP | Gate family | Go to |
| - | - | - | - |
| `SUPPRESSION_BLOCKED` | 422 | Opt-out suppression | [Opt-Out & Suppression Lists](/compliance/opt-out-suppression) |
| `CONSENT_FALSE` | 422 | Consent (no active opt-in) | [Consent Management & Receipts](/compliance/consent-management) |
| `QUIET_HOURS_BLOCKED` | 422 | Quiet hours (advisory, tenant) | [Quiet-Hours Preview](/compliance/quiet-hours-preview) |
| `TCPA_QUIET_HOURS` / `TCPA_DIALING_WINDOW_BLOCKED` | 422 | Quiet hours (voice, tenant) | [Quiet-Hours Preview](/compliance/quiet-hours-preview) |
| `TCPA_FEDERAL_DIALING_WINDOW_BLOCKED` | 422 | Quiet hours (federal, platform) | [Quiet-Hours Preview](/compliance/quiet-hours-preview) |
| `TCPA_STATE_DIALING_WINDOW_BLOCKED` | 422 | Quiet hours (state overlay) | [Quiet-Hours Preview](/compliance/quiet-hours-preview) |
| `QUIET_HOURS_TIMEZONE_UNKNOWN` / `TCPA_TIMEZONE_UNKNOWN` | 422 | Quiet hours (unresolved timezone) | [Quiet-Hours Preview](/compliance/quiet-hours-preview) |
| `DNC_CONTACT` / `DNC_NUMBER` | 422 | DNC pre-flight | [DNC Scrubbing](/compliance/dnc-scrub) |
| `DNC_SYNC_NOT_ENABLED` | 403 | DNC pre-flight (feed not synced) | [DNC Scrubbing](/compliance/dnc-scrub) |
| `RND_CONTACT` / `RND_REASSIGNED` | 422 | RND pre-flight | [RND Scrub](/compliance/rnd-scrub) |
| `HIPAA_BAA_REQUIRED` | 422 | HIPAA BAA lifecycle | [HIPAA](/compliance/hipaa) · [BAA](/compliance/baa) |

A `422` means a posture change is owed — retrying the same request
burns rate-limit budget without moving the state. A `403` on
`DNC_SYNC_NOT_ENABLED` is the opt-in you owe before the pre-flight
serves. A `5xx`-shaped code is transient and is not on this page —
retry with backoff first.

***

## 2. `SUPPRESSION_BLOCKED` — opt-out suppression

**What fired.** The recipient's address sits on your suppression
list — they replied STOP, unsubscribed through the Preference Center,
were recorded as `opt_in: false` through the Consent API, bounced, or
filed a complaint. A suppressed address is dropped before dispatch on
every regulated channel regardless of campaign, contact import, or
API call.

**Channel scopes.** Each suppression row carries a scope, and the send
gate honours the scope that covers the channel you sent on. The full
scope set is: `all`, `sms`, `voice`, `whatsapp`, `email`, `push`,
`telegram`, `messenger`, `rcs`.

* `all` blocks every channel reachable on that address — the scope the
  Consent API and the Preference Center always write, and the default
  for phone/WhatsApp rows on a bulk CSV import.
* `email` blocks email only — the default for email rows on a bulk
  CSV import unless a `channel` column overrides it.
* A per-channel scope (`sms`, `voice`, `whatsapp`, …) blocks only that
  channel.

**Tenant fix.** If the suppression is correct, do not send — honouring
it is a legal requirement. If the recipient has since re-opted-in,
reverse the suppression through the Consent API (`opt_in: true`) on
[Opt-Out & Suppression Lists](/compliance/opt-out-suppression), which
revokes the `all` plus matching per-channel rows without deleting the
audit trail.

**Re-check the posture.** Confirm the address is no longer suppressed:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/suppression-list/lookup?address=%2B14155550100" \
  -H "X-API-Key: dv_live_sk_..."
```

**Escalate.** Never owed for a genuine suppression — the fix is the
re-opt-in, or do not send. Open a ticket only if a re-opt-in succeeded
but the send still returns `SUPPRESSION_BLOCKED`.

***

## 3. `CONSENT_FALSE` — no active opt-in

**What fired.** The send requires a positive consent grant and none is
on file for this (contact, channel) pair — the latest consent row is
`opted_out`, `expired`, `pending` (an unconfirmed double opt-in), or
absent altogether. Marketing sends fail closed by default: outbound is
eligible only on a live, unexpired `opted_in` grant.

**Tenant fix.** Record an opt-in through the Consent API with the
channels the send targets, and supply the GDPR evidence fields a
consent-based grant requires — `lawful_basis`, `purpose`, and
`consent_text_version` (the disclosure version the recipient agreed
to). A re-confirmation in a jurisdiction that treats a stale grant as
lapsed is an ordinary opt-in POST, optionally with a fresh validity
window. The full shape is on
[Consent Management & Receipts](/compliance/consent-management).

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/compliance/consent" \
  -H "X-API-Key: dv_live_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "contact_id": "ctc_abc123",
    "channels": ["sms", "voice"],
    "opt_in": true,
    "lawful_basis": "consent",
    "purpose": "appointment reminders",
    "consent_text_version": "disclosure-v2.1",
    "expires_in_days": 365
  }'
```

**Re-check the posture.** Read the consent state the send gate reads:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/consent/lookup?contact_id=ctc_abc123&channel=sms" \
  -H "X-API-Key: dv_live_sk_..."
```

`marketing_eligible: true` (equivalently `status: "opted_in"`) is the
only state the send gate treats as eligible. `expired` or `pending`
means the send is correctly blocked — re-confirm first.

**Escalate.** Never owed for a genuinely missing or lapsed grant — the
fix is the opt-in. Open a ticket only if `lookup` returns `opted_in`
but the send still returns `CONSENT_FALSE`.

***

## 4. Quiet hours — advisory vs. enforced

**What fired.** The send landed outside the recipient-local calling or
messaging window. The same gate family returns several codes, and the
fix depends on which layer owned the block.

* `QUIET_HOURS_BLOCKED` — the messaging quiet-hours gate (tenant
  window) refused the send.
* `TCPA_QUIET_HOURS` / `TCPA_DIALING_WINDOW_BLOCKED` — the voice
  quiet-hours gate (tenant window) refused the send.
* `TCPA_FEDERAL_DIALING_WINDOW_BLOCKED` — the sole platform-owned
  federal guard refused a US voice send outside 8 AM–9 PM
  recipient-local. No tenant toggle widens it; the statutory exposure
  is not yours to waive.
* `TCPA_STATE_DIALING_WINDOW_BLOCKED` — 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.
* `QUIET_HOURS_TIMEZONE_UNKNOWN` / `TCPA_TIMEZONE_UNKNOWN` — the
  recipient's timezone could not be resolved; voice fails closed by
  default, messaging defaults to fail open unless you set `deny`.

**Advisory vs. enforced.** The
[`GET /compliance/quiet-hours/preview`](/compliance/quiet-hours-preview)
endpoint is **advisory** — it answers "would this send be held, and
until when?" without performing it. The send-time gate is
**enforced** — it refuses the dispatch and returns the codes above.
A blocked preview is not a hard block from the preview itself; it is a
prediction of the enforcement that follows. Schedule at the returned
`next_allowed_at` instead of polling.

**Tenant fix.** For your own tenant window, widen, narrow, or disable
it under Settings → Timezone Policy. For the federal and state guards,
schedule inside the window — no toggle exists. For an unresolved
timezone, set the org-level `unknown_timezone_policy` knob (`skip` to
allow unresolved recipients, `deny` to fail closed) or correct the
recipient number so it resolves.

**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_..."
```

**Escalate.** A `next_allowed_at` that contradicts the window you
configured, or a real E.164 number that fails to resolve, is the only
ticket class — open it with the destination and the `meta.request_id`
from the envelope. The full enforcement forks are on
[Quiet-Hours Preview](/compliance/quiet-hours-preview).

***

## 5. DNC / RND pre-flight

**`DNC_CONTACT` / `DNC_NUMBER` — 422.** The recipient's contact row
carries `dnc=true`, or the number sits in a scrubbed DNC source. This
gate fires **only once you opt in** (`dnc_sync_enabled`) — otherwise
the DNC scrub is not in the path. The fix is to lift the recipient
from the DNC list with a documented reason, or do not send. Sources,
freshness, and the check endpoint are on
[DNC Scrubbing](/compliance/dnc-scrub).

**`DNC_SYNC_NOT_ENABLED` — 403.** The pre-flight `GET /dnc/check` or
`POST /dnc/scrub` refused because the org never enabled the scrub or
the sync feed has not yet synced. Enable `dnc_sync_enabled`; a synced
snapshot retires the gate.

**`RND_CONTACT` / `RND_REASSIGNED` — 422.** The number was scrubbed
against the FCC Reassigned Numbers Database and matched a reassigned
line — the prior owner's consent does not transfer to the new
subscriber. The gate is opt-in per the RND flag; the lifecycle,
single-number check, and batch pre-campaign flow are on
[RND Scrub](/compliance/rnd-scrub).

**Re-check the posture.** Run the pre-flight read the send path
enforces, without performing a send:

```bash theme={null}
curl "https://api.orbit.devotel.io/api/v1/compliance/dnc/check?phone=%2B14155550100" \
  -H "X-API-Key: dv_live_sk_..."
```

Every served payload carries `federal_feeds_synced` and
`intl_feeds_synced` so you see the live feed state — when either is
`true` the check serves directly; when both are `false` the per-org
opt-in is required first.

**Escalate.** Never owed for a genuine DNC or RND match — the fix is
the list lift or do not send. If the feed stays `synced: false` past a
re-enable, open a ticket with the check response payload.

***

## 6. `HIPAA_BAA_REQUIRED` — the BAA lifecycle 422

**What fired.** HIPAA mode is opted-in and the send's audience or
content matched PHI, so the workspace refused PHI-bearing traffic
until your Business Associate Agreement is `executed` and in-term.
This is the one `422` that is owed by a lifecycle step rather than a
per-recipient gate — the BAA state machine gates every PHI send until
the agreement is current.

**Tenant fix.** Execute the BAA flow — attest PHI scope, preview, and
e-sign by typing the name — on [BAA](/compliance/baa). HIPAA mode itself
stays off until the BAA reads `executed`, so the gate is not just
"re-send later"; the agreement is the prerequisite.

**Re-check the posture.**

```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 the send stays
blocked. The full posture, PHI vocabulary, and the checklist runbook are
on [HIPAA](/compliance/hipaa) and
[HIPAA checklist runbook](/compliance/hipaa-checklist-runbook).

**Escalate.** For a workspace-role block on the BAA flow itself — a
403 on the execute endpoint rather than the `422` on the send — the
escalation path is on
[Compliance send-gate error codes](/compliance/troubleshooting-compliance-error-codes).
A `5xx`-shaped `HIPAA_BAA_GATE_DB_FAIL` is transient: retry with
backoff, then open a ticket with `meta.request_id` if it persists.

***

## Worked flows

**1. SMS to a recent STOP reply.** `422 SUPPRESSION_BLOCKED` — the
recipient replied STOP last week, which wrote a scope `all` row.
Honour it and do not send, or reverse the suppression through the
Consent API on
[Opt-Out & Suppression Lists](/compliance/opt-out-suppression) if they
re-opted in.

**2. Marketing send, no consent on file.** `422 CONSENT_FALSE` — the
contact has no consent row for the channel. Record an opt-in through the
Consent API with the GDPR evidence fields, re-check with
`GET /compliance/consent/lookup`, then re-send.

**3. Voice campaign at 10 PM recipient-local.**
`422 TCPA_DIALING_WINDOW_BLOCKED` (no `FEDERAL` in the code) — this is
your own tenant window. Reschedule at the `next_allowed_at` from a
preview, or widen the window. A code carrying `FEDERAL` is the one
platform-owned guard: schedule, no toggle.

**4. DNC scrub gated before a campaign.** `403 DNC_SYNC_NOT_ENABLED`
on `GET /dnc/check` — enable `dnc_sync_enabled` in compliance settings;
once a feed snapshot is synced the check serves directly. A subsequent
`DNC_CONTACT` on the send means a matched number: lift with a
documented reason or exclude it.

**5. PHI campaign, BAA pending.** `422 HIPAA_BAA_REQUIRED` — the
campaign audience is PHI-adjacent and the BAA reads `pending`. Execute
the BAA flow, re-read it with `GET /compliance/baa`, then relaunch.

***

## When nothing fits

If a `422` persists past the posture fix above, or the code does not
appear in the table, open a ticket carrying the code, the HTTP status,
the `meta.request_id` from the envelope, the referencing asset id
(sender id / campaign id / contact id), and the destination country.
The full send-gate error-code routing surface — including the
sender-identity, regional, policy-scan, and compliance-profile codes
that are not `blocked`-class — is on
[Compliance send-gate error codes](/compliance/troubleshooting-compliance-error-codes).

***

## Cross-reference map

Each per-code topic here links out to the page that owns the gate's
full lifecycle:

* [Opt-Out & Suppression Lists](/compliance/opt-out-suppression) —
  suppression entry points, channel scopes, bulk CSV import, and the
  re-opt-in.
* [Consent Management & Receipts](/compliance/consent-management) —
  the consent record, the lookup status states, double opt-in, and the
  GDPR evidence fields.
* [Quiet-Hours Preview](/compliance/quiet-hours-preview) — advisory
  vs. enforced, the voice enforcement forks, and the
  `next_allowed_at` semantics.
* [DNC Scrubbing](/compliance/dnc-scrub) — sources, freshness, the
  check endpoint, and the fail-open caveat.
* [RND Scrub](/compliance/rnd-scrub) — the FCC Reassigned Numbers
  Database, the opt-in flag, and the batch pre-campaign flow.
* [HIPAA](/compliance/hipaa) and [BAA](/compliance/baa) — the BAA
  state machine, the e-sign flow, and the PHI vocabulary.
* [Send Gates](/compliance/send-gates) — the canonical pre-send gate
  inventory.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.