2025-12-09 17:51:05 +00:00
---
summary: "Telegram bot support status, capabilities, and configuration"
read_when:
- Working on Telegram features or webhooks
2026-01-31 16:04:03 -05:00
title: "Telegram"
2025-12-09 17:51:05 +00:00
---
2025-12-07 22:46:02 +01:00
2026-01-31 21:13:13 +09:00
# Telegram (Bot API)
2026-01-07 00:25:16 +01:00
2026-02-11 11:58:06 -05:00
Status: production-ready for bot DMs + groups via grammY. Long polling is the default mode; webhook mode is optional.
2026-01-07 00:25:16 +01:00
2026-02-11 11:58:06 -05:00
< CardGroup cols = {3} >
< Card title = "Pairing" icon = "link" href = "/channels/pairing" >
Default DM policy for Telegram is pairing.
< / Card >
< Card title = "Channel troubleshooting" icon = "wrench" href = "/channels/troubleshooting" >
Cross-channel diagnostics and repair playbooks.
< / Card >
2026-02-11 12:10:52 -05:00
< Card title = "Gateway configuration" icon = "settings" href = "/gateway/configuration" >
2026-02-11 11:58:06 -05:00
Full channel config patterns and examples.
< / Card >
< / CardGroup >
2026-02-01 18:51:44 +00:00
2026-02-21 11:18:29 -05:00
## Quick setup
2026-01-11 02:40:28 +01:00
2026-02-11 11:58:06 -05:00
< Steps >
< Step title = "Create the bot token in BotFather" >
Open Telegram and chat with ** @BotFather ** (confirm the handle is exactly `@BotFather` ).
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
Run `/newbot` , follow prompts, and save the token.
2026-01-11 02:40:28 +01:00
2026-02-11 11:58:06 -05:00
< / Step >
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< Step title = "Configure token and DM policy" >
2026-01-07 00:25:16 +01:00
2025-12-07 22:46:02 +01:00
```json5
{
2026-01-13 06:16:43 +00:00
channels: {
telegram: {
enabled: true,
botToken: "123:abc",
dmPolicy: "pairing",
2026-01-31 21:13:13 +09:00
groups: { "*": { requireMention: true } },
},
},
2025-12-07 22:46:02 +01:00
}
```
2026-01-07 00:25:16 +01:00
2026-02-11 11:58:06 -05:00
Env fallback: `TELEGRAM_BOT_TOKEN=...` (default account only).
2026-02-22 17:09:06 +01:00
Telegram does **not** use `openclaw channels login telegram` ; configure token in config/env, then start gateway.
2026-01-11 02:40:28 +01:00
2026-02-11 11:58:06 -05:00
< / Step >
2026-01-08 01:18:37 +01:00
2026-02-11 11:58:06 -05:00
< Step title = "Start gateway and approve first DM" >
2026-01-08 09:33:35 +00:00
2026-02-11 11:58:06 -05:00
```bash
openclaw gateway
openclaw pairing list telegram
openclaw pairing approve telegram < CODE >
```
2026-01-08 09:33:35 +00:00
2026-02-11 11:58:06 -05:00
Pairing codes expire after 1 hour.
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< / Step >
2026-01-08 09:33:35 +00:00
2026-02-11 11:58:06 -05:00
< Step title = "Add the bot to a group" >
Add the bot to your group, then set `channels.telegram.groups` and `groupPolicy` to match your access model.
< / Step >
< / Steps >
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< Note >
Token resolution order is account-aware. In practice, config values win over env fallback, and `TELEGRAM_BOT_TOKEN` only applies to the default account.
< / Note >
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
## Telegram side settings
2026-01-08 09:33:35 +00:00
2026-02-11 11:58:06 -05:00
< AccordionGroup >
< Accordion title = "Privacy mode and group visibility" >
Telegram bots default to **Privacy Mode** , which limits what group messages they receive.
2026-01-08 09:33:35 +00:00
2026-02-11 11:58:06 -05:00
If the bot must see all group messages, either:
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
- disable privacy mode via `/setprivacy` , or
- make the bot a group admin.
2026-01-07 00:25:16 +01:00
2026-02-11 11:58:06 -05:00
When toggling privacy mode, remove + re-add the bot in each group so Telegram applies the change.
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-07 00:25:16 +01:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Group permissions" >
Admin status is controlled in Telegram group settings.
2026-01-31 21:55:59 +05:30
2026-02-11 11:58:06 -05:00
Admin bots receive all group messages, which is useful for always-on group behavior.
2026-01-31 21:55:59 +05:30
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-31 21:55:59 +05:30
2026-02-11 11:58:06 -05:00
< Accordion title = "Helpful BotFather toggles" >
2026-01-31 21:55:59 +05:30
2026-02-11 11:58:06 -05:00
- `/setjoingroups` to allow/deny group adds
- `/setprivacy` for group visibility behavior
2026-01-31 21:55:59 +05:30
2026-02-11 11:58:06 -05:00
< / Accordion >
< / AccordionGroup >
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
## Access control and activation
2026-01-08 02:34:32 +01:00
2026-02-11 11:58:06 -05:00
< Tabs >
< Tab title = "DM policy" >
`channels.telegram.dmPolicy` controls direct message access:
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
- `pairing` (default)
2026-02-26 23:36:33 +01:00
- `allowlist` (requires at least one sender ID in `allowFrom` )
2026-02-11 11:58:06 -05:00
- `open` (requires `allowFrom` to include `"*"` )
- `disabled`
2026-01-16 08:20:48 +00:00
2026-02-14 16:08:41 +01:00
`channels.telegram.allowFrom` accepts numeric Telegram user IDs. `telegram:` / `tg:` prefixes are accepted and normalized.
2026-02-26 23:36:33 +01:00
`dmPolicy: "allowlist"` with empty `allowFrom` blocks all DMs and is rejected by config validation.
2026-02-14 16:08:41 +01:00
The onboarding wizard accepts `@username` input and resolves it to numeric IDs.
2026-02-14 16:51:50 +01:00
If you upgraded and your config contains `@username` allowlist entries, run `openclaw doctor --fix` to resolve them (best-effort; requires a Telegram bot token).
2026-02-27 07:57:56 +05:30
If you previously relied on pairing-store allowlist files, `openclaw doctor --fix` can recover entries into `channels.telegram.allowFrom` in allowlist flows (for example when `dmPolicy: "allowlist"` has no explicit IDs yet).
2026-01-16 08:20:48 +00:00
2026-03-05 16:39:19 +08:00
For one-owner bots, prefer `dmPolicy: "allowlist"` with explicit numeric `allowFrom` IDs to keep access policy durable in config (instead of depending on previous pairing approvals).
2026-02-11 11:58:06 -05:00
### Finding your Telegram user ID
2026-01-25 04:33:14 +00:00
2026-02-11 11:58:06 -05:00
Safer (no third-party bot):
2026-01-25 04:33:14 +00:00
2026-02-11 11:58:06 -05:00
1. DM your bot.
2. Run `openclaw logs --follow` .
3. Read `from.id` .
2026-01-16 08:20:48 +00:00
2026-02-11 11:58:06 -05:00
Official Bot API method:
2026-02-08 18:07:13 +01:00
2026-02-11 11:58:06 -05:00
```bash
curl "https://api.telegram.org/bot< bot_token > /getUpdates"
```
2026-02-08 18:07:13 +01:00
2026-02-11 11:58:06 -05:00
Third-party method (less private): `@userinfobot` or `@getidsbot` .
2026-02-08 18:07:13 +01:00
2026-02-11 11:58:06 -05:00
< / Tab >
2026-02-08 18:07:13 +01:00
2026-02-11 11:58:06 -05:00
< Tab title = "Group policy and allowlists" >
2026-02-27 07:57:56 +05:30
Two controls apply together:
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
1. **Which groups are allowed** (`channels.telegram.groups` )
2026-02-27 07:57:56 +05:30
- no `groups` config:
- with `groupPolicy: "open"` : any group can pass group-ID checks
- with `groupPolicy: "allowlist"` (default): groups are blocked until you add `groups` entries (or `"*"` )
2026-02-11 11:58:06 -05:00
- `groups` configured: acts as allowlist (explicit IDs or `"*"` )
2026-01-08 04:02:04 +01:00
2026-02-11 11:58:06 -05:00
2. **Which senders are allowed in groups** (`channels.telegram.groupPolicy` )
- `open`
- `allowlist` (default)
- `disabled`
2026-01-07 08:54:58 +00:00
2026-02-11 11:58:06 -05:00
`groupAllowFrom` is used for group sender filtering. If not set, Telegram falls back to `allowFrom` .
2026-02-27 07:57:56 +05:30
`groupAllowFrom` entries should be numeric Telegram user IDs (`telegram:` / `tg:` prefixes are normalized).
Non-numeric entries are ignored for sender authorization.
2026-02-27 07:42:49 +05:30
Security boundary (`2026.2.25+` ): group sender auth does **not** inherit DM pairing-store approvals.
Pairing stays DM-only. For groups, set `groupAllowFrom` or per-group/per-topic `allowFrom` .
2026-02-27 07:57:56 +05:30
Runtime note: if `channels.telegram` is completely missing, runtime defaults to fail-closed `groupPolicy="allowlist"` unless `channels.defaults.groupPolicy` is explicitly set.
2026-01-07 08:54:58 +00:00
2026-02-11 11:58:06 -05:00
Example: allow any member in one specific group:
2026-01-07 08:54:58 +00:00
```json5
{
2026-01-13 06:16:43 +00:00
channels: {
telegram: {
groups: {
2026-02-11 11:58:06 -05:00
"-1001234567890": {
groupPolicy: "open",
requireMention: false,
},
2026-01-31 21:13:13 +09:00
},
},
},
2026-01-07 08:54:58 +00:00
}
```
2026-02-11 11:58:06 -05:00
< / Tab >
2026-01-07 08:54:58 +00:00
2026-02-11 11:58:06 -05:00
< Tab title = "Mention behavior" >
Group replies require mention by default.
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
Mention can come from:
- native `@botusername` mention, or
- mention patterns in:
- `agents.list[].groupChat.mentionPatterns`
- `messages.groupChat.mentionPatterns`
Session-level command toggles:
2026-01-07 08:54:58 +00:00
2026-02-11 11:58:06 -05:00
- `/activation always`
- `/activation mention`
These update session state only. Use config for persistence.
Persistent config example:
2026-01-31 21:13:13 +09:00
2026-01-07 08:54:58 +00:00
```json5
{
2026-01-13 06:16:43 +00:00
channels: {
telegram: {
groups: {
2026-02-11 11:58:06 -05:00
"*": { requireMention: false },
2026-01-31 21:13:13 +09:00
},
},
},
2026-01-07 08:54:58 +00:00
}
```
2026-02-11 11:58:06 -05:00
Getting the group chat ID:
- forward a group message to `@userinfobot` / `@getidsbot`
- or read `chat.id` from `openclaw logs --follow`
- or inspect Bot API `getUpdates`
< / Tab >
< / Tabs >
## Runtime behavior
- Telegram is owned by the gateway process.
- Routing is deterministic: Telegram inbound replies back to Telegram (the model does not pick channels).
- Inbound messages normalize into the shared channel envelope with reply metadata and media placeholders.
- Group sessions are isolated by group ID. Forum topics append `:topic:<threadId>` to keep topics isolated.
- DM messages can carry `message_thread_id` ; OpenClaw routes them with thread-aware session keys and preserves thread ID for replies.
- Long polling uses grammY runner with per-chat/per-thread sequencing. Overall runner sink concurrency uses `agents.defaults.maxConcurrent` .
- Telegram Bot API has no read-receipt support (`sendReadReceipts` does not apply).
## Feature reference
< AccordionGroup >
2026-03-02 23:02:50 +00:00
< Accordion title = "Live stream preview (native drafts + message edits)" >
OpenClaw can stream partial replies in real time:
- direct chats: Telegram native draft streaming via `sendMessageDraft`
- groups/topics: preview message + `editMessageText`
2026-02-11 11:58:06 -05:00
2026-02-15 20:09:10 +05:30
Requirement:
2026-02-11 11:58:06 -05:00
2026-03-02 23:02:50 +00:00
- `channels.telegram.streaming` is `off | partial | block | progress` (default: `partial` )
2026-02-21 19:53:23 +01:00
- `progress` maps to `partial` on Telegram (compat with cross-channel naming)
- legacy `channels.telegram.streamMode` and boolean `streaming` values are auto-mapped
2026-01-07 08:54:58 +00:00
2026-03-02 23:02:50 +00:00
Telegram enabled `sendMessageDraft` for all bots in Bot API 9.5 (March 1, 2026).
For text-only replies:
2026-01-10 14:51:51 +01:00
2026-03-02 23:02:50 +00:00
- DM: OpenClaw updates the draft in place (no extra preview message)
- group/topic: OpenClaw keeps the same preview message and performs a final edit in place (no second message)
2026-02-15 20:09:10 +05:30
For complex replies (for example media payloads), OpenClaw falls back to normal final delivery and then cleans up the preview message.
2026-02-21 15:19:13 +05:30
Preview streaming is separate from block streaming. When block streaming is explicitly enabled for Telegram, OpenClaw skips the preview stream to avoid double-streaming.
2026-01-10 14:51:51 +01:00
2026-03-02 23:02:50 +00:00
If native draft transport is unavailable/rejected, OpenClaw automatically falls back to `sendMessage` + `editMessageText` .
2026-02-11 11:58:06 -05:00
Telegram-only reasoning stream:
2026-01-31 21:13:13 +09:00
2026-02-15 20:09:10 +05:30
- `/reasoning stream` sends reasoning to the live preview while generating
2026-02-11 11:58:06 -05:00
- final answer is sent without reasoning text
2026-01-15 01:41:11 +00:00
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Formatting and HTML fallback" >
Outbound text uses Telegram `parse_mode: "HTML"` .
2026-01-15 01:41:11 +00:00
2026-02-11 11:58:06 -05:00
- Markdown-ish text is rendered to Telegram-safe HTML.
- Raw model HTML is escaped to reduce Telegram parse failures.
- If Telegram rejects parsed HTML, OpenClaw retries as plain text.
Link previews are enabled by default and can be disabled with `channels.telegram.linkPreview: false` .
< / Accordion >
< Accordion title = "Native commands and custom commands" >
Telegram command menu registration is handled at startup with `setMyCommands` .
Native command defaults:
- `commands.native: "auto"` enables native commands for Telegram
Add custom command menu entries:
2026-01-31 21:13:13 +09:00
2026-01-15 01:41:11 +00:00
```json5
{
2026-02-11 11:58:06 -05:00
channels: {
telegram: {
customCommands: [
{ command: "backup", description: "Git backup" },
{ command: "generate", description: "Create an image" },
],
},
},
2026-01-15 01:41:11 +00:00
}
```
2026-02-11 11:58:06 -05:00
Rules:
- names are normalized (strip leading `/` , lowercase)
- valid pattern: `a-z` , `0-9` , `_` , length `1..32`
- custom commands cannot override native commands
- conflicts/duplicates are skipped and logged
Notes:
- custom commands are menu entries only; they do not auto-implement behavior
- plugin/skill commands can still work when typed even if not shown in Telegram menu
If native commands are disabled, built-ins are removed. Custom/plugin commands may still register if configured.
Common setup failure:
- `setMyCommands failed` usually means outbound DNS/HTTPS to `api.telegram.org` is blocked.
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
### Device pairing commands (`device-pair` plugin)
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
When the `device-pair` plugin is installed:
2026-01-07 02:10:56 +00:00
2026-02-11 11:58:06 -05:00
1. `/pair` generates setup code
2. paste code in iOS app
3. `/pair approve` approves latest pending request
2026-01-07 11:08:11 +01:00
2026-02-11 11:58:06 -05:00
More details: [Pairing ](/channels/pairing#pair-via-telegram-recommended-for-ios ).
2026-01-15 20:55:03 -05:00
2026-02-11 11:58:06 -05:00
< / Accordion >
< Accordion title = "Inline buttons" >
Configure inline keyboard scope:
2026-01-15 20:55:03 -05:00
```json5
{
2026-01-31 21:13:13 +09:00
channels: {
telegram: {
capabilities: {
inlineButtons: "allowlist",
},
},
},
2026-01-15 20:55:03 -05:00
}
```
2026-02-11 11:58:06 -05:00
Per-account override:
2026-01-31 21:13:13 +09:00
2026-01-15 20:55:03 -05:00
```json5
{
2026-01-31 21:13:13 +09:00
channels: {
telegram: {
accounts: {
main: {
capabilities: {
inlineButtons: "allowlist",
},
},
},
},
},
2026-01-15 20:55:03 -05:00
}
```
2026-02-11 11:58:06 -05:00
Scopes:
2026-01-16 20:16:35 +00:00
2026-02-11 11:58:06 -05:00
- `off`
- `dm`
- `group`
- `all`
- `allowlist` (default)
2026-01-16 20:16:35 +00:00
2026-02-11 11:58:06 -05:00
Legacy `capabilities: ["inlineButtons"]` maps to `inlineButtons: "all"` .
2026-01-15 20:55:03 -05:00
2026-02-11 11:58:06 -05:00
Message action example:
2026-01-15 20:55:03 -05:00
```json5
{
2026-01-31 21:13:13 +09:00
action: "send",
channel: "telegram",
to: "123456789",
message: "Choose an option:",
buttons: [
2026-01-15 20:55:03 -05:00
[
2026-01-31 21:13:13 +09:00
{ text: "Yes", callback_data: "yes" },
{ text: "No", callback_data: "no" },
2026-01-15 20:55:03 -05:00
],
2026-01-31 21:13:13 +09:00
[{ text: "Cancel", callback_data: "cancel" }],
],
2026-01-15 20:55:03 -05:00
}
```
2026-02-11 11:58:06 -05:00
Callback clicks are passed to the agent as text:
`callback_data: <value>`
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Telegram message actions for agents and automation" >
Telegram tool actions include:
2026-01-15 06:09:14 +00:00
2026-02-11 11:58:06 -05:00
- `sendMessage` (`to` , `content` , optional `mediaUrl` , `replyToMessageId` , `messageThreadId` )
- `react` (`chatId` , `messageId` , `emoji` )
- `deleteMessage` (`chatId` , `messageId` )
- `editMessage` (`chatId` , `messageId` , `content` )
2026-02-27 07:57:56 +05:30
- `createForumTopic` (`chatId` , `name` , optional `iconColor` , `iconCustomEmojiId` )
2026-01-31 21:13:13 +09:00
2026-02-27 07:57:56 +05:30
Channel message actions expose ergonomic aliases (`send` , `react` , `delete` , `edit` , `sticker` , `sticker-search` , `topic-create` ).
2026-02-06 10:08:59 -05:00
2026-02-11 11:58:06 -05:00
Gating controls:
2026-01-15 06:09:14 +00:00
2026-02-11 11:58:06 -05:00
- `channels.telegram.actions.sendMessage`
- `channels.telegram.actions.deleteMessage`
- `channels.telegram.actions.reactions`
- `channels.telegram.actions.sticker` (default: disabled)
2026-01-31 21:13:13 +09:00
2026-02-27 07:57:56 +05:30
Note: `edit` and `topic-create` are currently enabled by default and do not have separate `channels.telegram.actions.*` toggles.
2026-02-11 11:58:06 -05:00
Reaction removal semantics: [/tools/reactions ](/tools/reactions )
2026-01-07 00:25:16 +01:00
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-07 08:54:58 +00:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Reply threading tags" >
Telegram supports explicit reply threading tags in generated output:
2026-01-07 08:54:58 +00:00
2026-02-11 11:58:06 -05:00
- `[[reply_to_current]]` replies to the triggering message
- `[[reply_to:<id>]]` replies to a specific Telegram message ID
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
`channels.telegram.replyToMode` controls handling:
2026-01-07 08:54:58 +00:00
2026-02-13 22:11:55 -08:00
- `off` (default)
- `first`
2026-02-11 11:58:06 -05:00
- `all`
2026-01-31 21:13:13 +09:00
2026-02-14 06:29:42 -06:00
Note: `off` disables implicit reply threading. Explicit `[[reply_to_*]]` tags are still honored.
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-07 08:54:58 +00:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Forum topics and thread behavior" >
Forum supergroups:
2026-02-05 23:45:45 +01:00
2026-02-11 11:58:06 -05:00
- topic session keys append `:topic:<threadId>`
- replies and typing target the topic thread
- topic config path:
`channels.telegram.groups.<chatId>.topics.<threadId>`
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
General topic (`threadId=1` ) special-case:
2026-01-07 00:25:16 +01:00
2026-02-11 11:58:06 -05:00
- message sends omit `message_thread_id` (Telegram rejects `sendMessage(...thread_id=1)` )
- typing actions still include `message_thread_id`
2026-01-31 21:13:13 +09:00
2026-03-04 09:34:42 +05:30
Topic inheritance: topic entries inherit group settings unless overridden (`requireMention` , `allowFrom` , `skills` , `systemPrompt` , `enabled` , `groupPolicy` ).
`agentId` is topic-only and does not inherit from group defaults.
2026-03-04 01:12:46 +02:00
**Per-topic agent routing** : Each topic can route to a different agent by setting `agentId` in the topic config. This gives each topic its own isolated workspace, memory, and session. Example:
```json5
{
channels: {
telegram: {
groups: {
"-1001234567890": {
topics: {
"1": { agentId: "main" }, // General topic → main agent
"3": { agentId: "zu" }, // Dev topic → zu agent
"5": { agentId: "coder" } // Code review → coder agent
}
}
}
}
}
}
```
2026-03-04 02:21:37 +02:00
Each topic then has its own session key: `agent:zu:telegram:group:-1001234567890:topic:3`
2026-01-31 21:13:13 +09:00
2026-03-05 09:38:12 +01:00
**Persistent ACP topic binding** : Forum topics can pin ACP harness sessions through top-level typed ACP bindings:
- `bindings[]` with `type: "acp"` and `match.channel: "telegram"`
Example:
```json5
{
agents: {
list: [
{
id: "codex",
runtime: {
type: "acp",
acp: {
agent: "codex",
backend: "acpx",
mode: "persistent",
cwd: "/workspace/openclaw",
},
},
},
],
},
bindings: [
{
type: "acp",
agentId: "codex",
match: {
channel: "telegram",
accountId: "default",
peer: { kind: "group", id: "-1001234567890:topic:42" },
},
},
],
channels: {
telegram: {
groups: {
"-1001234567890": {
topics: {
"42": {
requireMention: false,
},
},
},
},
},
},
}
```
This is currently scoped to forum topics in groups and supergroups.
2026-03-05 20:17:50 -05:00
**Thread-bound ACP spawn from chat** :
- `/acp spawn <agent> --thread here|auto` can bind the current Telegram topic to a new ACP session.
- Follow-up topic messages route to the bound ACP session directly (no `/acp steer` required).
- OpenClaw pins the spawn confirmation message in-topic after a successful bind.
- Requires `channels.telegram.threadBindings.spawnAcpSessions=true` .
2026-02-11 11:58:06 -05:00
Template context includes:
2026-01-07 00:25:16 +01:00
2026-02-11 11:58:06 -05:00
- `MessageThreadId`
- `IsForum`
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
DM thread behavior:
2026-01-07 00:25:16 +01:00
2026-02-11 11:58:06 -05:00
- private chats with `message_thread_id` keep DM routing but use thread-aware session keys/reply targets.
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-08 03:13:54 +00:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Audio, video, and stickers" >
### Audio messages
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
Telegram distinguishes voice notes vs audio files.
2026-01-08 03:13:54 +00:00
2026-02-11 11:58:06 -05:00
- default: audio file behavior
- tag `[[audio_as_voice]]` in agent reply to force voice-note send
2026-01-08 03:13:54 +00:00
2026-02-11 11:58:06 -05:00
Message action example:
2026-01-17 17:32:13 +00:00
```json5
{
2026-01-31 21:13:13 +09:00
action: "send",
channel: "telegram",
to: "123456789",
media: "https://example.com/voice.ogg",
asVoice: true,
2026-01-17 17:32:13 +00:00
}
```
2026-02-11 11:58:06 -05:00
### Video messages
2026-02-09 07:00:57 +00:00
2026-02-11 11:58:06 -05:00
Telegram distinguishes video files vs video notes.
2026-02-09 07:00:57 +00:00
2026-02-11 11:58:06 -05:00
Message action example:
2026-02-09 07:00:57 +00:00
```json5
{
action: "send",
channel: "telegram",
to: "123456789",
media: "https://example.com/video.mp4",
asVideoNote: true,
}
```
2026-02-11 11:58:06 -05:00
Video notes do not support captions; provided message text is sent separately.
2026-01-26 22:07:43 +00:00
2026-02-11 11:58:06 -05:00
### Stickers
2026-01-26 22:07:43 +00:00
2026-02-11 11:58:06 -05:00
Inbound sticker handling:
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
- static WEBP: downloaded and processed (placeholder `<media:sticker>` )
- animated TGS: skipped
- video WEBM: skipped
2026-01-26 22:07:43 +00:00
2026-02-11 11:58:06 -05:00
Sticker context fields:
2026-01-26 22:07:43 +00:00
2026-02-11 11:58:06 -05:00
- `Sticker.emoji`
- `Sticker.setName`
- `Sticker.fileId`
- `Sticker.fileUniqueId`
- `Sticker.cachedDescription`
2026-01-26 22:07:43 +00:00
2026-02-11 11:58:06 -05:00
Sticker cache file:
2026-01-26 22:07:43 +00:00
2026-02-11 11:58:06 -05:00
- `~/.openclaw/telegram/sticker-cache.json`
2026-01-26 22:07:43 +00:00
2026-02-11 11:58:06 -05:00
Stickers are described once (when possible) and cached to reduce repeated vision calls.
2026-01-26 22:07:43 +00:00
2026-02-11 11:58:06 -05:00
Enable sticker actions:
2026-01-26 22:07:43 +00:00
```json5
{
channels: {
telegram: {
actions: {
2026-01-31 21:13:13 +09:00
sticker: true,
},
},
},
2026-01-26 22:07:43 +00:00
}
```
2026-02-11 11:58:06 -05:00
Send sticker action:
2026-01-26 22:07:43 +00:00
```json5
{
2026-01-31 21:13:13 +09:00
action: "sticker",
channel: "telegram",
to: "123456789",
fileId: "CAACAgIAAxkBAAI...",
2026-01-26 22:07:43 +00:00
}
```
2026-02-11 11:58:06 -05:00
Search cached stickers:
2026-01-26 22:07:43 +00:00
```json5
{
2026-01-31 21:13:13 +09:00
action: "sticker-search",
channel: "telegram",
query: "cat waving",
limit: 5,
2026-01-26 22:07:43 +00:00
}
```
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Reaction notifications" >
Telegram reactions arrive as `message_reaction` updates (separate from message payloads).
When enabled, OpenClaw enqueues system events like:
- `Telegram reaction added: 👍 by Alice (@alice) on msg 42`
2026-01-26 22:07:43 +00:00
2026-02-11 11:58:06 -05:00
Config:
2026-01-26 22:07:43 +00:00
2026-02-11 11:58:06 -05:00
- `channels.telegram.reactionNotifications` : `off | own | all` (default: `own` )
- `channels.telegram.reactionLevel` : `off | ack | minimal | extensive` (default: `minimal` )
Notes:
- `own` means user reactions to bot-sent messages only (best-effort via sent-message cache).
2026-02-26 01:02:36 +01:00
- Reaction events still respect Telegram access controls (`dmPolicy` , `allowFrom` , `groupPolicy` , `groupAllowFrom` ); unauthorized senders are dropped.
2026-02-11 11:58:06 -05:00
- Telegram does not provide thread IDs in reaction updates.
- non-forum groups route to group chat session
- forum groups route to the group general-topic session (`:topic:1` ), not the exact originating topic
`allowed_updates` for polling/webhook include `message_reaction` automatically.
< / Accordion >
2026-02-15 11:29:51 -06:00
< Accordion title = "Ack reactions" >
`ackReaction` sends an acknowledgement emoji while OpenClaw is processing an inbound message.
Resolution order:
- `channels.telegram.accounts.<accountId>.ackReaction`
- `channels.telegram.ackReaction`
- `messages.ackReaction`
- agent identity emoji fallback (`agents.list[].identity.emoji` , else "👀")
Notes:
- Telegram expects unicode emoji (for example "👀").
- Use `""` to disable the reaction for a channel or account.
< / Accordion >
2026-02-11 11:58:06 -05:00
< Accordion title = "Config writes from Telegram events and commands" >
Channel config writes are enabled by default (`configWrites !== false` ).
Telegram-triggered writes include:
- group migration events (`migrate_to_chat_id` ) to update `channels.telegram.groups`
- `/config set` and `/config unset` (requires command enablement)
Disable:
2026-01-26 22:07:43 +00:00
```json5
{
2026-02-11 11:58:06 -05:00
channels: {
telegram: {
configWrites: false,
},
},
2026-01-26 22:07:43 +00:00
}
```
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Long polling vs webhook" >
Default: long polling.
2026-01-07 11:08:11 +01:00
2026-02-11 11:58:06 -05:00
Webhook mode:
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
- set `channels.telegram.webhookUrl`
- set `channels.telegram.webhookSecret` (required when webhook URL is set)
- optional `channels.telegram.webhookPath` (default `/telegram-webhook` )
2026-02-14 01:39:56 +10:00
- optional `channels.telegram.webhookHost` (default `127.0.0.1` )
2026-02-27 07:57:56 +05:30
- optional `channels.telegram.webhookPort` (default `8787` )
2026-01-07 11:08:11 +01:00
2026-02-14 01:39:56 +10:00
Default local listener for webhook mode binds to `127.0.0.1:8787` .
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
If your public endpoint differs, place a reverse proxy in front and point `webhookUrl` at the public URL.
2026-02-14 01:39:56 +10:00
Set `webhookHost` (for example `0.0.0.0` ) when you intentionally need external ingress.
2026-01-07 11:08:11 +01:00
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-09 22:40:58 +01:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Limits, retry, and CLI targets" >
- `channels.telegram.textChunkLimit` default is 4000.
- `channels.telegram.chunkMode="newline"` prefers paragraph boundaries (blank lines) before length splitting.
2026-03-06 10:53:06 -05:00
- `channels.telegram.mediaMaxMb` (default 100) caps inbound and outbound Telegram media size.
2026-02-11 11:58:06 -05:00
- `channels.telegram.timeoutSeconds` overrides Telegram API client timeout (if unset, grammY default applies).
- group context history uses `channels.telegram.historyLimit` or `messages.groupChat.historyLimit` (default 50); `0` disables.
- DM history controls:
- `channels.telegram.dmHistoryLimit`
- `channels.telegram.dms["<user_id>"].historyLimit`
2026-02-27 07:57:56 +05:30
- `channels.telegram.retry` config applies to Telegram send helpers (CLI/tools/actions) for recoverable outbound API errors.
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
CLI send target can be numeric chat ID or username:
2026-01-07 11:08:11 +01:00
2026-02-11 11:58:06 -05:00
```bash
openclaw message send --channel telegram --target 123456789 --message "hi"
openclaw message send --channel telegram --target @name --message "hi"
```
2026-01-31 21:13:13 +09:00
2026-03-05 19:24:43 -05:00
Telegram polls use `openclaw message poll` and support forum topics:
```bash
openclaw message poll --channel telegram --target 123456789 \
--poll-question "Ship it?" --poll-option "Yes" --poll-option "No"
openclaw message poll --channel telegram --target -1001234567890:topic:42 \
--poll-question "Pick a time" --poll-option "10am" --poll-option "2pm" \
--poll-duration-seconds 300 --poll-public
```
Telegram-only poll flags:
- `--poll-duration-seconds` (5-600)
- `--poll-anonymous`
- `--poll-public`
- `--thread-id` for forum topics (or use a `:topic:` target)
Action gating:
- `channels.telegram.actions.sendMessage=false` disables outbound Telegram messages, including polls
- `channels.telegram.actions.poll=false` disables Telegram poll creation while leaving regular sends enabled
2026-02-11 11:58:06 -05:00
< / Accordion >
< / AccordionGroup >
2026-01-07 17:48:19 +00:00
2026-02-11 11:58:06 -05:00
## Troubleshooting
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< AccordionGroup >
< Accordion title = "Bot does not respond to non mention group messages" >
2026-01-07 04:10:13 +01:00
2026-02-11 11:58:06 -05:00
- If `requireMention=false` , Telegram privacy mode must allow full visibility.
- BotFather: `/setprivacy` -> Disable
- then remove + re-add bot to group
- `openclaw channels status` warns when config expects unmentioned group messages.
- `openclaw channels status --probe` can check explicit numeric group IDs; wildcard `"*"` cannot be membership-probed.
- quick session test: `/activation always` .
2026-01-13 21:34:40 +02:00
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-13 21:34:40 +02:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Bot not seeing group messages at all" >
2026-01-13 21:34:40 +02:00
2026-02-11 11:58:06 -05:00
- when `channels.telegram.groups` exists, group must be listed (or include `"*"` )
- verify bot membership in group
- review logs: `openclaw logs --follow` for skip reasons
2026-01-13 21:34:40 +02:00
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Commands work partially or not at all" >
2026-01-13 21:34:40 +02:00
2026-02-14 16:51:50 +01:00
- authorize your sender identity (pairing and/or numeric `allowFrom` )
2026-02-11 11:58:06 -05:00
- command authorization still applies even when group policy is `open`
- `setMyCommands failed` usually indicates DNS/HTTPS reachability issues to `api.telegram.org`
2026-01-13 21:34:40 +02:00
2026-02-11 11:58:06 -05:00
< / Accordion >
2026-01-13 21:34:40 +02:00
2026-02-11 11:58:06 -05:00
< Accordion title = "Polling or network instability" >
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
- Node 22+ + custom fetch/proxy can trigger immediate abort behavior if AbortSignal types mismatch.
- Some hosts resolve `api.telegram.org` to IPv6 first; broken IPv6 egress can cause intermittent Telegram API failures.
2026-02-22 06:46:11 -04:00
- If logs include `TypeError: fetch failed` or `Network request for 'getUpdates' failed!` , OpenClaw now retries these as recoverable network errors.
- On VPS hosts with unstable direct egress/TLS, route Telegram API calls through `channels.telegram.proxy` :
```yaml
channels:
telegram:
2026-03-06 19:35:26 -05:00
proxy: socks5://< user > :< password > @proxy -host:1080
2026-02-22 06:46:11 -04:00
```
2026-02-22 17:09:06 +01:00
- Node 22+ defaults to `autoSelectFamily=true` (except WSL2) and `dnsResultOrder=ipv4first` .
- If your host is WSL2 or explicitly works better with IPv4-only behavior, force family selection:
2026-02-22 06:46:11 -04:00
```yaml
channels:
telegram:
network:
autoSelectFamily: false
```
2026-02-22 17:09:06 +01:00
- Environment overrides (temporary):
- `OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1`
- `OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY=1`
- `OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first`
2026-02-11 11:58:06 -05:00
- Validate DNS answers:
```bash
dig +short api.telegram.org A
dig +short api.telegram.org AAAA
2026-01-13 21:34:40 +02:00
```
2026-02-11 11:58:06 -05:00
< / Accordion >
< / AccordionGroup >
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
More help: [Channel troubleshooting ](/channels/troubleshooting ).
2026-01-13 21:34:40 +02:00
2026-02-11 11:58:06 -05:00
## Telegram config reference pointers
2026-01-31 21:13:13 +09:00
2026-02-11 11:58:06 -05:00
Primary reference:
2026-01-07 00:25:16 +01:00
2026-02-14 01:39:56 +10:00
- `channels.telegram.enabled` : enable/disable channel startup.
- `channels.telegram.botToken` : bot token (BotFather).
- `channels.telegram.tokenFile` : read token from file path.
- `channels.telegram.dmPolicy` : `pairing | allowlist | open | disabled` (default: pairing).
2026-02-27 07:57:56 +05:30
- `channels.telegram.allowFrom` : DM allowlist (numeric Telegram user IDs). `allowlist` requires at least one sender ID. `open` requires `"*"` . `openclaw doctor --fix` can resolve legacy `@username` entries to IDs and can recover allowlist entries from pairing-store files in allowlist migration flows.
2026-03-05 19:24:43 -05:00
- `channels.telegram.actions.poll` : enable or disable Telegram poll creation (default: enabled; still requires `sendMessage` ).
2026-02-27 07:57:56 +05:30
- `channels.telegram.defaultTo` : default Telegram target used by CLI `--deliver` when no explicit `--reply-to` is provided.
2026-02-14 01:39:56 +10:00
- `channels.telegram.groupPolicy` : `open | allowlist | disabled` (default: allowlist).
2026-02-27 07:57:56 +05:30
- `channels.telegram.groupAllowFrom` : group sender allowlist (numeric Telegram user IDs). `openclaw doctor --fix` can resolve legacy `@username` entries to IDs. Non-numeric entries are ignored at auth time. Group auth does not use DM pairing-store fallback (`2026.2.25+` ).
2026-02-26 05:31:51 -05:00
- Multi-account precedence:
2026-03-03 16:27:19 +08:00
- When two or more account IDs are configured, set `channels.telegram.defaultAccount` (or include `channels.telegram.accounts.default` ) to make default routing explicit.
- If neither is set, OpenClaw falls back to the first normalized account ID and `openclaw doctor` warns.
2026-02-26 05:31:51 -05:00
- `channels.telegram.accounts.default.allowFrom` and `channels.telegram.accounts.default.groupAllowFrom` apply only to the `default` account.
- Named accounts inherit `channels.telegram.allowFrom` and `channels.telegram.groupAllowFrom` when account-level values are unset.
- Named accounts do not inherit `channels.telegram.accounts.default.allowFrom` / `groupAllowFrom` .
2026-02-14 01:39:56 +10:00
- `channels.telegram.groups` : per-group defaults + allowlist (use `"*"` for global defaults).
- `channels.telegram.groups.<id>.groupPolicy` : per-group override for groupPolicy (`open | allowlist | disabled` ).
- `channels.telegram.groups.<id>.requireMention` : mention gating default.
- `channels.telegram.groups.<id>.skills` : skill filter (omit = all skills, empty = none).
- `channels.telegram.groups.<id>.allowFrom` : per-group sender allowlist override.
- `channels.telegram.groups.<id>.systemPrompt` : extra system prompt for the group.
- `channels.telegram.groups.<id>.enabled` : disable the group when `false` .
2026-03-04 09:34:42 +05:30
- `channels.telegram.groups.<id>.topics.<threadId>.*` : per-topic overrides (group fields + topic-only `agentId` ).
2026-03-04 01:12:46 +02:00
- `channels.telegram.groups.<id>.topics.<threadId>.agentId` : route this topic to a specific agent (overrides group-level and binding routing).
2026-02-14 01:39:56 +10:00
- `channels.telegram.groups.<id>.topics.<threadId>.groupPolicy` : per-topic override for groupPolicy (`open | allowlist | disabled` ).
- `channels.telegram.groups.<id>.topics.<threadId>.requireMention` : per-topic mention gating override.
2026-03-05 09:38:12 +01:00
- top-level `bindings[]` with `type: "acp"` and canonical topic id `chatId:topic:topicId` in `match.peer.id` : persistent ACP topic binding fields (see [ACP Agents ](/tools/acp-agents#channel-specific-settings )).
2026-03-04 01:12:46 +02:00
- `channels.telegram.direct.<id>.topics.<threadId>.agentId` : route DM topics to a specific agent (same behavior as forum topics).
2026-02-14 01:39:56 +10:00
- `channels.telegram.capabilities.inlineButtons` : `off | dm | group | all | allowlist` (default: allowlist).
- `channels.telegram.accounts.<account>.capabilities.inlineButtons` : per-account override.
2026-02-27 07:57:56 +05:30
- `channels.telegram.commands.nativeSkills` : enable/disable Telegram native skills commands.
2026-02-13 22:11:55 -08:00
- `channels.telegram.replyToMode` : `off | first | all` (default: `off` ).
2026-02-14 01:39:56 +10:00
- `channels.telegram.textChunkLimit` : outbound chunk size (chars).
- `channels.telegram.chunkMode` : `length` (default) or `newline` to split on blank lines (paragraph boundaries) before length chunking.
- `channels.telegram.linkPreview` : toggle link previews for outbound messages (default: true).
2026-03-02 23:02:50 +00:00
- `channels.telegram.streaming` : `off | partial | block | progress` (live stream preview; default: `partial` ; `progress` maps to `partial` ; `block` is legacy preview mode compatibility). In DMs, `partial` uses native `sendMessageDraft` when available.
2026-03-06 10:53:06 -05:00
- `channels.telegram.mediaMaxMb` : inbound/outbound Telegram media cap (MB, default: 100).
2026-02-27 07:57:56 +05:30
- `channels.telegram.retry` : retry policy for Telegram send helpers (CLI/tools/actions) on recoverable outbound API errors (attempts, minDelayMs, maxDelayMs, jitter).
2026-02-22 17:09:06 +01:00
- `channels.telegram.network.autoSelectFamily` : override Node autoSelectFamily (true=enable, false=disable). Defaults to enabled on Node 22+, with WSL2 defaulting to disabled.
- `channels.telegram.network.dnsResultOrder` : override DNS result order (`ipv4first` or `verbatim` ). Defaults to `ipv4first` on Node 22+.
2026-02-14 01:39:56 +10:00
- `channels.telegram.proxy` : proxy URL for Bot API calls (SOCKS/HTTP).
- `channels.telegram.webhookUrl` : enable webhook mode (requires `channels.telegram.webhookSecret` ).
- `channels.telegram.webhookSecret` : webhook secret (required when webhookUrl is set).
- `channels.telegram.webhookPath` : local webhook path (default `/telegram-webhook` ).
- `channels.telegram.webhookHost` : local webhook bind host (default `127.0.0.1` ).
2026-02-27 07:57:56 +05:30
- `channels.telegram.webhookPort` : local webhook bind port (default `8787` ).
2026-02-14 01:39:56 +10:00
- `channels.telegram.actions.reactions` : gate Telegram tool reactions.
- `channels.telegram.actions.sendMessage` : gate Telegram tool message sends.
- `channels.telegram.actions.deleteMessage` : gate Telegram tool message deletes.
- `channels.telegram.actions.sticker` : gate Telegram sticker actions — send and search (default: false).
- `channels.telegram.reactionNotifications` : `off | own | all` — control which reactions trigger system events (default: `own` when not set).
- `channels.telegram.reactionLevel` : `off | ack | minimal | extensive` — control agent's reaction capability (default: `minimal` when not set).
2026-02-11 11:58:06 -05:00
- [Configuration reference - Telegram ](/gateway/configuration-reference#telegram )
Telegram-specific high-signal fields:
- startup/auth: `enabled` , `botToken` , `tokenFile` , `accounts.*`
2026-03-05 09:38:12 +01:00
- access control: `dmPolicy` , `allowFrom` , `groupPolicy` , `groupAllowFrom` , `groups` , `groups.*.topics.*` , top-level `bindings[]` (`type: "acp"` )
2026-02-27 07:57:56 +05:30
- command/menu: `commands.native` , `commands.nativeSkills` , `customCommands`
2026-02-11 11:58:06 -05:00
- threading/replies: `replyToMode`
2026-02-21 15:19:13 +05:30
- streaming: `streaming` (preview), `blockStreaming`
2026-02-11 11:58:06 -05:00
- formatting/delivery: `textChunkLimit` , `chunkMode` , `linkPreview` , `responsePrefix`
- media/network: `mediaMaxMb` , `timeoutSeconds` , `retry` , `network.autoSelectFamily` , `proxy`
2026-02-14 01:39:56 +10:00
- webhook: `webhookUrl` , `webhookSecret` , `webhookPath` , `webhookHost`
2026-02-11 11:58:06 -05:00
- actions/capabilities: `capabilities.inlineButtons` , `actions.sendMessage|editMessage|deleteMessage|reactions|sticker`
- reactions: `reactionNotifications` , `reactionLevel`
- writes/history: `configWrites` , `historyLimit` , `dmHistoryLimit` , `dms.*.historyLimit`
## Related
2026-01-07 08:54:58 +00:00
2026-02-11 11:58:06 -05:00
- [Pairing ](/channels/pairing )
- [Channel routing ](/channels/channel-routing )
2026-02-17 14:27:52 -06:00
- [Multi-agent routing ](/concepts/multi-agent )
2026-02-11 11:58:06 -05:00
- [Troubleshooting ](/channels/troubleshooting )