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

# Pre-launch readiness for fallback chains

> Check every channel in a campaign's fallback chain before launch, not just the primary. Learn how the dry-run preview reads the channels[] ladder (order >= 1 steps), what each fallback warning means, and where the dashboard surfaces per-step readiness.

# Pre-launch readiness for fallback chains

A campaign's fallback chain — the `channels[]` ladder that moves a send to the next channel when one hop fails — is only as safe as its weakest step. Before this surface existed, the pre-launch preview checked provider and connection readiness on the **primary channel only**. A chain like WhatsApp → SMS with no SMS sending number connected still reported the green "ready to launch," because nothing ever probed the SMS fallback step.

The dry-run preview now probes the whole chain, and the dashboard shows each step's readiness. This page explains what the preview checks per step, how to read the response, and where the same chain appears in the campaign UI.

Configure the chain itself first — the [fallback chains guide](/guides/fallback-chains) covers the `channels[]` shape, ordering rules, and trigger semantics.

## 1. Which steps the preview reads: order 0 vs order >= 1

The fallback chain lives in the campaign's `channels` array. Each entry
carries a `channel` and an `order`:

* **`order: 0` is the primary channel** — the same value as the campaign's
  top-level `channel` field. Readiness for the primary is checked exactly as
  before; it is excluded from the fallback-step probe so it is never probed
  twice.
* **`order >= 1` entries are the fallback steps** — the only entries the
  fallback-chain probe extracts. Gaps and non-contiguous orders are fine;
  only relative ascending order matters.

Single-channel campaigns (no `order >= 1` entry) have no fallback steps, so
every fallback surface below stays empty — the same behaviour the campaign
review step shows.

Example — a WhatsApp → SMS chain as the preview reads it:

```json theme={null}
{
  "channel": "whatsapp",
  "channels": [
    { "channel": "whatsapp", "order": 0, "fallback_on": "failed", "fallback_after_seconds": 300 },
    { "channel": "sms", "order": 1 }
  ]
}
```

## 2. What the dry-run preview checks per fallback step

Run the read-only preview against the campaign:

```bash theme={null}
curl -X POST "https://api.orbit.devotel.io/api/v1/campaigns/{campaign_id}/preview" \
  -H "X-API-Key: $ORBIT_API_KEY"
```

For every fallback step the preview reports three signals:

* **Provider registered** — a provider class exists on the platform for that
  channel. Missing provider → the step is flagged in the waterfall and a
  warning is added.
* **Channel connected** — the tenant actually has a working sender for that
  channel. For SMS and MMS this means a dedicated sending number; for RCS it
  means a verified brand agent. This is the check that was previously
  skipped for fallback steps: an SMS fallback with no sending number is no
  longer a silent green.
* **Not unverifiable** — channels with no probeable connection signal at all
  (for example WhatsApp or email, whose connection is gated by separate
  flows) are reported as `null`, not as a pass. A fallback SMS/MMS probe
  that cannot run (for example a transient error) also fails closed: the
  preview adds an advisory warning instead of reporting green.

Each warning suppresses the green banner: `ready_to_launch` only returns
`true` when the warnings list is empty **and** the provider-readiness
aggregate reads `pass`.

## 3. Reading the preview response

Two blocks carry the fallback-step verdicts.

**Warnings** (plain-language, one per finding):

```json theme={null}
{
  "warnings": [
    "Fallback channel SMS: No dedicated sending number attached — this campaign will send from the shared Devotel sender. Buy a number under Numbers → Buy for a dedicated sender ID and better deliverability.",
    "Cross-channel fallback configured for [mms] but no provider is registered for those channels."
  ],
  "ready_to_launch": false
}
```

Warnings follow the `Fallback channel <CHANNEL>: …` prefix for connection
findings (SMS/MMS numbers, RCS verified agents, or an unverifiable probe), or
the `Cross-channel fallback configured for […]…` shape when a provider class
is missing entirely.

**Channel waterfall** (structured, one entry per step):

```json theme={null}
{
  "channel_waterfall": {
    "primary": "whatsapp",
    "primary_provider_available": true,
    "primary_channel_connected": null,
    "cross_channel_fallback": ["sms"],
    "cross_channel_fallback_available": [
      { "channel": "sms", "provider_available": true, "channel_connected": false }
    ]
  }
}
```

Read `channel_connected` per step:

* `true` — the step can send from a tenant-connected sender.
* `false` — flagged; the step ships nothing you verified.
* `null` — the preview cannot verify this channel's connection (WhatsApp,
  email, and similar). It makes no claim either way.

The enumerated `provider_readiness` block aggregates the same dimensions into
three-state values (`pass` / `fail` / `unknown` per check, `pass` / `blocked`
/ `unverified` overall), so "could not verify" never collapses into a green.

## 4. Where the dashboard shows the same chain

The campaign detail page renders the chain in a fallback-chain panel: each
`order >= 1` step with its advance trigger (`delivery failed` /
`not delivered` / `no engagement`) and waiting window, alongside the
campaign's per-campaign credit cap. Single-channel campaigns show no panel —
the deliberate "stay quiet" behaviour for campaigns with nothing to read.

Open the preview from the campaign composer or detail page before launch and
confirm every step reads connected; on the API, do the same against the
`channel_waterfall` above before pressing send.

## 5. Delivery-based fallback vs budget-downgrade fallback

Everything above concerns **delivery-based hop-by-hop fallback**: the chain
advances because a hop failed to deliver or engage, at send time.

Orbit also supports a distinct **budget-downgrade fallback**: spend-triggered
channel downgrade, where a campaign steps delivery down to a cheaper channel
to stay efficient within its per-campaign credit cap. The two chains are
separate configurations — readiness for a delivery chain does not validate a
budget-downgrade chain, and a budget cap never arms a delivery hop on its
own.

## Wire-up summary

* Build the ladder: [Fallback chains guide](/guides/fallback-chains).
* Advance triggers and windows: [Campaign end-to-end guide](/guides/campaign-end-to-end), step 6.
* Other pre-launch gates (wallet, suppression, quiet hours, caps): [Outbound compliance pre-flight checklist](/guides/send-gates-preflight-checklist).
* Delivery vs budget-downgrade shapes: [Fallback and cascade planes](/concepts/fallback-and-cascade-planes).
