The five fallback planes
Orbit has five independent planes that move a message from one channel to the next when a send doesn’t land. Each plane resolves a different failure class, at a different stage of the send, with a different owner (org policy, per-send field, notify request, or campaign graph). This page names all five, orders them as a choice, states what every plane shares, and walks one recipient through each — so the owner pages can go deep on their own plane without re-answering “which plane do I use.” The five planes:- Org capability chain — an org-configured ordered chain (e.g.
RCS → SMS) the router advances through when the current channel can’t carry the recipient at all. Owner page: Cross-channel fallback. - Per-request DLR fallback — an opt-in per send (
fallback_channels+auto_fallback) that re-sends on the next channel only after a terminal delivery receipt arrives. Owner page: Fallback on terminal DLR. - Message-level cascade policy — an org default cascade plus a typed per-send
cascadefield that stamps the chain for you and binds every hop under onemessage_group_id. Owner page: Cascade failover policy and groups. - Notify waterfall cost bounds — a per-recipient
mode: "waterfall"chain onPOST /notifywith a per-hopmax_priceand a cumulativemax_total_pricecap. Owner page: Notify cascade cost model. - Campaign
channels[]ladder — an ordered per-campaign channel ladder with engagement-based triggers (failed,no_delivery,no_engagement) and timed windows (fallback_after_seconds). Owner page: Cross-channel fallback (campaign-level variant) and the campaign journey builder guide.
Precedence and when each plane fires
The planes don’t fight over the same send — each resolves in a fixed order, and each fires only at its own stage:
Three precedence rules matter:
- Capability short-circuits before a DLR can exist. The chain’s trigger (the recipient can’t use this channel at all) resolves mid-send, before the carrier returns a receipt; the DLR hook’s trigger (the carrier said no) can only arise after the send was accepted. So the org chain always resolves first, and the DLR plane never fires on that attempt.
- The DLR plane’s chain source has its own precedence. Inside Cascade failover policy and groups: raw
metadata.fallback_channelsbeats the typedcascadefield, which beats the org policy. Sources are never merged — a caller’s own chain is never silently over-filed by the org default. - The notify waterfall and the campaign ladder are self-contained. The waterfall is one
POST /notifycall that bounds its own cost; the ladder is a campaign-scoped graph evaluated per enrollment. Each owns its own escalation decisions and neither defers to the org chain.
Invariants across planes
Whatever plane owns a hop, the hop is a first-class new send on the next channel — not a silent rewrite of the failing attempt. Every hop re-enters the canonical send pipeline, so the same gates apply at every hop of every plane:- Sender resolution — the hop resolves its own sender for the new channel.
- Consent and opt-out gates — the recipient’s SMS opt-out blocks an SMS hop even when the recipient accepted RCS on the primary; the TCPA re-check runs on every hop into SMS.
- Quiet hours — send-gating rules apply per hop, not per cascade.
- Per-segment billing — each hop prices and charges on the channel it lands on; there is no separate fallback or cascade fee class.
The channel-closure rule
The cascade-eligible channel set is closed:sms, whatsapp, rcs, viber, telegram, messenger, instagram, line, apple_messages. Voice, fax, email, and push are never cascade-eligible — their billing and consent semantics differ too much for an automatic hop (an undelivered email turning into SMS is a compliance surface, not a convenience). Validation rejects anything outside the set with a 422 naming each invalid field. The same closure applies to the org capability chain: fallback applies to outbound messaging only, never to voice calls or email sends.
Which plane to choose
Pick by goal, not by channel:Worked example: one recipient through each plane
Same recipient (+15551234567), same body (“Your appointment is tomorrow at 10:30.”), traced through all five planes:
- Org capability chain. You configured
RCS → SMSonce on the org. The RCS capability check returnsnot_capable, so the router advances immediately — before any receipt exists — and the SMS hop re-enters the pipeline (sender resolution, TCPA re-check, quiet hours) then bills as a normal SMS. The DLR plane never sees this send. - Per-request DLR fallback. You sent RCS with
fallback_channels: ["sms"]. The send was accepted; twenty seconds later the carrier returnsundelivered. The fallback hook stampsfallback_attempted_atatomically and dispatches one new SMS send carryingfallback_of: <your rcs message id>. Carrier replays of the DLR can’t re-send — the stamp is already set. - Message cascade policy. An org default (
channels: ["whatsapp", "sms"]) arms every send; a per-sendcascade: { "channels": ["sms"], "fallback_window_seconds": 3600 }overrides it for one send; either stamps onemessage_group_id. Read the finished run back atGET /api/v1/messages/cascade/groups/<group_id>— one logical message, N legs,fallback_ofandfallback_reasonon every hop. - Notify waterfall.
POST /notifywithmode: "waterfall"andrcs → whatsapp → sms, a per-hopmax_price: 0.02, and a cumulativemax_total_price: 0.05. RCS prices at 0.03 over its per-hop bound, so it’s skipped; the cumulative cap trims the tail before arming; the SMS hop fires and bills under both caps. The response’sdropped_for_cost_capnames what never fired. - Campaign ladder. An omnichannel campaign runs
channels: ["whatsapp", "sms"]withfallback_on: "no_engagement"andfallback_after_seconds: 86400. WhatsApp delivers; after 24 hours with no engagement event, the ladder advances and SMS fires on a timed window — an engagement-based trigger the org chain’s capability triggers can’t express.
Related
- Cross-channel fallback — the org-level capability chain and the campaign ladder.
- Fallback on terminal DLR — the per-request escalation engine.
- Cascade failover policy and groups — org default, per-send
cascadefield, and one logical group id. - Notify cascade cost model —
max_priceandmax_total_pricebounds. - Campaign journey builder — the visual ladder behind the campaign
channels[]shape.