Telegram bot dispatch and demo-account model
Telegram on Orbit is a first-class messaging channel — a business contact channel in its own right, not an SMS-lite or WhatsApp-lite shortcut. It is dispatched through exactly one of two assets: your own BotFather bot connected by pasting a token, or the shared demo bot Orbit operates for evaluation. This page defines how a dispatch picks between the two, which delivery mechanics and media semantics make Telegram different from the carrier channels, how Telegram plugs into the shared routing and fallback machinery, and why a channel Telegram does not charge for still writes cost rows. The per-feature how-to lives on the Telegram channel page; the cross-channel ladder vocabulary lives on the channel test-account model. This page owns the Telegram-specific concepts. Tenants ship Telegram when their audience already lives on it: countries where Telegram is the default chat app, support desks that want a free inbound contact surface before any carrier channel is provisioned, and businesses whose customers prefer a rich-app conversation over SMS. Once Telegram is connected, a customer chat is one more identity on a contact and one more channel on a conversation — the inbox, the AI agent, and the routing machinery treat it exactly like the others.Dispatch: own bot or shared demo bot
Every Telegram send resolves one of two paths, decided by the same gate you meet as a 403:- Your own bot — connected once by pasting the BotFather token into
POST /api/v1/telegram/connect-bot. All Bot API features are available, dispatched under your bot’s identity. - The shared demo bot — available while you evaluate. You link one chat against the shared bot with
POST /api/v1/telegram/test/start-verify(a five-minute deep-link token, rendered in the dashboard as a link and QR), andPOST /api/v1/telegram/test/senddispatches curated demo content to that chat, bounded by a daily test-send allowance. When your organization also owns a bot, the same test/send endpoint dispatches through your own bot instead — the call shape never changes.
The demo pack, and what linking a chat seeds
A verified demo account is not an empty channel. On verification, Orbit seeds a curated pack of demo content so the dashboard preview and the test send both have real material to work with:- Text templates spanning the common transactional shapes — OTP, welcome, order status, appointment reminder, shipping update, payment receipt, feedback request, booking confirmation, account alert, back-in-stock — with
{{1}}-style variables filled by sample values. - Inline keyboards for conversational UX — a support menu, NPS collector, agent handoff, and an appointment time picker — rendered as real button matrices.
- Reply keyboards for the three Bot API request primitives (contact, location, group member) that inline buttons cannot express.
- Polls, venues, Mini App, and streaming draft — the remainder of the current Bot API surface presented as demo placeholders, so the preview shows what the paid surface will look like when you connect your own bot.
GET /api/v1/telegram/demo-content, so your front end can render it without a Bot API round-trip. Demo content IDs follow a fixed orbit_demo_* prefix, which is how the demo gate filters curated material from operator-authored content on the test path.
Webhook delivery, never polling — and the update envelope
Orbit receives Telegram traffic by webhook only. Connecting a bot registers its webhook against Orbit’s platform endpoint (setWebhook with a per-credential secret); polling (getUpdates) is never used, so there is no update-offset state to lose and no long-poll loop to supervise. The one platform guarantee that keeps re-verifying is webhook health: a scheduled check re-registers any bot whose webhook has drifted (retracted by BotFather, overwritten off-platform, or erroring) so inbound is never silently black-holed — the same drift-guard pattern that protects the shared demo bot’s registration.
Every inbound update is mapped into the platform’s common message envelope before routing touches it:
- Chat identity — the update’s chat id is keyed against
telegram_chats, which joins the chat to a contact. A first message from a new chat creates the contact on its Telegram identity. - Update → envelope — text, media, keyboard callbacks, and contact/location shares are normalized into the same inbound envelope SMS, WhatsApp, and email arrivals use (see the message envelope model); direction is
inbound,channelistelegram. - Into the conversation pipeline — the envelope lands on the contact’s open conversation (or opens one) exactly like any other channel; the inbound message routing rules and inbox auto-assignment machinery see no Telegram special case.
Resolving inbound updates back to your organization
Telegram webhook payloads do not carry the bot id — every bot’s updates arrive on the same endpoint — so routing depends on theX-Telegram-Bot-Api-Secret-Token header Telegram echoes back from the secret registered at setWebhook time. The credentials repository resolves that header in ordered lanes:
- Per-organization bot credential row. Each connected bot stores a per-row webhook secret; a match resolves the owning organization and refuses organizations that have been soft-deleted, so inbound into a retired tenant is rejected rather than routed.
- Shared demo-bot row. The shared test bot is a single platform entry; a match authorizes the request, and tenant attribution then happens by verified chat id or by the linking token redeemed on
/start. - Derived platform secret. A value derived from the platform secret — matching exactly what the platform registration passed to
setWebhook— closes the loop between registration and verification without a second Secret.
The bot-credential lifecycle
One credential row per bot, kept for audit:- Connect validates the token with a
getMecall, stores the token encrypted, registers the webhook with its per-row secret, and marks the row active. A bot id can belong to exactly one organization at a time. - Disconnect soft-retires the row (revoking the webhook) rather than deleting it — history of who owned a bot is preserved, and lookup lanes short-circuit retired rows cheaply.
- Reconnect reactivates a retired row in place, so re-pasting a bot token — by the same organization or a new one claiming a released bot — succeeds instead of colliding with the archived row.
Media semantics: a URL the provider fetches
Telegram media travels by URL, not upload. A photo, video, or document send carriesmediaUrl (see the Telegram channel page) and Orbit hands that URL to Telegram’s Bot API, whose servers fetch the file — there is no multipart upload stage on the Orbit side. That makes Telegram a preflight-style media channel in the media planes taxonomy: the link is declared on the send and resolved by the provider, rather than attached to a stored object first.
Practical consequences to design for:
- The URL must be reachable from Telegram’s fetchers. A presigned Media Library URL works; a private object store path does not. The media library issues signed URLs for exactly this kind of provider-fetch handoff.
- Stored vs preflight is your choice. Use a stored asset when the same file serves many sends or must survive sourcing changes; use a preflight URL when the asset is generated per send.
- Bot API size and type limits apply at Telegram’s side. A rejected media URL lands as a provider-level delivery failure and advances any configured fallback chain like any other failure.
Sender, termination, and fallback — Telegram in the shared routing machinery
Telegram plugs into the same routing planes the carrier channels use; what differs is only what the “sender” is.- Sender resolution. On the carrier channels, sender resolution picks a phone number, sender ID, or pool. On Telegram, the sender is the bot itself — dispatch resolves to your connected bot or the shared demo bot (the two-section gate above), and Telegram is exempt from the from/pool/service chain entirely. In the unified-termination vocabulary, Telegram is one member of the closed channel enum — a
deliverhop targetstelegram, and your bot’s identity goes with it (see unified termination routing). - Unified termination. Because
telegramis a first-class termination channel, a termination rule can absorb an SMPP or REST submit onto Telegram the same way it can onto WhatsApp — one recipient the customer gave you a Telegram handle for gets the message on Telegram while everyone else stays on SMS, and the single billed egress semantics of the terminator hold unchanged. - Cross-channel fallback toward SMS. In an org-level cross-channel fallback chain, Telegram can be a hop in either direction — most commonly
Telegram → SMS: a send that fails on Telegram (user blocked the bot, chat unreachable, media URL rejected) advances to SMS under the same re-checks every hop runs (consent/TCPA re-verification, fresh sender resolution on the new channel, per-hop billing). The inverse — SMS-failing-onto-Telegram — delivers onto your bot when the recipient is a linked Telegram contact. - The free-channel DLR note. Telegram carries no per-message DLR gating plane on the no-receipt transition sweep (see the DLR pipeline) — a Telegram row at
sentis the platform-imputed terminal state, exactly like the other zero-price channels.
Opt-in enablement, reachability, and compliance posture
All Telegram controls below are tenant-owned: you enable the channel, you own the bot, you declare your audience.- Opt-in by construction. No tenant gets Telegram “for free” — the channel is inert until you either connect a bot or verify a demo chat, and production traffic additionally requires the send-permitted gate to pass. There is no ambient shared asset that can send to your contacts; the demo bot reaches only chats it explicitly verified against a token you minted.
- Reachability is contact-derived. Telegram reachability comes from the recipient messaging your bot first (or redeeming your
/start-deep-link verification). Telegram is not a numbering plan: there is no tenant-owned MSISDN database to blast onto bots; every reachable chat is a contact who opted to talk to your bot. That makes the channel inherently inbound-sided — ship it as a contact and support surface first, and only consider business-initiated blasts for audiences that already chose you. - Region notes. Telegram availability is a fact of the destination market (a handful of countries block or throttle it; reachability is defined by the contact’s client, not a carrier). Where Telegram reaches, it is free — no per-message carrier rate — which is why most fallback chains place it before the paid SMS hop for Telegram-first audiences, and after it for SMS-first ones.
- Compliance surface. The channel-level consent and suppression rules apply unchanged: STOP-family keywords and suppression lists honor a Telegram chat the same way they honor a phone number, and a contact blocked on Telegram can still be reached via fallback on a consented channel. Nothing on this page adds a legal gate the carrier channels do not already carry — the differences are which asset owns identity and who the recipient had to talk to first.
Worked example: a customer message arrives
- A customer opens your bot (your connected one, or the shared demo bot after verification) and sends “Where is my invoice?”
- Telegram pushes the update to the platform webhook with the
X-Telegram-Bot-Api-Secret-Tokenheader; the credentials repository resolves it on the per-organization lane (own bot) or the shared lane plus verified chat id (demo), and refuses anything that does not match — 401, logged, dropped. - The inbound webhook handler maps the update into the common inbound envelope:
direction: inbound,channel: telegram, the chat id joining the message to its contact viatelegram_chats. - The envelope enters the same conversations pipeline the other channels use: the contact’s open conversation gains the message, or a new conversation opens. Your inbox rules, AI-agent session, and auto-assignment do exactly what they do for SMS or WhatsApp arrivals — the conversation now shows
channels: ["telegram"]and replies default to the bot. - Your operator (or AI agent) replies from the inbox; the send resolves the dispatch gate — own bot or demo — and dispatches through the Bot API. If the reply fails on Telegram (blocked chat, unreachable user), the org’s fallback chain can advance to SMS — re-checked, re-priced, and recorded on the same message thread.
Cost model: ledger rows on a free channel
Telegram’s Bot API is free at the provider level. Orbit still writes a $0 cost row on every Telegram send, markedfree for production traffic and test for demo-bot traffic:
- Analytics stay complete. The per-channel cost rollup aggregates message prices by channel; without an explicit row, Telegram volume would vanish from the chart and skew per-message-cost denominators low.
- Demo traffic is metered. Demo-tier rows let the platform account for the shared asset’s operating cost, the same reason the WhatsApp demo tier is metered.
- A wiring point for paid features. When a paid Telegram surface such as Telegram Stars lands, the breakdown gains a unit-priced tier while the ledger shape, the aggregation, and the dashboard donut keep working unchanged.
GET /api/v1/telegram/analytics/costs splits demo vs free volume over a window and returns the totals with a free-tier disclaimer, so a future paid tier becomes a column in the same shape rather than a new integration.
Cross-references
- Telegram channel — message shapes, keyboards, token handling, ownership disputes.
- The channel test-account model — the tester-to-producer ladder and the two gate classes shared across channels.
- Telegram onboarding guide — the ordered how-to path from empty channel to production bot.
- The message envelope model — the common inbound/outbound envelope this channel normalizes into.
- Inbound message routing — where a received Telegram (or any) message lands once it is on the shared pipeline.
- Conversations: the omnichannel thread model — the thread the Telegram envelope lands on.
- Media planes — the preflight-vs-stored taxonomy Telegram’s URL-passed media sits in.
- Sender resolution — the carrier-channel sender chain Telegram is exempt from, and how it interacts when a chain falls off Telegram onto SMS.
- Unified termination routing — how Telegram participates as a termination channel a rule can deliver onto.
- Cross-channel fallback — the ordered chain Telegram hops participate in, mostly toward SMS.
- RCS capability check and SMS fallback — the sibling capability-pattern page (capability probe vs sender gate) for the same design family.
- Sandbox, test mode, and the provisioning model — the orthogonal
dv_test_sk_*simulation toggle.