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

# Per-campaign quiet hours: override the window on a campaign row

> Set quiet_hours_enabled, quiet_hours_start and quiet_hours_end on a single campaign, understand how the row window resolves against the org fallback and the platform default, and verify deferrals before launch.

# Per-campaign quiet hours: override the window on a campaign row

The org fallback on **Settings → Campaign limits** sets one quiet-hours
posture for a group of campaigns. When one campaign needs a different
window, a tighter one for a sensitive list or a shifted one for a
regionally concentrated audience, set the window on the campaign row
itself with three fields: `quiet_hours_enabled`, `quiet_hours_start`,
and `quiet_hours_end`, accepted on campaign create and update.

The row window is a negative filter: *do not send during these
recipient-local hours*. This guide covers what the three fields mean,
where to set them in the dashboard and over the API, how they resolve
against the org fallback and the platform default, how they combine
with a send window, which sends read them, and how to verify what each
recipient will actually receive.

## The control

| Field | Type | Meaning |
| - | - | - |
| `quiet_hours_enabled` | boolean | `true` arms the row filter; `false` switches it off. |
| `quiet_hours_start` | integer, 0–23 | First quiet hour, recipient-local (inclusive). |
| `quiet_hours_end` | integer, 0–23 | Hour the window reopens, recipient-local (exclusive). |

Semantics to plan around:

* **Default off.** While the fields are absent the campaign carries no
  row-level window, so nothing defers at row level; the send resolves
  against the org fallback and the platform default like any other
  campaign. Absent means "no row-level deferral", not "no quiet hours
  anywhere".
* **`enabled: false` versus absent.** Passing
  `quiet_hours_enabled: false` persists an explicit decision on the
  campaign: a later update that omits the quiet-hours fields leaves the
  stored value untouched, so the explicit off survives partial updates.
  At send time `false` and absent behave the same way (no row window,
  resolution continues to the fallback), and neither suppresses the
  always-on platform default.
* **Whole hours only.** Hours are integers 0–23; the API rejects
  non-integer or out-of-range values at the boundary.
* **Cross-midnight windows.** `quiet_hours_start` greater than
  `quiet_hours_end` wraps overnight: `21` → `7` is quiet from 21:00
  through 06:59 recipient-local and reopens at 07:00.
* **End-exclusive.** The window includes the start hour and stops
  before the end hour: with `21` → `9`, a send at 08:xx local defers and
  a send at 09:xx goes.
* **`start` equal to `end`** reads as quiet at every hour and defers
  every send. Treat it as a misconfiguration.

## Where to configure it

### Dashboard

Two surfaces show the row window where you plan a launch:

* **Cross-schedule planner** (Campaigns → *Spread sends*). The
  planner's quiet-hours toggle and start/end inputs take a window
  alongside the shared hourly cap, and a chip on the input row names
  the time zone those hours are entered in. The planner is advisory:
  it shapes the recommended schedule, and the note under the inputs
  says it plainly: at send time, each recipient's own local quiet
  hours still apply.
* **Launch preview.** The campaign's launch preview shows a
  **Quiet-hours deferred** tile: an estimate of how many sampled
  recipients would defer inside the window that resolves for this
  campaign, with the sample size underneath (`quiet_hours.skipped_estimate`
  in the preview payload). When no window applies, the tile says so.

The API below is where the three fields are written.

### API

The same three fields are accepted on create and on update. Arm a
21:00 → 09:00 window on an existing campaign:

```bash theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/campaigns/$CAMPAIGN_ID" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "quiet_hours_enabled": true,
    "quiet_hours_start": 21,
    "quiet_hours_end": 9
  }'
```

An EU-shaped overnight window, 22:00 → 07:00:

```bash theme={null}
curl -X PUT "https://api.orbit.devotel.io/api/v1/campaigns/$CAMPAIGN_ID" \
  -H "Authorization: Bearer $ORBIT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "quiet_hours_enabled": true,
    "quiet_hours_start": 22,
    "quiet_hours_end": 7
  }'
```

Read the campaign back with `GET /api/v1/campaigns/$CAMPAIGN_ID` to
confirm the stored window before launch, and switch the row filter off
with `"quiet_hours_enabled": false`.

## Resolution order

When a campaign send is evaluated, exactly one window applies,
resolved in this order:

1. **Campaign row** — `quiet_hours_start` / `quiet_hours_end` on the
   row, when the row filter is enabled, wins for that campaign only.
2. **Org fallback** — *Settings → Campaign limits → Default quiet
   hours*, or `GET`/`PUT /api/v1/campaigns/quiet-hours/settings`. Every
   row without its own window inherits this.
3. **Platform default** — 21:00 → 09:00 recipient-local. This is the
   floor; the fallback and any row override can only narrow it.

Whichever layer supplies the window, enforcement is recipient-local,
hour-granular, and end-exclusive, as described above. The `GET` on the
fallback echoes `platform_default_start` / `platform_default_end`, so
you can always see which regime a silent row will resolve to.

## Quiet hours versus `send_window`

A campaign can also carry a send window
(`send_window.start_local_hour` / `send_window.end_local_hour`), the
positive twin of this control: *only send during these recipient-local
hours*. Quiet hours say when not to send; a send window says when to
send.

| | Quiet hours (this page) | `send_window` |
| - | - | - |
| Kind | Negative: hold sends inside the window | Positive: send only inside the window |
| Fields | `quiet_hours_enabled/start/end` | `send_window.start_local_hour/end_local_hour` |
| Timezone | Recipient-local | Recipient-local |
| Default | Off | Off |

When both are set, a send must satisfy both, so the tighter bound wins
in practice. Worked example: `send_window` 9 → 17 with a row quiet
window 12 → 14.

| Recipient-local hour | Inside send window? | Inside quiet window? | Outcome |
| - | - | - | - |
| 08:00 | No | No | Deferred, outside the send window |
| 10:00 | Yes | No | Sent |
| 13:00 | Yes | Yes | Deferred, inside quiet hours |
| 18:00 | No | No | Deferred, outside the send window |

Pick by what you know: use a send window when you know the good hours
(local business hours for a B2B list), quiet hours when you know the
bad ones (evenings and early mornings for a consumer list). For
send-window tuning, see
[Send-window optimization](https://docs.orbit.devotel.io/guides/message-scheduling-send-window-optimization.md).

## Which sends read the row window

* **Campaign and journey sends.** Sends that originate from a campaign
  or a journey resolve to the marketing lane, so the row window
  applies to them: blasts, drips, and journey steps alike.
* **Direct API transactional sends.** A message sent directly over the
  API without a campaign never reads a campaign row; the row window
  cannot defer it. Transactional sends stay governed by the org
  channel gate and the compliance rails, not by campaign posture.
* **Voice.** The row window narrows marketing send timing only. It
  never relaxes the always-on federal dialing-window guard for US
  campaign and dialer voice; that guard is platform-owned and no tenant
  setting touches it.

## Verify and debug

Read the window the way the send path will, before launch:

1. **Launch preview.** The *Quiet-hours deferred* tile estimates the
   deferred share of the sampled audience for the window that resolves
   on this campaign. A surprising number here is almost always a wrong
   window on the row or a fallback you forgot about.
2. **Preview endpoint.**
   `GET /api/v1/compliance/quiet-hours/preview?phone=…&channel=…`
   returns the decision for one recipient without sending: whether the
   send would hold, the window that applied, and `next_allowed_at`,
   the recipient-local instant the gate reopens. Pass
   `&timezone_override=<iana-name>` when your CRM knows the
   recipient's zone better than the area code does.
3. **The held record.** A deferred send carries a `quiet_hours` block
   with the reason, the window edges in recipient-local time, and
   `next_allowed_at`; the preview returns the same fields, so you can
   match any deferral back to the layer that applied.

How a deferral surfaces depends on the send type. A campaign or
journey send is scheduled to the next open: the campaign stays live
and resumes on its own when the window closes, per
[Campaign lifecycle](https://docs.orbit.devotel.io/concepts/campaign-lifecycle.md). A one-shot message
held by a gate reports blocked with `next_allowed_at` to re-queue
against. When a block looks wrong, the recipient should have been in
allowed hours, work the layer table in
[Troubleshooting quiet-hours false positives](https://docs.orbit.devotel.io/troubleshooting/quiet-hours-false-positives.md);
for the decision model behind the three layers see
[Quiet hours FAQ](https://docs.orbit.devotel.io/compliance/quiet-hours-faq.md).

## Group posture playbook

Setting the row window on every campaign does not scale, and most orgs
do not need to. The resolution order is designed for one posture per
group:

1. Set the **org fallback** once to the group's window on
   *Settings → Campaign limits → Default quiet hours*.
2. Leave the rows silent so they inherit it.
3. Override only the one or two outlier rows that genuinely differ:
   the sensitive list that needs 20:00 → 08:00, the regional blast
   that can run later.

State the limits of the row control honestly when you plan: hours
only, in whole-hour steps, evaluated recipient-local. There is no
day-of-week scoping on a campaign row; day-of-week control lives on the
org channel gate (`allowed_days`), not on the campaign, and
minutes-level precision does not exist at any quiet-hours layer.

## See also

* [Campaign limits: audience cap and default quiet hours](https://docs.orbit.devotel.io/guides/campaign-limits-quiet-hours.md):
  the org fallback this row window overrides.
* [Quiet hours configuration](https://docs.orbit.devotel.io/guides/quiet-hours-configuration.md): every
  surface that reads your quiet-hours posture.
* [Quiet hours FAQ](https://docs.orbit.devotel.io/compliance/quiet-hours-faq.md): the resolution order
  and the one-posture-per-group model.
* [Troubleshooting quiet-hours false positives](https://docs.orbit.devotel.io/troubleshooting/quiet-hours-false-positives.md):
  when a block looks wrong.
* [Send-window optimization](https://docs.orbit.devotel.io/guides/message-scheduling-send-window-optimization.md):
  the positive twin of this control.


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