Skip to main content
The Telegram integration uses the grammy library and connects via long polling. Once the bot token is set, the gateway starts polling automatically on launch.

Environment variables

VariableRequiredDescription
TELEGRAM_BOT_TOKENYesThe bot token from @BotFather
TELEGRAM_ALLOWLISTNoComma-separated chat IDs allowed to message the bot

Setup

1

Create a bot with @BotFather

Open Telegram and start a chat with @BotFather. Run the /newbot command and follow the prompts to choose a name and username for your bot.
2

Copy your bot token

After creating the bot, BotFather sends you a token that looks like this:
123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11
Keep this token private. Anyone with it can control your bot.
3

Find your chat ID

To restrict your bot to your own chat, you need your Telegram chat ID. The easiest way is to start a chat with @userinfobot — it replies with your numeric user ID.Alternatively, send any message to your bot and watch the gateway logs. The log line for an unallowlisted sender includes the chat ID:
Message from non-allowlisted chat — add this chatId to TELEGRAM_ALLOWLIST
4

Set the environment variables

Add both values to your .env file:
TELEGRAM_BOT_TOKEN=123456:ABC-DEF...
TELEGRAM_ALLOWLIST=123456789
To allow multiple chat IDs, separate them with commas:
TELEGRAM_ALLOWLIST=123456789,987654321
5

Start the gateway

npm run dev
The gateway logs Telegram bot started (polling) when the bot is ready. Send a message to your bot in Telegram to verify the connection.

Allowlist behavior

The gateway evaluates every incoming message against TELEGRAM_ALLOWLIST before passing it to the router.
  • Empty allowlist — the bot accepts messages from any chat ID. This is suitable for private bots running on a local machine, but not for bots exposed to the public.
  • Populated allowlist — only chat IDs in the list are accepted. Messages from other senders are dropped and logged as a warning.
The check uses the Telegram chat ID, not the username. Chat IDs are stable and do not change when a user changes their username.
// config.ts — allowlist check
export function isAllowedTelegramChat(chatId: string): boolean {
  if (TELEGRAM_ALLOWLIST.size === 0) return true;
  return TELEGRAM_ALLOWLIST.has(chatId);
}

How messages are routed

The bot listens for message:text events. When a message arrives:
  1. The chat ID is extracted from the update.
  2. The allowlist check runs.
  3. If the sender is allowed, the message is wrapped in an IncomingMessage with a conversationId of the form telegram:<chatId> and handed to the router.
  4. The router passes the message to the agent backend and sends the reply back via bot.api.sendMessage.
The bot sends replies as HTML first (to preserve any formatting the agent includes). If HTML parsing fails, it falls back to plain text automatically. Long replies are split into chunks of up to 4,000 characters.

Attachments

The Telegram integration currently handles text messages only. If the agent produces an attachment in its reply (for example, a file generated by a code run), the gateway sends a notice explaining that the attachment is available at the path specified in ATTACHMENTS_DIR.
Incoming file messages (photos, documents, voice notes) are not forwarded to the backend. Only text messages trigger the agent. The ATTACHMENTS_DIR defaults to .gateway/attachments/. The agent can write files there and reference them in replies.

Build docs developers (and LLMs) love