Skip to main content

Cross-schedule planner: operator walkthrough

The cross-schedule planner on the Campaigns page spreads concurrent campaigns across one shared hourly cap and recommends a start time for each. This guide walks the planner itself, and then the part a plan cannot show you: how a recommended slot composes with the controls that still evaluate when a message actually sends. For the allocation model behind the plan, see the cross-campaign send allocator; for the org defaults the planner starts from, see Settings → Campaigns.
The planner is advisory. Generating a plan never schedules, launches, or mutates a campaign, and every recommendation is re-checked by the live send gates at dispatch.

Open the planner and build a plan

  1. Open the Campaigns hub and open the planner with Spread sends.
  2. Pick the campaigns to spread. Only campaigns that can still take a start time are listed: drafts, scheduled, and paused. Each row shows its remaining audience (“N to send”); a campaign with nothing left to send is listed but cannot be picked. The preview arbitrates up to 100 campaigns per request, so split a larger calendar into two plans.
  3. Set Window start and Window end. The start cannot be in the past and the end must be after the start. The form opens on now to seven days out and pre-fills your org defaults from Settings → Campaigns where they are set; overriding them here never changes the org default.
  4. Set Global cap / hour: the maximum messages per hour across the selected campaigns together. This is your organization’s shared throughput budget, the same figure frequency caps describe per contact but applied to total volume.
  5. Optionally switch on Quiet hours and enter a start and end hour. Wrap-around windows work: 21 to 9 plans around evening and early morning. The hours are entered in your local time zone; a banner above the fields and a chip on the field row name that zone, and rule out UTC and any fixed workspace or campaign zone. The planner sends that zone’s offset (tz_offset_minutes) with the request.
Click Generate plan. Each campaign row returns its recommended start (the first scheduled slot, offered as the scheduled_at to apply), the scheduled count, and any overflow that did not fit the window; the summary row shows total scheduled versus requested and the peak slot utilization against the cap. Applying a recommendation happens through the Schedule link on each row, which opens the campaign’s own schedule path. Any edit to the form clears the rendered plan, so what you read always matches the inputs.

What the planner plans around, and what it only warns about

The planner’s two time controls and the cap behave differently at send time: Hold that last row in mind when you size a spread. The plan arbitrates the selected campaigns against one shared hourly cap; it has no view of per-recipient rolling caps, unselected campaigns, or state calling windows. A plan is a good starting schedule, not a delivery guarantee. The note under the planner’s quiet-hours fields says the same in one line: the window shapes the plan only, and each recipient’s own local quiet hours still apply at send time.

What still evaluates at send time

A recommended slot is a proposal. When the scheduled send fires, it walks the same gates as any other send:
  • The federal voice window. US voice campaigns and dialer calls send only inside 8 AM to 9 PM recipient local. This guard is platform-owned: no tenant setting and no planner slot moves it.
  • State overlays. A set of states narrow the federal window further with earlier evening cutoffs and blocked-day rules; see US state calling windows for the current map. A slot that is fine federally can still land in a state hold.
  • Quiet hours, recipient-local. The planner’s quiet-hours input shapes the plan in your zone; enforcement re-evaluates each recipient’s own local window (row window, org fallback, or the 21:00 to 09:00 platform default), hour-granular and end-exclusive.
  • Per-recipient frequency caps. Every send checks the caps you created; a send past its cap is rejected 429 FREQUENCY_CAP_EXCEEDED. Because the planner cannot arbitrate these, two campaigns planned a day apart can still collide on a contact capped at one message per day.
  • Opt-out and suppression. Suppressed recipients never receive a scheduled send, planned or not.
When a gate holds a send, the held record reports the reason and next_allowed_at, the recipient-local instant the gate reopens; GET /api/v1/compliance/quiet-hours/preview returns the same decision for one recipient before you send. For the cap half, GET /api/v1/contacts/:id/cap-status returns the live per-channel usage and when each cap resets, so you can read back exactly why a planned recipient rejected a send. For how the caps sit beside the when-controls in a compliance posture, see frequency caps as a TCPA litigation-risk control.

Worked example: two campaigns, a wrap-around quiet window across a DST cutover, and a state overlay

Setup. Campaign A (2,000 recipients, high priority) and Campaign B (1,500 recipients, low priority), spread from Saturday to Monday. Global cap 500/hour. Planner quiet hours 21 to 9. The window crosses the US fall DST cutover, when clocks in observing zones repeat the 1 AM hour on Sunday.
  1. Plan. The planner excludes the 21:00 to 09:00 slots in the zone you entered. Across the cutover, quiet hours are resolved on local wall-clock: the repeated 1 AM hour stays inside the quiet window rather than opening a surprise send slot, and the morning reopen happens once, at local 09:00. This is the same behavior the single-campaign guide describes in quiet hours and the DST crossover; the planner’s spread inherits it. Generate the plan: Campaign A claims the Saturday and Sunday morning slots to cap, Campaign B defers into later slots, and a slice of B shows as overflow because weekend capacity ran out.
  2. Apply. Follow each row’s Schedule link and apply the recommended start through the campaign’s normal schedule path. Nothing about the plan binds the runtime.
  3. Dispatch, first hold. Campaign B’s 5 PM slot reaches a recipient whose number resolves to a state with an overlay that closes earlier in the evening than the federal window. The send is fine federally but lands in a state hold; the held record carries next_allowed_at at the overlay’s reopen, and the campaign resumes on its own when the window opens. One hold like this needs no action: the runtime re-queues against next_allowed_at.
  4. Dispatch, second hold. A run of holds pushes some of B’s sends into the next day, where the contact has already taken Campaign A’s message and sits at its per-day cap. The send is rejected 429 FREQUENCY_CAP_EXCEEDED rather than delivered late over cap. Read the contact’s position with GET /api/v1/contacts/:id/cap-status.
  5. Resolve. The cap is tenant-owned, so the resolution is yours: widen B’s spread window so holds clear before the cap day rolls, lower B’s volume, exclude the capped segment, or adjust the cap rule itself per frequency caps. The planner is not the resolution path for a cap collision; it never sees per-recipient caps, and no plan can override one.

When the planner refuses, and what to do

See also