The channel test-account model: per-channel shared ladders
Some interactive messaging channels on Orbit ship a shared test account — a channel asset Devotel owns that you bind to one verified recipient so you can send real traffic before you own a production asset. Critically, the model is per-channel, not universal: Telegram ships it, RCS uses it during approval, and WhatsApp ran it until 2026-10-08, when the shared demo WABA was retired. This page defines the model and marks where each channel stands today. The ladder is distinct fromdv_test_sk_* test mode: test mode decides whether a send is simulated (persisted, never dispatched, no provider reached), while a shared test account is a real delivery path — messages actually reach the provider under Devotel’s channel asset. Both exist so you can evaluate in the way that fits: simulation for integration shape, real delivery for end-to-end proof — on the channels that still ship a shared asset.
Which channels still run a shared test account
- Telegram — ships it. The production asset is an unregulated BotFather bot, but the graduation step is still a paste-a-token action, so the shared demo bot remains useful as a real-delivery warm-up. Telegram keeps the full ladder below.
- RCS — uses it during approval. The production asset is a Google-approved agent, and approval takes days. While your agent application is pending, the platform’s approved demo agent carries real sends for verification, exactly the warm-up role the WhatsApp demo used to play. Once Google approves your agent, the shared lane ends.
- WhatsApp — retired 2026-10-08. Meta’s approval friction no longer justifies a shared WABA: every organization now connects its own WABA through Embedded Signup, and the demo endpoints answer
410 GONEinstead of OTP or send traffic. See the 2026-10-08 changelog entry and the WhatsApp channel page for the current error surface.
The three-mode state machine, per channel
On a channel that ships a shared test account (Telegram today; RCS during approval; WhatsApp before retirement), your organization sits in exactly one mode at a time. Telegram makes the modes explicit:
On WhatsApp the table reduced to two rows after retirement:
not_connected (no WABA connected — any send is refused 422 CHANNEL_NOT_CONFIGURED before a message row is written) and production (your WABA connected). The test_verifying/test_active rows exist there only for organizations with a legacy verified link, and GET /api/v1/whatsapp/get-status reports them as retired: true — readable, permanently inert.
The transitions, and who advances each (Telegram used as the worked example):
- Start verification — you call
POST /api/v1/telegram/test/start-verify, which mints a single-use linking token (five-minute TTL) and returns a deep link plus the same value to render as a QR code. Opening the link and pressing Start redeems the token; the inbound webhook binds that chat to your organization and advances the mode totest_active. - Paste a token — you call
POST /api/v1/telegram/connect-botwith the BotFather token. The token is validated, encrypted, and the webhook subscription registered. The mode becomesproduction. Production wins over test: when both exist, the state machine reportsproductionand the test block drops out of the response. - Disconnect —
POST /api/v1/telegram/test/disconnectclears the verified-chat link (back tonot_connected), andPOST /api/v1/telegram/disconnect-botrevokes the webhook registration and retires the BYO row.
The two gate classes
On channels with a shared ladder, every capability falls into one of two gate classes. This is the part of the model your code encounters as 403s.Send-permitted — reachable from both test and production
The send gate permits the call when either the organization owns a connected asset or the organization has an active test account. It answers one question: is this organization allowed to push traffic on this channel at all? Dashboards and preflight checks use it so they fan out without duplicating the test-mode allowance logic. Intest_active, per-send enforcement still applies underneath: sends go only to the verified recipient, against the curated demo allowlist, bounded by a daily cap. On WhatsApp after 2026-10-08 this gate has only one branch: own-WABA-connected. There is no second branch — nothing treated as permitted on the shared asset remains.
Asset-owner-only — production only
The ownership gate rejects with403 FORBIDDEN unless the organization owns the channel asset. Telegram groups these Bot API features in it, because each one mutates the bot as an asset or operates the bot’s economy:
setMyCommandsbeyond the curated demo command set — the shared bot carries a demo command list; redefining it is owner-only.setChatPhoto,setChatTitle,setChatDescription— chat identity mutations.- Payments:
sendInvoice,answerPreCheckoutQuery,answerShippingQuery. - Business connections.
- Sticker-pack management.
getMe/setMyNamemutations — anything that changes the bot identity itself.
403 FORBIDDEN with a connect-your-own message. On Telegram it is “Connect your own Telegram bot to use this feature”; on WhatsApp “Connect your WhatsApp Business account to use this feature”. Both are permanent, deterministic responses: connect the asset and the same call passes.
The shared-asset identity lock, and the $0 ledger rows
Two consequences of running on an asset Orbit owns (applies to whichever channels still ship one): Identity mutations are a 403 even for an active test organization. A shared asset has one identity serving every evaluating tenant. Iftest_active organizations could rename it or redefine its commands, one tenant’s experiment would be every tenant’s asset. So the ownership gate does not ask “are you allowed to send?” (the send gate does) but “do you own this asset?” — and on a shared-lane organization the answer is always no.
Zero-cost rows exist on purpose. Telegram’s Bot API is free at the provider level, so every Telegram cost-ledger row is $0.00 — but the row is written anyway, marked tier: "test" when the send rode the shared bot. Three reasons:
- Cost analytics stay complete. The per-channel cost rollup aggregates message prices by channel; without an explicit $0 row, Telegram volume would vanish from the chart and skew per-message-cost denominators.
- Dev capacity is measurable. Test-tier rows let the platform account for the shared asset’s operating cost.
- Future paid features have a wiring point. When a paid Telegram surface lands, the tiers and consumers already exist.
What your code branches on
One read, one contract, no code change between test and production — on channels that still have a ladder:GET /api/v1/<channel>/channel-stateis the single source of truth for where your organization sits. On Telegram it reportsmode, the shared bot username, the daily test-send counter and limit, the verified chat when test-linked, and the pending verification token whileverifying. The state read is deliberately degrade-safe: if an upstream fault hits it, Orbit returns the well-definednot_connectedempty state rather than a 5xx, so your dashboard card renders “Connect Telegram” instead of an error.- Branch on the returned
mode, never on your own record of what you connected. The per-mode capability matrix is exactly the gate table above:test_activegets send-permitted features to the verified recipient;productiongets both gate classes. - The same endpoint routes differently per mode.
POST /api/v1/telegram/test/senddispatches: ontest_activeit sends via the shared bot to the verified chat and counts the daily cap; onproductionit sends through your own bot. Your integration’s send calls are identical before and after graduation.
channel-state, treat anything but production as “connect a WABA”, and never construct a test_active branch in new code — the retired endpoints answer 410 GONE the moment you call them.
Cross-references
- Telegram channel — message shapes, keyboards, token handling, ownership disputes.
- WhatsApp channel — templates, flows, catalog, Embedded Signup, and the post-retirement error surface.
- Telegram onboarding guide — the ordered how-to path from empty channel to production bot.
- Sandbox, test mode, and the provisioning model — the orthogonal
dv_test_sk_*simulation toggle, and theTENANT_PROVISIONING503. - Verification lifecycle — how approval cycles on regulated channels progress.
- 2026-10-08 changelog: WhatsApp requires your own account — the retirement that removed WhatsApp from this ladder.