# Telegram channel

A Telegram bot that replies to DMs and (with privacy mode) group commands/@mentions.
Updates arrive via the Telegram Bot API **webhook**; replies go out via `sendMessage`.

## 1. Create a bot

In Telegram, message **[@BotFather](https://t.me/BotFather)** → `/newbot` → follow the
prompts → copy the **bot token** (e.g. `123456789:ABC-DEF…`).

Pick a **secret token** too — any random string you choose (letters/digits/`-`/`_`,
1–256 chars). Telegram echoes it back on every webhook so Callbackfy can verify the request.

## 2. Configure the channel in Callbackfy

Channels → **New channel** → Kind = **telegram**.

| Field             | What it is                                                                   |
| ----------------- | ---------------------------------------------------------------------------- |
| **Default agent** | Agent that answers.                                                          |
| **Identity**      | A label for this bot, e.g. `acme-bot`.                                       |
| **Bot token**     | The `@BotFather` token. Sends replies. Supports `{{ variables }}`.           |
| **Secret token**  | The random string from step 1. Verifies inbound. Supports `{{ variables }}`. |

Store both as **secure variables** (e.g. `{{ telegram_bot_token }}` /
`{{ telegram_secret_token }}`). Save.

## 3. Register the webhook

Open the channel → **Endpoint** panel → **Register**. That calls Telegram's
`setWebhook` for you, pointing it at:

```
POST /telegram/<workspaceId>/<channelId>/webhook
```

with your secret token attached. Re-run **Register** whenever the URL or token changes.

> Prefer to do it by hand? `curl "https://api.telegram.org/bot<token>/setWebhook" -d "url=<webhook>&secret_token=<secret>"`.

## Behavior

- **DMs** — every message is answered.
- **Groups** — by default Telegram's _privacy mode_ means the bot only receives commands, @mentions, and replies to it (keep privacy mode on via BotFather to avoid reacting to every message). A `/command@yourbot` suffix is stripped before routing.
- Commands, sticky routing, the concierge, and guards work as on every channel (see the [common docs](./README.md)). The sender allowlist matches Telegram usernames/IDs.
- Replies render markdown via Telegram's HTML parse mode (**bold**, links, `code`, lists); if a message ever fails to parse it's resent as plain text, and everything is truncated at Telegram's 4096-char limit.

## How it's secured

Every webhook request must carry the `X-Telegram-Bot-Api-Secret-Token` header matching
the channel's secret token (Telegram adds it because we registered the webhook with it);
a wrong/missing token is rejected with `401`. A channel with **no** secret token rejects
every inbound update — leaving it unset would make the endpoint open to anyone who
learned the URL. The webhook is acked immediately and the agent runs in the background.

## One bot, one channel

Telegram allows a single webhook per bot, so two channels sharing a bot token would mean
whichever you **Register** last silently steals the webhook and the other stops receiving
messages. Saving a channel resolves its token via `getMe` and records the bot id, so the
second channel is refused with a `409` instead. Changing the token re-checks it, and an
invalid token is rejected at save time rather than failing silently later.
