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

# Voice Guard: the Federal Dialing-Window Decision Check

> How the outbound-voice federal dialing gate decides allow or deny before a dial fires — where the gate is wired at every voice dispatch point, the decision inputs (recipient, timezone, local hour), the hard-block error and its reason enum, how the guard differs from your tenant-owned quiet-hours controls, and a worked blocked-dial walkthrough with the correction path.

# Voice Guard: the Federal Dialing-Window Decision Check

Outbound voice dispatch in Devotel Orbit passes one recipient-level
decision check before the call is placed: is this recipient reachable
under the US federal TCPA window — 8 AM to 9 PM recipient-local time —
at this moment? This page documents that check: the gates it runs at,
how the verdict is computed, the error surface a blocked dial returns,
and what distinguishes this guard from your tenant-owned quiet-hours
settings. The worked example at the end walks a flagged +1 recipient
through the correction path.

## 1. Where the voice firewall is deployed

The guard is wired at the dispatch decision point, not the campaign
definition. Every outbound voice dispatch channel consults it before
placing the call:

* **The public voice-dispatch API** — every `POST /voice/calls`-class
  dispatch request.
* **Dialer pacing workers** — predictive, progressive, preview, and
  agentless campaign dials.
* **Callback dispatch workers** — virtual-hold and scheduled callbacks.
* **The voice gateway pre-dial gate** — the final hop before the
  carrier egress.

All four consult the same shared decision module, so a verdict is
identical at every gate — there is no path that skips the check.
Every evaluation, allowed or blocked, emits an observability event,
so monitoring the gate's wire-up is a count question, not a code
question. Blocked evaluations log with the recipient number masked.

## 2. How the gate evaluates

The decision is a short, deterministic chain. Non-+1 recipients and
non-NANP numbers skip the federal window entirely; everything else is
evaluated against recipient-local time.

1. **Recipient check** — the guard reads the E.164 destination. A
   non-US, non-NANP recipient is allowed immediately (reason
   `non_us_recipient`); tenant quiet-hours or state overlays may still
   apply downstream, but the federal wire is skipped.
2. **Timezone resolution** — for a +1 recipient the guard resolves the
   timezone from the NANP area-code map. If no map entry resolves, the
   check fails closed: because TCPA jurisdiction cannot be disproved,
   the dial is denied rather than guessed (reason
   `timezone_unresolved`).
3. **Local-hour evaluation** — the resolved timezone converts the
   evaluation instant into a recipient-local hour. An unresolvable hour
   fails closed the same way.
4. **Window comparison** — 8 AM to 9 PM recipient-local is allowed
   (reason `inside_federal_window`); anything else is denied, and the
   result carries the UTC instant the window next opens
   (`next_allowed_at`), computed with DST-safe hour arithmetic.

The guard supports three evaluation modes at the integration points
that ask for a decision without enforcing it: **enforce** (the default
— a block denies the dial), **warn** (returns the verdict and logs it,
for dry-run pacing), and **preview** (returns the verdict silently,
for scheduling previews).

## 3. What a hard block means

A blocked evaluation in enforce mode returns HTTP `422` with the error
code `TCPA_FEDERAL_DIALING_WINDOW_BLOCKED`. That code is intentionally
distinct from `TCPA_DIALING_WINDOW_BLOCKED` (your tenant quiet-hours
gate), so audit filtering can separate federal-window denials from
org-configured window denials.

The error body carries a structured detail object so your retry logic
never has to parse message text:

| Field             | Meaning                                                                                                   |
| ----------------- | --------------------------------------------------------------------------------------------------------- |
| `channel`         | Always `voice` on this gate.                                                                              |
| `reason`          | One of the enum below — read before planning.                                                             |
| `timezone`        | The resolved recipient timezone, when resolved; `null` on fail-closed.                                    |
| `local_hour`      | The recipient-local hour the decision evaluated, when computable.                                         |
| `next_allowed_at` | UTC ISO instant the window reopens. Present on `outside_federal_window`; `null` on `timezone_unresolved`. |
| `regulation`      | `47_USC_227_b_1_B` — the statutory hook the guard enforces.                                               |

The `reason` enum:

| `reason`                 | Verdict | Your plan                                                            |
| ------------------------ | ------- | -------------------------------------------------------------------- |
| `non_us_recipient`       | allowed | Proceed; check tenant quiet-hours/state overlays if enabled.         |
| `inside_federal_window`  | allowed | Proceed.                                                             |
| `outside_federal_window` | blocked | Schedule the dial to `next_allowed_at`.                              |
| `timezone_unresolved`    | blocked | Fail-closed. Fix the contact's timezone (see the walkthrough below). |

## 4. How this differs from your tenant-owned controls

Every other compliance gate — tenant quiet-hours, DNC/consent, country
blocks, the org `unknown_timezone_policy` (`skip` / `enforce_utc` /
`deny`) — is something you own: it is configurable per tenant, defaults
open, and fails open when resolution is impossible.

This guard is the one exception. It accepts no tenant toggle and no
per-tenant opt-out, and its timezone-unresolved path always fails
closed regardless of your org policy setting. The federal
$500–$1,500-per-call penalty (47 U.S.C. § 227(b)(1)(B)) is the reason
that asymmetry exists: the guard checks one input (the recipient's NANP
timezone) and owns one window (8 AM–9 PM), independent of anything you
configure. Any override posture — for example a tenant state-list
exception — belongs in the tenant quiet-hours layer, never here; this
gate has no exemption knobs.

State overlays still matter, but they intersect downstream: the
[state calling windows](/compliance/state-calling-windows) overlay can
only narrow within the federal window (e.g. Florida's 8 PM close); it
never reopens a federally closed hour. The relationship is spelled out
on [quiet-hours preview](/compliance/quiet-hours-preview).

## 5. Worked example: a +1 recipient gets flagged

A campaign dial targets `+1 305 555 0101` at 22:40 recipient-local
(11:40 PM at the evaluation instant — before the dialer's batch spins
up): the area-code map resolves `America/New_York`, local hour 22 is
outside 8–21, and the enforce-mode dispatch receives:

```json theme={null}
{
  "error": {
    "code": "TCPA_FEDERAL_DIALING_WINDOW_BLOCKED",
    "message": "US TCPA federal dialing window (8 AM–9 PM America/New_York) — outbound voice call blocked. Next allowed at 2026-09-20T12:00:00.000Z.",
    "details": {
      "channel": "voice",
      "reason": "outside_federal_window",
      "timezone": "America/New_York",
      "local_hour": 22,
      "next_allowed_at": "2026-09-20T12:00:00.000Z",
      "regulation": "47_USC_227_b_1_B"
    }
  }
}
```

The correction path reads the `reason` first:

* **`outside_federal_window`** — schedule the dial to
  `next_allowed_at`. Queue workers re-poll on that instant; a campaign
  launch holds to the smallest `next_allowed_at` across recipients.
* **`timezone_unresolved`** — the recipient's area code resolved to no
  timezone entry (common on Canadian or Caribbean +1 numbers). Fix the
  contact record's timezone, then re-dispatch; without the correction
  every retry fails closed identically.
* **`non_us_recipient` / `inside_federal_window`** — no action; the
  verdict is advisory for downstream gates only.

Because `next_allowed_at` is UTC ISO and DST-safe, schedule against
that field and never re-derive the opening hour in your own scheduler.

## See also

* [Quiet-hours preview](/compliance/quiet-hours-preview) — the
  read-only "would this dispatch now" endpoint across channels
* [US state calling windows](/compliance/state-calling-windows) — the
  mini-TCPA overlays that narrow the federal window
* [TCPA posture across SMS and voice](/guides/tcpa-quiet-hours-and-windows) —
  the tenant-owned control map
* [Troubleshooting compliance error codes](/compliance/troubleshooting-compliance-error-codes) —
  the full error-code index including both `TCPA_FEDERAL_DIALING_WINDOW_BLOCKED`
  and `TCPA_DIALING_WINDOW_BLOCKED`
