Skip to main content

The voice-broadcast model

A voice broadcast is the one-shot “call these contacts, play a message” use case. This page names where that use case sits in the outbound model — beside the dialer that connects answered calls to live agents and the multi-step campaign engine — and ties together the runway a broadcast travels: the campaigns backbone it rides, the three audio sources it can carry, the gating chain it must clear, and how settled cost and ROAS attribution land afterward. Read this once and every page of broadcast documentation points at the same model.

The taxonomy — broadcast vs dialer vs multi-step campaign

Orbit’s outbound voice surface has three distinct modes. Picking between them is a one-time architectural read, not a per-campaign decision: Broadcast owns exactly one thing — the voice-channel blast. The dialer owns agent-handoff dialing (preview, progressive, predictive, and agentless mode, where the scheduler dials and routes to a recorded broadcast or an AI voice agent). The multi-step campaign owns sequencing across channels. A broadcast is never a dialer campaign: it creates no dispositions, consumes no agent presence, and its agentless analog is just the recorded-broadcast route inside the dialer model.

The campaigns backbone

Everything the Outbound → Voice Broadcasts wizard saves is an ordinary campaign record — one POST /campaigns call with channel: "voice" and type: "blast". There is no separate broadcast object:
  • Same endpoints. Create, read back, launch, pause, resume, and cancel through the campaigns API; audience preview runs POST /campaigns/audience/preview with channel: "voice" so suppression and do-not-call exclusions show before you spend anything on audio.
  • Same status lifecycle. The broadcast moves through draft → scheduled → sending → running → completed exactly as campaign lifecycle defines; paused, aborting, and the terminal statuses mean the same things.
  • Same voice metadata. The wizard packs the TTS voice id, language, business-hours flag, and caller-id override into the campaign’s variables bag, which the dispatch provider reads when it picks up the call stream.
Because there is only one object, none of the broadcast UI’s behavior is special-cased — a paused broadcast, a reverted approval, or a voice-cost-rollup read all exercise the campaigns spine.

The authoring lane — three payload sources

The broadcast composer offers three audio sources, and the choice rides the campaign record in two forms:
  • Pre-recorded audio upload. The clip (MP3, WAV, or M4A up to 25 MB) uploads to the voice asset store first (POST /voice/assets); the returned audio:asset:<file_id> handle becomes the campaign’s message_template, so the dispatch resolves the asset at send time even if the signed preview URL has expired.
  • TTS text. The script body lands directly in message_template; metadata.voice_id and input.language in variables pick the stock or cloned voice and its language. Contact tokens ({{first_name}}, {{last_name}}, custom fields) resolve per recipient at render time.
  • Voice clone. A clone created under Voice → Voice Clones (with signed consent and a sample script) is just another entry in the TTS voice picker — the campaign stores the clone id in voice_id and lives the TTS-text path from then on.
The A/B lane is the same record plus ab_test_enabled: true; each variant carries its own script body, and the winner-selection rules (30 answered calls per variant, 24-hour evaluation window, 10% lead or confidence) score the variants afterward.

The gating chain — TCPA, quiet hours, approvals

A voice broadcast must clear every gate the voice channel declares, evaluated in this fixed order:
  1. TCPA federal voice guard — the hard 8 AM–9 PM recipient-local window. A scheduled broadcast that lands outside it fails the launch with 422 TCPA_FEDERAL_DIALING_WINDOW_BLOCKED; the window is not configurable. See TCPA federal voice guard.
  2. Quiet hours — the workspace-level per-recipient dialing window (business_hours_only on the wizard). The composer flag forwards through variables.business_hours_only, and the dispatch defers per recipient against the tenant-owned quiet window rather than reverting to a global clock. See send gating and quiet hours.
  3. Action approvals — when the org’s trust tier requires supervisor sign-off, the launch returns pending_approval and parks in Outbound → Approvals instead of dispatching. See action approvals model.
All three are tenant-owned controls: TCPA is federally fixed, quiet hours are workspace-defined, approvals are trust-tier-defined. Recording-consent acknowledgement (recording_consent_acknowledged: true) is a fourth, unconditional gate on every voice campaign create — the wizard affirms it on your behalf.

Preflight cost preview and approvals flow

Before the first recipient dials, the wizard reads the same server-side aggregate the campaign page uses (GET /campaigns/:id/voice-cost-rollup) and renders the projected per-minute pricing for the draft. Check the returned sufficiency fields against the wallet before launch — a broadcast that clears the gates but overdraws the wallet returns 402 at the create call. The approvals queue then treats the identically-shaped record the same way it treats any campaign: approvers clear the queue and the launch proceeds.

Settlement and attribution

Voice billing settles by the minute after the call stream drains; a broadcast’s settled cost surfaces through the campaigns spine:
  • One-minute billing increments — the rollup charges in one-minute ticks per answered call; short messages price small, long ones price linearly with duration. Per-call minimums apply where the carrier contract declares them; the rollup surfaces either shape in the settled fields.
  • ROAS attribution — post-settlement, GET /campaigns/:id/roas joins the settled spend against conversion events to produce attributed revenue with last-touch and multi-touch funnels (plus holdout-incremental revenue when you ran a holdout cohort). A/B scoring reports against the same settled answer rates.
Settlement is terminal — after the campaign completes, cost and ROAS reads return the actual roll-up, not projections.

One worked example

The wizard creates exactly this campaign record when you press Create broadcast:
Post-settlement, the same id answers GET /campaigns/cmp_ab12cd34ef56 with status: "completed", the rollup returns settled totals instead of projections, and the ROAS attribution endpoint carries revenue against the settled spend — none of which requires a second object. The broadcast is one campaign record end to end.

See also