Fallback configuration worked samples
The concept pages define Orbit’s fallback planes; this page gives you the exact payloads to arm them. Every sample is a tenant-owned control: the chain order, the escalation window, and the cost ceilings are choices you make per request or per organization. Copy a request as written, substitute your own numbers and key, and compare the envelope you get back. The two read-back shapes and the five planes they sit on are defined in The five fallback planes and Cascade failover policy and groups — read those for precedence rules; come here for the wire shape. The visual composer overPOST /notify is covered in Cascade fallback chains in the notify composer.
The primitives, mapped to fields
Four primitives, each a field you send:
An escalation trigger is always a terminal delivery receipt —
failed, undelivered, or rejected — arriving inside the window. There is no timed retry without a receipt, and each hop runs at most once: a receipt replayed by the carrier cannot re-send a hop.
Worked sample 1: SMS backup after a WhatsApp primary
One recipient, one message, two hops. Order the bindings richest → cheapest; the first binding is the primary, the rest form the escalation tail.results entries are registered as armed hops rather than sent. If the WhatsApp hop returns a terminal receipt within 3600 seconds, the SMS hop fires as a brand-new send. fallback_window_seconds accepts 30 to 86,400 seconds (24 hours maximum) on this endpoint; omit it for the 24-hour engine default. Waterfall requires at least two bindings — a single-binding waterfall fails validation with a 400 naming bindings.
Worked sample 2: Cost-bounded three-hop chain
max_price bounds each hop independently; max_total_price bounds the whole chase. Here RCS prices above its per-hop ceiling of 0.02 and is rejected before billing if armed, and the cumulative cap trims whatever would push the past-costly tail over 0.05:
dropped_for_cost_cap. Per-binding max_price overrides the shared value; max_total_price itself is ignored in the default fanout mode, where every binding fires immediately and there is no cascade to cap.
Worked sample 3: One org default for every send
When you want the same chain on every single-channel send without stamping fields per request, set the org policy once:GET /api/v1/messages/cascade/policy:
{ "data": { "policy": null, "configured": false } }. Policy writes require the messages:write scope and an owner, administrator, or developer role, and each write records an audit-log entry. Senders keep their own chain: a per-send cascade field or a raw metadata.fallback_channels value beats the policy — sources are never merged.
Worked sample 4: Per-send override and opt-out
Override the org policy for one send, or opt a send out of it entirely:cascade field accepts the same shape as the policy and defaults to enabled: true. Declaring a chain with "enabled": false — or setting raw metadata.auto_fallback: false — opts that one send out even when a chain exists; the resolution reads the false guard before it stamps anything.
Reading a cascade back
Two read-back endpoints close the loop. The/notify receipt aggregates every hop of one envelope into a single status and a unified price:
status is delivered when any hop landed, failed when the last hop terminated with nothing left armed, and in_progress while the cascade is live. The cost.total sums only the hops that actually fired — the armed-but-unsent tail is never billed. When a max_total_price trimmed the chain, dropped_for_cost_cap names the channels that never ran.
For policy-driven or per-send cascades, every hop shares one message_group_id, returned on send and readable as a group:
legs list, not an error. A leg that failed to dispatch is simply absent, so the shape always reflects which hops actually ran.
Guardrails: consent and quiet hours re-run on every hop
Every hop is a first-class new send, so the same gates apply at every hop of every plane:- Opt-out and consent. The recipient’s SMS opt-out blocks an SMS hop even if the primary on another channel was accepted. TCPA re-checks run on every hop into SMS.
- Quiet hours. Your tenant-configured quiet-hours windows gate each hop independently — a cascade armed during a quiet window holds the hop until the window opens, and the freshness window bound applies hop by hop.
- Per-hop billing. Each hop prices and charges on the channel it lands on; there is no fallback or cascade fee class.
The closed channel set
The eligible chain set for the cascade policy and the per-sendcascade field is fixed: sms, whatsapp, rcs, viber, telegram, messenger, instagram, line, apple_messages. Voice, fax, email, and push are never cascade-eligible on the messaging endpoints — an undelivered email or call re-arming as a text is a compliance surface, not a convenience. A policy or cascade chain naming one of them fails validation with a 422 listing the rejected fields; the escalation engine additionally refuses hops into those channels even when a raw metadata.fallback_channels chain names them. POST /notify in the default fan-out mode accepts the full channel set, because there every channel fires once, immediately, by explicit declaration — it is the waterfall escalation into voice/email that is closed. Voice-specific fallback chains exist only on the verify product surface (see Verify fallback chains), not on messaging sends.
Related
- The five fallback planes — precedence rules across all five planes.
- Cascade failover policy and groups — the policy and per-send model this page samples.
- Fallback on terminal DLR — the escalation engine every plane arms.
- Notify cascade cost model —
max_priceandmax_total_pricesemantics. - Send gating and quiet hours — the per-hop gate chain.
- Cascade fallback chains in the notify composer — the dashboard composer over
POST /notify.