> ## Documentation Index
> Fetch the complete documentation index at: https://docs.orbit.devotel.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Settings: Telegram channel connection and toggles

> Walk through the Telegram channel settings page at /settings/channels/telegram — the five state views (not-connected, verifying, test-active, BYO setup, production), the production toggle surface, failure-loop recovery (invalid token, webhook verify rejects, paused webhook), and how this page differs from the Telegram onboarding guide and the /channels/telegram reference.

# Settings: Telegram channel connection and toggles

The **Settings → Channels → Telegram** page (`/settings/channels/telegram`) is the tenant-owned surface that manages the Telegram channel itself: which bot is attached, whether you are on the shared test bot or your own BotFather bot, and the health of the live connection. This guide walks that page end to end.

It is deliberately separate from two other documents you may already have open:

* **[Telegram onboarding](/guides/telegram-onboarding)** — the ordered first-time path from empty channel to a working bot, including the curl calls. That guide is the "how do I get set up" walkthrough.
* **[Telegram channel reference](/channels/telegram)** — the capability reference (message shapes, metadata, token handling, ownership disputes). That page is the "what can the channel do" specification.

This page is the operator's console you return to after onboarding: checking state, swapping test ↔ production, recovering from a dead token, and exercising the channel from inside the dashboard.

## 1. How a Telegram bot becomes a first-party channel on Orbit

A Telegram bot is a first-party Orbit channel the moment Orbit holds three things for it:

* **The BotFather token** — the credential Telegram issues when you create a bot with [@BotFather](https://t.me/BotFather). Orbit stores it in an encrypted credential vault; the token is never shown back to you after you paste it.
* **An active webhook registration** — Orbit calls Telegram's `setWebhook` against `https://api.orbit.devotel.io/api/v1/webhooks/inbound/telegram` the moment you connect, so Telegram starts pushing updates to Orbit immediately. No inbound polling is involved.
* **A verifiable webhook signature** — every inbound update is validated against the per-bot `secret_token` Orbit rotates on connect. Telegram presents it in the `X-Telegram-Bot-Api-Secret-Token` header; an update that does not present the right value is rejected before it reaches your routing pipeline.

With those three in place, Telegram joins the same omnichannel routing surface as SMS, WhatsApp, and so on — inbound updates arrive as `message.received` events, outbound sends go through the unified Messaging API, and the channel respects your tenant-owned opt-in/opt-out routing.

Telegram's opt-in model is inverter-of-default compared to SMS: a user starts the conversation by messaging your bot (or pressing a deep-link `start` button), which *is* the consent signal. When that user later blocks the bot, Telegram stops delivering to them — see §5 for how Orbit surfaces a block.

## 2. Connection modes: webhook vs polling

Orbit only supports **webhook mode** for Telegram. Telegram offers two transports (`setWebhook` for push, `getUpdates` for pull); Orbit registers the webhook on connect and never polls `getUpdates`. This is a deliberate choice, not a gap:

| Mode | Telegram behaviour | Orbit support | Why |
| - | - | - | - |
| **Webhook** (`setWebhook`) | Telegram pushes each update to an HTTPS endpoint in near real time. | **Supported — always used.** | Matches how Orbit ingests every other channel: an inbound event arrives, is signature-validated, and fans out to your webhook subscribers without a polling loop in the middle. |
| **Polling** (`getUpdates`) | The client calls Telegram repeatedly and pulls new updates. | **Not supported.** | A polling loop is a per-tenant owned process that competes with any other consumer of the same bot token, has no at-least-once guarantee, and cannot be load-shared across Orbit replicas. |

Opractical consequence for you: connecting a bot to Orbit **claims the webhook exclusively**. If you previously had the same bot wired to another service via `setWebhook`, Orbit overwrites that registration on connect; if the other service uses `getUpdates`, Telegram's one-consumer rule kicks in and only one of you will see updates. The rule of thumb matches the [per-channel connection modes guide](/guides/subaccount-connection-modes): pick one live consumer per channel, and let Orbit be it.

## 3. Channel setup on this page, step by step

Open **Settings → Channels → Telegram**. The page renders one of five exclusive states, and you move between them by acting on the page:

1. **Not connected** — pick a path: stay on the shared **test bot** (recommended for evaluation) or **connect your own** BotFather bot. This is the only state where both choices are presented side by side.
2. **Verifying** (test path only) — Orbit shows a deep link (`https://t.me/<shared_bot>?start=<token>`) plus a QR code. Open the link in Telegram on the device you want to test from, and the page polls every 3 s until the link confirms. Verification is what moves you to test-active.
3. **Test-active** — you are on the shared bot in demo posture. The page shows your linked chat, your remaining daily test quota, and a "Manage in production" CTA. Test sends route through Devotel's shared bot under its branding, not yours.
4. **BYO setup** — the production path: a single-token form. Paste the token BotFather gave you; Orbit validates it against Telegram's `getMe`, claims the webhook, and flips the channel to production in one step. One org owns one bot: if another Orbit organization already holds the `bot_id`, the connect call returns `409 TELEGRAM_BOT_ALREADY_CONNECTED` and the form surfaces it — see the [ownership-disputes](/channels/telegram#ownership-disputes) recovery path on the channel reference.
5. **Production** — your own bot is connected. See §4 for the toggle surface this state exposes.

The page is owner/admin only — bot tokens are credentials, and the rest of the workspace should not see them. RoleGuard blocks viewer/member/developer seats from the whole surface, not just the token form.

## 4. The production-state toggle surface

Once your own bot is connected, the page becomes a status-and-actions card. Every row below is a tenant-owned control; none of them need a Telethon call or a support ticket.

### Bot identity

| Row | What it shows | Where it comes from |
| - | - | - |
| **Bot** | `@username` handle | Telegram `getMe`, refreshed on connect and on the periodic probe |
| **Name** | Bot display name | Telegram `getMe` |
| **Bot ID** | The numeric prefix before the `:` in the token | Parsed from the token; this is Orbit's internal key for the bot |
| **Connected** | When the token was first accepted | Wall-clock timestamp, formatted relative-then-absolute |
| **Status** | Connection health badge: **Active**, **Disabled**, or **Invalid token** | The periodic probe's latest verdict (see §5) |
| **Last verified** | When the probe last succeeded | Wall-clock timestamp, same renderer as **Connected** |

### Actions

| Button | What it does | Guard |
| - | - | - |
| **Send test message** | Opens a composer that sends a message through your bot to the chat the operator linked during setup. Useful for smoke-testing after a token rotate. | Disabled while **Status** is `invalid_token`. |
| **Disconnect** | Revokes the webhook with Telegram (`deleteWebhook`), clears the stored token, and returns the channel to test mode. Conversation history is keyed by `bot_id`, so it survives a reconnect. | Behind a confirmation modal — the modal spells out that inbound stops and outbound fails. |
| **Reconnect** (visible only when **Status** is `invalid_token`) | Routes you back to the BYO setup form with the current `bot_id` retained, so pasting a refreshed token from BotFather restores service without touching history. | Only rendered in the invalid-token failure loop. |

The card also embeds the **feature matrix panel**, which renders the capability matrix for the current mode (test vs production) so you can compare what each posture includes without leaving the page.

Telegram does **not** expose rate-cap, template, or recipient-list toggles on this page — those controls exist on channels whose provider requires them (WhatsApp templates, RCS sender agents). Telegram's flood-control is enforced by Telegram itself; see `TELEGRAM_RATE_LIMITED` in the [onboarding error reference](/guides/telegram-onboarding) for how the 429 flows back to your send call. If you need a recipient allow-list for a compliance-locked deployment, do it at your own send-side router rather than here.

## 5. The two failure loops this page exists to break

### Loop A — bot token is invalid

**Symptom.** **Status** flips to the red **Invalid token** badge. The most common cause: someone ran `/revoke` or `/token` in BotFather and rotated the token without re-pasting it into Orbit, or the token was never re-pasted after an environment copy.

**Recovery.** Click **Reconnect**. You land back on the BYO setup form; paste the current token; Orbit re-claims the webhook. History and your channel configuration survive because they key off `bot_id`, not the token itself.

**Prevention.** Treat the BotFather token as a single-writer credential. If your team also rotates it via automation, have the automation call `POST /api/v1/telegram/connect-bot` with the new value as part of the same runbook, so Orbit is never holding a dead token.

### Loop B — webhook verify returns a Telegram 401, or the bot is blocked

Two distinct failures share a symptom: inbound messages silently stop arriving.

* **Webhook verify 401** — Telegram's `setWebhook` re-handshake is rejected because the bot token Orbit holds is no longer valid. The periodic probe catches this and flips **Status** to `invalid_token`; the fix is Loop A above.
* **Bot blocked by the user (`bot was blocked by the user`)** — a Telegram-side state, not an Orbit one. Telegram returns `403 Forbidden: bot was blocked by the user` on your send and stops delivering inbound from that user. Orbit surfaces this as a delivery failure on the message record and the channel stays **Active** — the block is user-scoped, not bot-scoped.

**Distinguishing them.** A 401 on the webhook verify is a credential problem: every inbound update stops, and the page's **Invalid token** banner is the tell. A user-level block is a delivery-scoped problem: that one user's thread stops, everyone else continues, and the block surfaces on the per-message `delivery.failed` event.

**What a `WebhookPause` looks like.** When Telegram cannot reach the Orbit webhook (a network partition, a cert error, or a 5xx storm on our side), Telegram retries with its own exponential backoff and eventually stops delivering. Our probe detects the stall and raises the invalid-token/disabled surface on this page even though the token itself is fine — the page treats an unreachable webhook as a not-healthy channel, because from your users' perspective it is. Reconnecting the bot re-runs `setWebhook` and un-pauses the pipe.

## 6. Smoke-test the channel from the sandbox

Before you point real traffic at the bot, exercise it through the [sandbox](/guides/sandbox-test-mode):

```bash theme={null}
# Send a test message via the shared test bot (no BotFather token needed)
curl -X POST https://api.orbit.devotel.io/api/v1/telegram/test/send \
  -H "X-API-Key: dv_test_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "to": "<linked_chat_id>",
    "body": "Sandbox smoke test from Orbit."
  }'
```

The sandbox uses test-mode keys (`dv_test_sk_...`) and the `X-Test-Mode` header; no credits are spent and no Telegram flood-control is incurred. Once that loop is green, flip to your production key and the connected production bot — the same endpoint shape routes through your own bot, so a green sandbox loop is a green production path. The full matrix of sandbox magic numbers and simulate-inbound tooling is in the [sandbox guide](/guides/sandbox-test-mode).

## 7. What this page is *not* — and where the other two documents live

* This page is the **operator console** for a channel you already have. It is not the first-time walkthrough — for that, start with the [onboarding guide](/guides/telegram-onboarding), which assumes nothing is connected and walks the whole path linearly. Re-open **this** page whenever you want to check state, rotate a token, or recover from a failure.
* This page is the **dashboard surface**, not the capability reference. Message shapes, `parse_mode` values, keyboard conventions, edit/delete limits, ownership-dispute recovery, and the error-code table all live on the [Telegram channel reference](/channels/telegram). The settings page links out to that reference where those topics come up.
* The onboarding guide and this page target the same channel, but the guide is API-shaped (endpoint-by-endpoint) and this page is operator-shaped (state-by-state). They cross-link at every hand-off so following either gets you to the same place.

## Related guides

* [Telegram onboarding: shared test bot to your own bot](/guides/telegram-onboarding) — the ordered first-time setup path
* [Telegram channel reference](/channels/telegram) — message shapes, metadata, token handling, error codes
* [Per-channel connection mode: BYO vs platform default for subaccounts](/guides/subaccount-connection-modes) — the reseller-mode inheritance model
* [Sandbox and test mode](/guides/sandbox-test-mode) — exercise the channel without carrier spend
* [The channel test-account model](/concepts/channel-test-account-model) — the state-machine concept behind the five views on this page


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.