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

# Build a blast or drip campaign with the create wizard

> Walk every page of the campaigns create wizard in the dashboard — setup, audience (lists, segments, manual picks, CRM), message, schedule (fixed time or recurrence), sending readiness, localization, compliance review, launch — plus drafts, launch gates, and post-launch analytics.

# Build a blast or drip campaign with the create wizard

The create wizard is the dashboard path for turning on a blast or drip campaign without writing a request. It runs five ordered steps — Setup → Audience → Message → Schedule → Review — and renders the readiness, localization, and compliance panels inline before launch. This guide walks each step in order, maps every form field onto the `POST /campaigns` body so you can switch to the API mid-flow, covers drafts, the launch validation gates, and what the campaign detail page gives you after launch.

Two worked examples land at the end: an SMS promo blast, and a three-step onboarding drip whose second step goes out on WhatsApp.

## 1. Wizard or API — pick the right entry point

Use the wizard when a person is driving the campaign: it enforces validation on every step transition, runs the pre-flight dry-run visually, and gates Launch on the same checks the API enforces server-side. Use the API (see [Send a campaign end-to-end](/guides/campaign-end-to-end)) when you're provisioning campaigns from your own system, templating them, or running them from CI.

Launch requires an owner, admin, or developer seat — the same role gate `POST /campaigns` enforces. A billing or supervisor seat can compose a campaign but the Review step's launch call is rejected with `403 INSUFFICIENT_PERMISSIONS`; the wizard keeps your input locally so an owner can finish the send. Everything else in this guide — drafts, previews, dry-runs — works in either surface, because the wizard is a client of the same public API.

The wizard lives at **Outbound → Campaigns → Create campaign** in the dashboard navigation.

## 2. Step 1 — Setup: name, type, and channel

Setup picks the campaign type (`blast`, `drip`, or `journey`), a name, an optional description, and the primary channel. It also validates the omnichannel fallback chain when you stack channels.

* **Name** (1–200 chars), mapped to `name`. **Description** (≤1000 chars) → `description`.
* **Type** → `type`. Blast and drip stay in this wizard; `journey` and ad campaigns route to their own surfaces (the journey canvas, or the ads console).
* **Channel** → `channel`. The selector lists every live or beta channel from the channel registry; "coming soon" channels render disabled and can't be submitted.
* **Fallback chain** (optional) → `channels`. An ordered list of up to 5 channels. Each non-final entry carries `fallback_on` (`failed` / `no_delivery` / `no_engagement`) and `fallback_after_seconds` (60–604,800 seconds). The last entry is terminal. The wizard enforces the same invariants the API does: monotonic order, no duplicate channels, no fallback fields on the final entry. A single-channel campaign sends only the top-level `channel`.
* **Sender selection (SMS/MMS only)** — an optional "Send from" picker for your dedicated numbers, and an optional Messaging Service selector that maps a campaign to a sender pool, opt-out list, and throughput cap. Both persist to `variables.from` and `variables.messaging_service_id`; leave either empty to keep account-wide auto-select. Outbound SMS/MMS always terminates through the Devotel wholesale network either way — this chooses which of your identities it presents.

### The RCS sender panel

Picking `rcs` mounts a per-channel sender panel under the capabilities card. It derives its state from your RCS sender roster with three outcomes: **verified** (the campaign originates as a carrier-verified agent, with branding: "Sends from your verified sender"), **pending** (agents mid-verification — build now, launch when cleared), or **none** (no sender set up; a deep-link to Settings → Channels → RCS). Whichever state, the panel also notes the automatic SMS fallback: recipients whose handset or carrier can't receive RCS are delivered by SMS on the same dispatch, and you can additionally add SMS as an explicit chain fallback for the no-delivery or no-engagement cases.

## 3. Step 2 — Audience: lists, segments, CSV, manual picks, CRM

Audience resolves who the send targets. Pick a strategy card:

| Strategy                                                                        | Maps to                                                              | Use it for                                          |
| ------------------------------------------------------------------------------- | -------------------------------------------------------------------- | --------------------------------------------------- |
| **All Contacts**                                                                | `audience_type: "all"`                                               | Every contact in the workspace.                     |
| **Contact List**                                                                | `audience_type: "list"` + `audience_id`                              | A saved list (uploads, manual curation).            |
| **Segment**                                                                     | `audience_type: "segment"` + `audience_id`                           | A dynamic segment resolved at send time.            |
| **CSV upload**                                                                  | `audience_type: "csv"` with addresses in `variables.csv_recipients`  | A one-off roster.                                   |
| **Choose contacts** (manual picker)                                             | `audience_type: "manual"` with ids in `variables.manual_contact_ids` | Hand-picked rosters — exec outreach, legal notices. |
| **CRM sources** (HubSpot list, Salesforce report / list view, Pipedrive filter) | `audience_source` descriptor                                         | Members pulled from a connected CRM.                |

The **Choose contacts** card mounts a searchable picker over your contacts: debounced search, a recent-contacts fallback when the query is empty, chip/remove handling, and a 10,000-contact ceiling matching the server-side audience limit. The picker submits raw contact ids; the send path re-resolves each one to a full audience entry at launch. Salesforce list-view sources additionally ask for a target object (Contact or Lead).

Below the strategy, an estimated recipient count updates — the wizard reuses the audience preview (`POST /campaigns/audience/preview`) net-projection so the count you see already discounts suppression rows, channel opt-outs, and unreachable addresses. The count snapshot is saved with the campaign (`variables.estimated_recipients`) so a scheduled send shares it with the Review step.

## 4. Step 3 — Message: content, templates, A/B variants

The composer holds the campaign body (`message_template`, up to 100,000 chars — sized for HTML email), personalization tokens in `{{token}}` form, and per-channel character counters for SMS and other short-body channels.

* **Template picker.** Load any approved template from your template library (the `/outbound/templates` collection) by name. Loading a template writes its body into the composer — so anything you start from stays editable before launch. Channels with pre-registered content (WhatsApp) resolve against approved templates rather than freeform copy.
* **Email subject** — email campaigns get a subject field (`subject`, ≤500 chars), interpolated with the same tokens at send time. Drips carry a per-step subject instead, so this field only applies to blast email.
* **A/B testing.** Enable to add a Variant B (and optionally C/D) with a traffic split. Two variants allow any integer split summing to 100 (presets 50/50, 70/30, 80/20 are shortcuts); three-plus variants get fine-grained per-variant allocations. You also pick the winner metric (delivered / opened / clicked / replied) and an optional holdout percent (≤50) for lift measurement. Everything here persists through a `variables.ab_test` structure plus variant rows synced at launch.
* **Personalization preview.** A recipient picker renders the body with a sample contact's fields substituted — custom fields (e.g. `{{customer_tier}}`) included — and the phone mock shows the resolved sender identity (a dedicated number or the shared Devotel sender for SMS; your brand name for brandable channels).

### Localization: the translate-locales dialog

The "Translate for locales" button calls the template translator (`POST /campaigns/templates/translate`) which rewrites the current body into one or more locales while preserving tokens and the opt-out instruction. You review each generated variant in a dialog — only variants you explicitly approve are saved onto the campaign as `variables.locale_variant_set`, and the send pipeline routes each recipient to the variant matching their contact's language, falling back to the base body when no variant matches.

When to translate vs. fork: use the locale variant set when one campaign with per-recipient language routing is the right unit of measurement. Fork into one campaign per locale instead when different locales need different send times, different sender registrations, or separate holdout/ROI accounting.

## 5. Step 4 — Schedule: fixed time, recurrence, throttling, windows

Schedule decides when and how fast the send fires.

* **Send now or later.** A one-off send (`recurrence: once` → no `variables.recurrence`) can fire immediately or at a fixed `scheduled_at` timestamp interpreted in the timezone you pick. The wizard rejects past instants and converts the wall-clock to a UTC ISO string via the same timezone you selected.
* **Recurrence.** For scheduled sends, optionally pick a cadence — daily, weekly (with weekday selection), monthly (with day-of-month), or custom cron (5 fields). Every recurring campaign requires an explicit end condition: never (requires the operator to tick the confirm box acknowledging indefinite sending — a hard gate, not a passive banner), after N occurrences, or on an end date. The recurrence block persists to `variables.recurrence` only when the send is scheduled and recurring, so a switched-back "Send now" send never inherits a stale cadence.
* **Throttle.** A messages/second ceiling (`throttle_rate`, 0–10,000). Zero means "no explicit ceiling" — the platform default of 50 msg/s applies.
* **Business hours.** Restricts sends to business-hours windows (`variables.business_hours_only`).
* **Number validation (HLR).** An optional per-recipient lookup (`variables.validate_numbers`) checked before send, priced separately from the message rate; the wizard projects its cost including recurring-occurrence totals.
* **TCPA window notice.** For voice and SMS, sends queue only in the 8 AM–9 PM recipient-local federal window; the step renders a banner explaining that out-of-window recipients are deferred rather than failed. The window is enforced server-side at send time; see the [send-gating model](/concepts/send-gating-and-quiet-hours).

## 6. Step 5 — Review: readiness, localization recap, compliance, launch

Review assembles the launch surface: the cost estimate, the sending-readiness panel, per-locale variant recap, the compliance checklist, and the launch/submit-for-approval action.

### Sending-readiness panel

Four enumerated rows fold the live preflight into a verdict (pass / attention / unverified — never a silent pass):

* **Channel** — a channel is selected.
* **Route** — outbound SMS/MMS always routes via the Devotel wholesale network; other channels report "unknown" rather than a fabricated pass (their setup happens under Settings → Channels).
* **Channel connection** — whether this account has a dedicated sending number for the channel. SMS-family is the only channel the preflight probes, so WhatsApp/RCS/voice/email connection reads "unknown" rather than green.
* **Sender identity** — the exact from-identity the send will originate from (your dedicated number's number, the shared Devotel sender when no dedicated number is attached, or an email sender name).

A not-connected dedicated sender is **attention**, not blocked: outbound still ships via the shared Devotel sender, and the checklist adds a required acknowledgment before Launch enables.

### Compliance checklist

The checklist mixes machine-verified rows (locked to a real signal, not toggleable) with self-attestation rows:

* **Sending setup** (machine) — satisfied when the live preflight returns no blocking issue. Rendered in an advisory register when only advisory issues exist (no dedicated number attached, or a regulated-country destination without an approved profile), and unsatisfied while the check is errored or loading. Remediation deep-links (buy a number, set up a compliance profile) render beside it.
* **Opt-out language** (machine) — for freeform channels (SMS, MMS, RCS), every launch body — the primary variant plus each non-empty A/B variant — must contain carrier-accepted opt-out language (STOP / UNSUBSCRIBE / OPT OUT / cancel). WhatsApp template sends and email are exempt (Meta handles template opt-out; ESPs carry unsubscribe in headers). For multi-variant tests, an unsatisfied hint names the specific missing variant.
* **Recipients opted in** (attestation) — confirm the audience consented.
* **Content reviewed** (attestation) — confirm the copy is accurate.
* **Shared-sender acknowledgement** (attestation, conditional) — appears only when no dedicated SMS number is connected; the send ships on the shared Devotel sender either way, but launch requires the conscious confirmation.
* **Channel-readiness acknowledgement** (attestation, conditional) — appears only for channels the preflight can't verify (WhatsApp, RCS, voice). Unlike SMS, these have no shared-sender fallback, so their connection needs an explicit confirmation before launch.

Launch is gated on every machine row satisfied plus every attestation row ticked — see the gate list below.

### Launch vs. submit for approval

When the org level requires approval (`campaigns/approvals`), the primary action becomes **Submit for review**: the launch parks in the approvals queue instead of sending, and an approver (owner/admin with approval rights) releases it from **Outbound → Approvals**. The wizard refuses to render a confident one-click launch while the approval policy is unknown.

## 7. What the wizard posts — field-to-body mapping

Every Review-step launch call chains the same public endpoints the API guide uses, in this order:

1. `POST /campaigns` (or `PUT /campaigns/:id` for an edit) — the campaign row.
2. `POST /campaigns/:id/steps` — drip steps (drips only).
3. `POST /campaigns/:id/variants` — A/B variant rows (3+ variants).
4. `POST /campaigns/:id/send` — the launch. For a future `scheduled_at`, this moves the campaign to `scheduled` status without dispatching; the scheduler fires it at the configured time. No call → stuck in draft.

The body mapping from wizard field to API field:

| Wizard field                                | API field                                                                                                                           |
| ------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| Type / name / description / channel / chain | `type`, `name`, `description`, `channel`, `channels`                                                                                |
| Sender pickers (SMS/MMS)                    | `variables.from`, `variables.messaging_service_id`                                                                                  |
| Audience strategy + list/segment id         | `audience_type` + `audience_id`                                                                                                     |
| CRM source                                  | `audience_source` (+ `audience_type: "all"`)                                                                                        |
| Manual roster                               | `variables.manual_contact_ids`                                                                                                      |
| CSV                                         | `variables.csv_recipients`                                                                                                          |
| Body / email subject                        | `message_template`, `subject` (blast email only)                                                                                    |
| A/B                                         | `ab_test_enabled: true`, variant rows, winner metric on the campaign row                                                            |
| Holdout                                     | `variables.campaign_holdout_percent`                                                                                                |
| Throttle / business hours / HLR             | `variables.throttle_rate`, `variables.business_hours_only`, `variables.validate_numbers`                                            |
| Recurrence                                  | `variables.recurrence` (only when scheduled + recurring)                                                                            |
| Approved locale variants                    | `variables.locale_variant_set`                                                                                                      |
| Schedule                                    | `scheduled_at` (UTC-converted) or immediate                                                                                         |
| Spending cap                                | `credit_cap_usd_cents` (null = no cap)                                                                                              |
| Drip steps                                  | `delay_minutes` per step (minutes/hours/days/weeks converted), per-step `condition` when not "always", per-step `subject` for email |
| Exit goals (drips)                          | `exit_goals`                                                                                                                        |

If a mid-chain call fails (steps/variants/send), the campaign row already exists, and the Review step reports the partial-launch state instead of silently leaving a created-but-idle draft — re-launching updates the existing row rather than minting a duplicate.

## 8. Drafts: saving and resuming

**Save draft** (Review step) persists the campaign as a draft row. A draft reopens through **Campaigns → Drafts tab** in the list, or directly via the `?edit=<id>` deep-link the draft card offers. Reopening routes edits to `PUT /campaigns/:id`, so repeated saves never mint duplicates. When a launch attempt fails on a non-permission error, the wizard still keeps the draft it minted locally, so retrying updates rather than duplicates.

A draft saved mid-wizard carries its complete form — schedule, recurrence, A/B, locale variants — so "Save draft" from a scheduled send restores the same schedule on reopen.

## 9. Launch gates — what disables the button, and the error you get

The Review step disables Launch/Submit and lists the blocking reasons beside the button. Gates, in check order:

| Gate                                                 | Wizard error                                                                       |
| ---------------------------------------------------- | ---------------------------------------------------------------------------------- |
| Form validation errors anywhere in the wizard        | "Please go back and fix validation errors" — the first failing field is named.     |
| Audience resolved to zero recipients                 | "Your audience resolves to zero recipients" — fix at step 2 or the preview.        |
| Compliance checklist incomplete                      | The unsatisfied attestation or machine row is named (e.g. "Add opt-out language"). |
| Preflight couldn't be verified (errored/loading)     | "Checking your sending numbers and destination profiles…" retry until it resolves. |
| Approval policy unverifiable                         | Held to avoid a confident one-click launch past a required approval.               |
| Cost preview unresolved or channel-default fallback  | "Launch stays disabled until we can confirm the real campaign cost."               |
| WhatsApp body edited away from the approved template | Exact-match violation — revert to the template text.                               |
| WhatsApp template catalog unverified                 | Loading the approved-template list gates the check.                                |

Server-side, `POST /campaigns/:id/send` enforces the same checks — the dry-run buckets ([Send a campaign end-to-end](/guides/campaign-end-to-end)) map one-to-one to the Review-step panels, so a failed launch from the API can be diagnosed on the wizard's dry-run report (audience / cost / quiet-hours / warnings).

## 10. After launch: the campaign detail page

Launching puts the campaign onto the tracking page (Campaigns → click the row). What you get:

* **Stats panel** — live totals for sent, delivered, failed, opened, clicked, replied; polled while running.
* **Pause / resume / cancel** — pause stops dispatch and preserves state; cancel terminates (in-flight sends complete); resume continues from where it stopped. A campaign that hit its `credit_cap_usd_cents` auto-pauses and tells you why.
* **Drip analytics** (`/campaigns/:id/drip-analytics`) — per-step sent/delivered/read/failed plus sequence progress, for drips.
* **Holdout-lift console** (`/campaigns/:id/holdout-lift`) — treatment vs. control conversion-rate delta with confidence interval when you set a holdout.
* **ROAS** (`/campaigns/:id/roas` + touchpoints) when you attribute revenue.
* **Lifecycle webhooks** — `campaign.started/paused/resumed/cancelled/completed` plus drip-step events; subscribe under [webhooks](/webhooks/overview).

## 11. Troubleshooting

* **Wizard stuck in draft.** The campaign exists but no send fired — almost always a missing `POST /campaigns/:id/send` (the wizard reports the partial-launch chain). Reopen the draft from the Drafts tab and launch again; the wizard will update the existing row.
* **Launch button disabled.** The inline reason list names the gate — work down section 9's table. The most common are an empty net audience (all suppressed/opted-out/unreachable — rerun the preview with a channel) and a missing opt-out line.
* **"403 INSUFFICIENT\_PERMISSIONS" on launch.** The launch needs owner/admin/developer; a supervisor or billing seat must hand the draft to an owner — the wizard preserves the entry so an owner completes it.
* **Dry-run errors from the API.** Match them to the dry-run buckets — `audience.deliverable: 0` maps to the zero-recipients gate; `cost.sufficient: false` to the wallet gate; `warnings[]` ("no provider registered", "quiet hours fully closed") to the advisory panels on the Review step.
* **Recurring send won't advance past Schedule.** Recurrence requires an explicit end condition; a "Never" end requires the confirm tick. Cron needs five fields.

## Worked example 1 — SMS promo blast

A scheduled SMS blast to a VIP list with a holdout, no recurrence.

1. **Setup**: name `Retail promo — summer sale`, type `blast`, channel `sms`.
2. **Audience**: Contact List card, pick `list_summerVIPs`; the estimate shows net reach.
3. **Message**: body `Hi {{first_name}}, early access to our summer sale: 25% off through Sunday. Reply STOP to opt out.`
4. **Schedule**: schedule a fixed future time, recurrence "once" (no end condition demanded), throttle blank (default).
5. **Review**: pass compliance (opt-out language is in the body), launch.

The equivalent API path — the exact fields the wizard sent — folds to the end-to-end guide's worked example at `POST /campaigns` with `type: "blast"`, `channel: "sms"`, `audience_type: "list"`, `variables.campaign_holdout_percent`, and `POST /:id/send` (see [Send a campaign end-to-end](/guides/campaign-end-to-end)).

## Worked example 2 — three-step onboarding drip

A welcome drip on signup: welcome email first, WhatsApp follow-up second, SMS nudge third.

1. **Setup**: type `drip`, primary channel can be any single one — per-step channels override it.
2. **Audience**: segment `new-signups`.
3. **Message**: the drip step editor lists steps you add one at a time. Step 1: email with a subject (`Welcome to Acme`). Step 2: WhatsApp — if your account has an approved WhatsApp template, it routes as a template send; the guard re-checks against your approved catalog before launch. Step 3: SMS.
4. Set each step's delay (minutes/hours/days/weeks — converted to minutes in the payload), and optionally a per-step send condition (e.g. "previous step read").
5. **Schedule**: send now (the kick-off sends immediately; steps follow per their delays).
6. **Review**: launch. Drip analytics then report per-step numbers.

## Worked example — manual picker, recurring schedule, RCS sender panel

**Manual roster**: Audience step → Choose contacts → search contacts by name/number → chips accumulate as you pick → the roster becomes `variables.manual_contact_ids` on the campaign. Reuse for exec outreach or one-off regulatory notices.

**Recurring schedule**: Schedule step → send later → pick weekly recurrence with Mon/Wed/Fri → end "after 20 occurrences". The payload becomes `variables.recurrence: { recurrence_type: "weekly", recurrence_days: ["mon","wed","fri"], recurrence_end_type: "after_count", recurrence_end_count: 20 }`.

**RCS sender panel**: Setup step → pick `rcs` → the panel below the capabilities card names the verified sender (or the "not yet set up" link). It also notes the automatic SMS fallback every RCS blast gets for non-RCS handsets.

## Related reading

* [Send a campaign end-to-end](/guides/campaign-end-to-end) — the same lifecycle over the API, including the dry-run report.
* [Campaign journey builder](/guides/campaign-journey-builder) — the event-driven journey canvas for `type: "journey"`.
* [A/B testing campaigns](/guides/campaign-ab-testing) — variants, allocation, and winner metrics.
* [Outbound templates](/guides/outbound-templates) — the template library the picker searches.
* [Policy scanner](/compliance/policy-scanner) — regulatory checks layered under the opt-out and consent posture here.
* [Opt-out lists](/guides/opt-out-lists) and [best practices](/guides/best-practices) — suppression and deliverability specifics.
