Multi-Channel Cascade
Multi-Channel Cascade
What you build: an outreach flow that tries channels in order until the person responds. Message on WhatsApp first; if no reply, send an SMS; if still nothing, place a call. Each “rung” only fires if the previous one didn’t reach them — so you send only what’s needed. (The order is yours; WhatsApp → SMS → voice is the default.)
Who it’s for: collections, high-value appointment reminders, urgent notifications — anywhere reaching the person matters more than the channel. This is a genuine Voicebip differentiator: voice-only platforms can’t cascade across SMS and WhatsApp.
Where the cascade is configured. Cascade is an orchestrator feature behind the ENABLE_CASCADE flag. You turn a normal campaign into a cascade by adding a cascade.ladder block to the campaign’s config. The ladder is an ordered list of rungs, each just a channel and a wait window. The campaign’s own channel must equal the first rung (the entry channel). The lifecycle, targets, and counters underneath are the ordinary Campaigns primitives.
Prerequisites
- A voice agent for the call rung.
- An approved WhatsApp template for the WhatsApp rung (see WhatsApp AI agent).
ENABLE_CASCADEenabled on your workspace, plus the outbound flags.- Familiarity with Campaigns — a cascade is a campaign whose
configcarries an ordered set of channel steps.
Step 1 — Define the cascade
Create a campaign whose config carries a cascade.ladder. Each rung is exactly two fields — channel and wait_seconds (how long to wait for a response before escalating to the next rung):
How the ladder works:
- The rung only picks the channel + wait. The message content per channel (SMS body, WhatsApp template + category,
from_number) comes from the campaignconfigand the target’sparams— not from the rung. - The campaign’s
channelmust equal the first rung’s channel (the ladder’s entry channel — the campaign seeds onto that channel’s dispatcher). Here both arewhatsapp. - Stop condition is “the target responded” — a WhatsApp reply or an answered call. There is no per-rung
advance_on: before each rung a re-check reads a per-(workspace, number)“reached” marker, and a target who responded is never escalated. Otherwise, afterwait_secondswith no response, the sweeper advances to the next rung. wait_seconds≥ 0 (0 = escalate immediately / final rung). Max 6 rungs. The last rung’s wait is unused.
Opt into the default ladder — WhatsApp (60m) → SMS (30m) → voice — by sending an empty block: "config": { "cascade": {} }. Then the campaign channel must be whatsapp.
Step 2 — Add targets and start
Targets carry the params every rung references (name, amount), so all channels stay personalised (see Campaigns deep-dive for the target schema):
Step 3 — Track which rung reached them
Each rung emits its channel’s terminal webhook with the campaign_id. A WhatsApp reply or an answered call sets the “reached” marker and stops escalation; anything else lets the ladder advance after the rung’s wait_seconds:
Double-contact protection (handled for you)
The dispatcher marks each target “in-flight” as a crash-idempotency guard, keyed by the bare target id. A cascade walks one target through several rungs on that same key, so a previous rung’s stale marker could make the next rung get skipped as “already in-flight.” The sweeper handles this automatically:
- Non-voice prior rung (SMS/WhatsApp): its marker only clears on a carrier delivery receipt, which can be slow or never arrive — so the sweeper force-clears it before dispatching the next rung. Voice-after-SMS works.
- Voice prior rung: a voice marker clears reliably on
call.completedand is a live-resource guard (if the prior call is still ringing when the window elapses, the marker legitimately blocks a double-dial). The sweeper leaves voice markers alone.
So you can order rungs however you like, including the default WhatsApp → SMS → voice. Once-per-rung idempotency is guaranteed separately by an atomic step-advance, not the marker.
If you ever see a target that reached neither a response nor ladder-exhaustion, check the orchestrator logs for clear stale in-flight marker failed — that’s the one path where a Redis error could leave a rung skipped.
Test it (sandbox)
Run the cascade with pk_test_ targets (+234800000xxxx). Synthetic dispositions let you rehearse the rung progression with ₦0 billing. Simulate the first rung’s outcome to drive the ladder:
Troubleshooting
Next steps
- The campaign lifecycle and counters underneath cascades → Campaigns deep-dive.
- Make the voice rung smarter with tools → Tool-calling.
- Single-channel version → Outbound reminder campaign.