Skip to main content

Upgrade SMS traffic to RCS per recipient

RCS is not a fleet-wide switch — reachability is per device. A recipient whose handset and carrier bridge to the RBM hub gets the rich experience; everyone else still needs SMS. This guide chains the upgrade end to end: detect which recipients can receive RCS, re-author the campaign as an RCS-first ladder with SMS as the terminal hop, prove the ladder in sandbox, watch per-hop receipts, and flip to production behind the pre-flight gates. Two things must already exist before any of this works: an RCS brand and agent that carriers have approved (the RCS onboarding guide walks brand → agent → verify → launch), and at least one SMS sending number for the fallback hop. If your agent is a draft, stop at the org-level fallback in the RCS channel page and come back after launch.

1. Upgrade vs fallback: pick the mechanism

“Upgrade to RCS” means the primary channel moves from SMS to RCS and SMS demotes to a fallback hop — not that SMS disappears. Three mechanisms move traffic across channels; pick one per send class: The fallback chains guide is the full plane map (campaign ladder, per-message cascade_policy, Verify step-up). This page is the worked SMS → RCS instance of the campaign ladder.

2. Detect per-recipient RCS capability

Decide “RCS-capable” per recipient, not per audience. Two surfaces answer the question: Reach scan (bulk pre-check). POST /api/v1/rcs/reach-scan samples a segment against your bot and returns reach_percent plus a recommended_channel of rcs, mixed, or sms — the answer to “is an RCS-first ladder worth it for this audience” before you touch the campaign. See the RCS channel page. Route preview (per recipient). POST /messages/route-preview scores the channel against the recipient’s capability flags; pass rcs_available: true and RCS can win the pick:
Response — 200:
A recipient with rcs_available: false (or with the flag absent, which the router reads as “unknown”) never enters RCS into the candidate set — the preview comes back channel: "sms". Where does the flag come from? Your contact store: run the capability check (GET /api/v1/rcs/capability/:botId/:to) when a contact enters the segment, cache the verdict for 24 hours, and stamp rcs_available on the preview call from that cache. Run the preview over a sample of the audience before committing the ladder — if the sample resolves mostly to SMS, the RCS-first ladder buys you nothing.

3. Author the RCS-first campaign ladder

Flip the campaign from SMS-only to a two-hop ladder: RCS as the primary (order: 0, must equal the top-level channel), SMS as the terminal hop. Channel-specific fields stay on their own entry — the RCS hop carries its template, the SMS hop carries the plain body:
Reading the ladder entry by entry:
  • The RCS hop fires first. It can carry either a raw rich payload (rich_card / rich_card_carousel shape from the RCS channel page) or an rcs_template reference to an approved template from the Templates tab — never both, and rcs_template is legal only on the rcs entry.
  • The SMS hop is terminal. It carries no fallback_on / fallback_after_seconds; the platform rejects a chain whose last entry still declares a trigger. SMS sends from your normal sending number with normal opt-out screening.
  • The advance trigger decides who stays on RCS. fallback_on: "failed" moves a recipient to SMS only on a terminal RCS failure (undelivered / rejected, including the capability check returning RCS_NOT_SUPPORTED). fallback_on: "no_engagement" would also move delivered-but-ignored recipients to SMS — a second paid send per recipient — so keep the trigger on failed for an upgrade and measure engagement on the RCS hop instead.
Recipients the capability probe disqualifies never consume the RCS hop’s full attempt: the send short-circuits, the hop records RCS_NOT_SUPPORTED, and the ladder advances them to SMS.

4. Validate in sandbox

Prove the ladder with sandbox keys (dv_test_sk_*) before spending a live credit. Two tools cover it: Magic numbers. The sandbox simulator keys delivery outcomes on the recipient’s trailing digit — send the campaign draft against recipients ending in 2 (delivered) and 3 (undelivered). A recipient ending in 3 fails the RCS hop terminally and exercises your SMS advance; one ending in 2 settles on RCS and the ladder must stop. The full digit table is in Sandbox magic numbers — it behaves identically across RCS and SMS hops, so each hop’s outcome is independently controllable. Route preview. Preview is sandbox-safe by construction (nothing ever sends, even on live keys): re-run the section 2 call with your sandbox key and the magic recipients, and confirm an undelivered-pattern recipient still resolves RCS as the pick — the delivery outcome is what advances the ladder, not the pick.

5. Read per-hop DLRs

Every hop is its own message with its own receipt. The unified read is GET /api/v1/notify/:notifyId — one receipt that lists each hop with its channel, outcome, error_code, and billed price. For campaign-driven cascades the same per-hop breakdown renders in the dashboard’s Track a cascade panel (Messages → Multi-channel notify); paste the notify id or the campaign’s hop ids. Excerpt of a settled two-hop envelope where RCS failed and SMS delivered:
Read three things off the receipt after your first pilots:
  • error_code mix on the RCS hop. RCS_NOT_SUPPORTED means the recipient was never RCS-capable — a signal to fix your capability flagging (step 2), not the ladder. Carrier rejections mean template or sender issues instead.
  • delivered_channel distribution. The share of recipients settling on SMS is your true RCS reach in the wild; compare it against the reach scan’s estimate.
  • cost.total vs the SMS-only baseline. A failed RCS hop that short-circuits on capability is free; an RCS hop that attempts and fails still bills. If the terminal-SMS share is high and RCS attempts are costly, restrict the audience to capability-verified recipients.
The full receipt vocabulary (hop ordering, fallback_of linkage, cost caps) is in Track a live cascade by notify id.

6. Rollout gates

Do not flip the whole audience on day one. Run the pre-flight, pilot a slice, then widen:
  1. Pre-flight the chain. POST /api/v1/campaigns/{id}/preview now probes every fallback step, not just the primary — for this ladder it verifies the RCS hop has a verified brand agent and the SMS hop has a dedicated sending number. A step that reads unconnected suppresses the green ready_to_launch. Details: Pre-launch readiness for fallback chains.
  2. Pilot a slice. Launch the ladder against a small segment (or a versioned audience slice) and read the per-hop receipts from step 5.
  3. Widen or narrow by what the receipts say. A high RCS_NOT_SUPPORTED share means your capability flags are stale — shorten the cache window before widening. A healthy RCS-delivered share means widen to the full audience.
  4. Keep SMS in the ladder forever. Every advance trigger keeps an exit to SMS; removing it strands non-capable recipients with a hard failure.

7. Limits and exclusions

  • Approved brand + agent first. An RCS hop in any ladder fires only for a verified or launched agent; the campaign pre-flight flags a draft agent as unconnected. There is no sandbox bypass around the approval.
  • Voice never joins the ladder. voice and fax are filtered out of cascade chains — OTP step-up via a Verify profile is the only surface that admits voice, and that is a different plane.
  • Org-level fallback is the wide net. The RCS channel page also offers an org-wide RCS → SMS chain under Settings → Channels → Cross-Channel Fallback that applies to every RCS send without a campaign ladder. A campaign ladder overrides it for that campaign; leave the org chain armed as the backstop for direct API sends.
  • Templates gate separately. An rcs_template hop sends only after that template is approved — a PUT to the template resets approval to pending, so publish template edits before the campaign depends on them.

Where to go next