---
title: "Telegram"
description: "Reach your agent from Telegram bot webhooks, with inline-keyboard human-in-the-loop prompts and attachments."
type: integration
---

The Telegram channel puts your agent behind a Telegram bot. It takes Bot API webhooks, checks the `X-Telegram-Bot-Api-Secret-Token` header before trusting anything, and routes the messages it cares about (private chats plus group messages that address the bot) to a reply over `sendMessage`. See [Channels](./overview) for the contract this builds on.

## Add the channel

```ts title="agent/channels/telegram.ts"
import { telegramChannel } from "eve/channels/telegram";

export default telegramChannel({
  botUsername: "my_bot",
});
```

```bash
TELEGRAM_BOT_TOKEN=123456:...        # replies, typing, callbacks, proactive sends
TELEGRAM_WEBHOOK_SECRET_TOKEN=...    # must match the secret_token you register
```

You can pass the same values via `credentials: { botToken, webhookSecretToken }`. The channel mounts `POST /eve/v1/telegram`. Register the deployed URL yourself; eve does not call `setWebhook`:

```bash
curl -X POST "https://api.telegram.org/bot$TELEGRAM_BOT_TOKEN/setWebhook" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://your-app.example.com/eve/v1/telegram",
       "secret_token":"'"$TELEGRAM_WEBHOOK_SECRET_TOKEN"'",
       "allowed_updates":["message","callback_query"]}'
```

## How the channel handles messages

### Dispatch

In a private chat, text, captions, photos, and documents all go through. Groups are stricter. Only three things wake the bot: a command (`/ask`, `/ask@my_bot`), an `@my_bot` mention (when `botUsername` is set), or a reply to one of the bot's own messages. Everything else is ignored.

Forum topics carry `message_thread_id` in the continuation token, so each topic stays on its own thread.

To customize auth or filtering, override `onMessage`. Group privacy mode itself lives in BotFather, not here.

### Delivery

The default `message.completed` handler sends plain text via `sendMessage`. It passes no `parse_mode`, so any Markdown shows up literally. Replies longer than Telegram's 4096-char limit are split across messages. Custom handlers use `channel.telegram`.

### Human-in-the-loop (HITL)

Human-in-the-loop (HITL) turns option requests into inline-keyboard buttons and freeform requests into `ForceReply`. Telegram caps `callback_data` at 64 bytes, so eve keeps compact callback ids in channel state instead. It acknowledges its own callbacks with `answerCallbackQuery`; anything it doesn't recognize goes to `onCallbackQuery`.

### Proactive sessions

Start a session without an inbound message through `receive(telegram, { message, target, auth })` from a schedule `run` handler, or `args.receive(telegram, ...)` from another channel. `target.chatId` is required. Add `messageThreadId` to land in a specific forum topic.

Private proactive chats stay keyed to the chat, or to the chat plus `messageThreadId` when you target a topic. Group and supergroup proactive sends anchor to the bot message id returned by Telegram, so replies to different bot messages can resume different sessions in the same chat. If Telegram does not return a recognized chat type for an outbound send, eve keeps the session unanchored instead of guessing.

### Attachments

Inbound photos and documents are supported. eve fetches them on demand via `getFile`, only when an upload policy allows the type:

```ts
export default telegramChannel({
  botUsername: "my_bot",
  uploadPolicy: { allowedMediaTypes: ["image/*", "application/pdf"], maxBytes: 10 * 1024 * 1024 },
});
```

## What to read next

- [Channels overview](./overview): the channel contract and every built-in channel
- [Auth & route protection](../guides/auth-and-route-protection): authenticating inbound traffic
