Telegram (Bot API)¶
Status: produktionsreif für Bot-DMs + Gruppen über grammY. Long-Polling standardmäßig; Webhook optional.
Quick setup¶
@BotFather ist.
```
Führen Sie `/newbot` aus und folgen Sie den Anweisungen (Name + Benutzername mit Endung `bot`).
```
{
channels: {
telegram: {
enabled: true,
botToken: "123:abc",
dmPolicy: "pairing",
groups: { "*": { requireMention: true } },
},
},
}
```
Env-Option: `TELEGRAM_BOT_TOKEN=...` (funktioniert für das Standardkonto).
```
`openclaw pairing approve telegram <CODE>`
```
Pairing codes expire after 1 hour.
```
channels.telegram.groups and groupPolicy to match your access model.
TELEGRAM_BOT_TOKEN only applies to the default account.
Telegram side settings¶
```
**Hinweis:** Wenn Sie den Privacy Mode umschalten, verlangt Telegram, den Bot
aus jeder Gruppe zu entfernen und erneut hinzuzufügen, damit die Änderung wirksam wird.
```
```
Den Bot als Gruppen-**Admin** hinzufügen (Admin-Bots erhalten alle Nachrichten).
```
```
`/setjoingroups` — Hinzufügen des Bots zu Gruppen erlauben/verbieten.
```
Access control and activation¶
channels.telegram.dmPolicy controls direct message access:
```
`channels.telegram.allowFrom` akzeptiert numerische Benutzer-IDs (empfohlen) oder `@username`-Einträge. Es ist **nicht** der Bot-Benutzername; verwenden Sie die ID des menschlichen Absenders. Der Assistent akzeptiert `@username` und löst sie, wenn möglich, zur numerischen ID auf.
```
curl "https://api.telegram.org/bot<bot_token>/getUpdates"
```
Third-party method (less private): `@userinfobot` or `@getidsbot`.
```
```
{
channels: {
telegram: {
groups: {
"*": { requireMention: false }, // all groups, always respond
},
},
},
}
```
{
channels: {
telegram: {
groups: {
"-1001234567890": {
groupPolicy: "open",
requireMention: false,
},
},
},
},
}
```
Standardmäßig antwortet der Bot in Gruppen nur auf Erwähnungen (`@botname` oder Muster in `agents.list[].groupChat.mentionPatterns`). Um dieses Verhalten zu ändern:
```
{
channels: {
telegram: {
groups: {
"*": { requireMention: true }, // or omit groups entirely
},
},
},
}
```
Leiten Sie eine beliebige Nachricht aus der Gruppe an `@userinfobot` oder `@getidsbot` auf Telegram weiter, um die Chat-ID zu sehen (negative Zahl wie `-1001234567890`).
```
Runtime behavior¶
- Telegram is owned by the gateway process.
- Deterministisches Routing: Antworten gehen zurück zu Telegram; das Modell wählt keine Kanäle.
- Eingehende Nachrichten werden in den gemeinsamen Kanal-Umschlag mit Antwortkontext und Medien-Platzhaltern normalisiert.
- Group sessions are isolated by group ID. Hängt
:topic:<threadId>an den Sitzungsschlüssel der Telegram-Gruppe an, sodass jedes Thema isoliert ist. - Sendet Tippindikatoren und Antworten mit
message_thread_id, damit Antworten im Thema bleiben. - Long-Polling nutzt den grammY-Runner mit Sequenzierung pro Chat; die Gesamtkonkurrenz ist durch
agents.defaults.maxConcurrentbegrenzt. Overall runner sink concurrency usesagents.defaults.maxConcurrent. - Die Telegram Bot API unterstützt keine Lesebestätigungen; es gibt keine Option
sendReadReceipts.
Feature reference¶
sendMessageDraft verwendet wird.
```
Requirement:
- `channels.telegram.streamMode` is not `"off"` (default: `"partial"`)
Modes:
- `off`: no live preview
- `partial`: frequent preview updates from partial text
- `block`: chunked preview updates using `channels.telegram.draftChunk`
`draftChunk` defaults for `streamMode: "block"`:
- `minChars: 200`
- `maxChars: 800`
- `breakPreference: "paragraph"`
`maxChars` is clamped by `channels.telegram.textChunkLimit`.
This works in direct chats and groups/topics.
For text-only replies, OpenClaw keeps the same preview message and performs a final edit in place (no second message).
For complex replies (for example media payloads), OpenClaw falls back to normal final delivery and then cleans up the preview message.
`streamMode` is separate from block streaming. When block streaming is explicitly enabled for Telegram, OpenClaw skips the preview stream to avoid double-streaming.
Telegram-only reasoning stream:
- `/reasoning stream` sends reasoning to the live preview while generating
- final answer is sent without reasoning text
```
parse_mode: "HTML" (Telegram-unterstützter Tag-Subset).
```
- 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`.
```
```
OpenClaw registriert native Befehle (wie `/status`, `/reset`, `/model`) beim Start im Bot-Menü von Telegram. Sie können über die Konfiguration benutzerdefinierte Befehle zum Menü hinzufügen:
```
{
channels: {
telegram: {
customCommands: [
{ command: "backup", description: "Git backup" },
{ command: "generate", description: "Create an image" },
],
},
},
}
```
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.
### Device pairing commands (`device-pair` plugin)
When the `device-pair` plugin is installed:
1. `/pair` generates setup code
2. paste code in iOS app
3. `/pair approve` approves latest pending request
More details: [Pairing](/channels/pairing#pair-via-telegram-recommended-for-ios).
```
{
channels: {
telegram: {
capabilities: {
inlineButtons: "allowlist",
},
},
},
}
```
Per-account override:
```
{
channels: {
telegram: {
accounts: {
main: {
capabilities: {
inlineButtons: "allowlist",
},
},
},
},
},
}
```
`allowlist` — DMs + Gruppen, aber nur Absender, die durch `allowFrom`/`groupAllowFrom` erlaubt sind (gleiche Regeln wie Steuerbefehle)
```
{
action: "send",
channel: "telegram",
to: "123456789",
message: "Choose an option:",
buttons: [
[
{ text: "Yes", callback_data: "yes" },
{ text: "No", callback_data: "no" },
],
[{ text: "Cancel", callback_data: "cancel" }],
],
}
```
Wenn ein Benutzer einen Button anklickt, werden die Callback-Daten als Nachricht mit folgendem Format an den Agenten zurückgesendet:
`callback_data: value`
```
```
Werkzeug: `telegram` mit Aktion `react` (`chatId`, `messageId`, `emoji`).
```
```
- `[[reply_to_current]]` replies to the triggering message
- `[[reply_to:<id>]]` replies to a specific Telegram message ID
`channels.telegram.replyToMode` controls handling:
- `off` (default)
- `first`
- `all`
Note: `off` disables implicit reply threading. Explicit `[[reply_to_*]]` tags are still honored.
```
```
Allgemeines Thema (Thread-ID `1`) ist speziell: Nachrichtensendungen lassen `message_thread_id` weg (Telegram lehnt es ab), Tippindikatoren enthalten es weiterhin.
```
```
`[[audio_as_voice]]` — Audio als Sprachnotiz statt als Datei senden.
```
{
action: "send",
channel: "telegram",
to: "123456789",
media: "https://example.com/voice.ogg",
asVoice: true,
}
```
Video messages (video vs video note)
```
{
action: "send",
channel: "telegram",
to: "123456789",
media: "https://example.com/video.mp4",
asVideoNote: true,
}
```
Video notes do not support captions; provided message text is sent separately.
### Stickers
Inbound sticker handling:
- static WEBP: downloaded and processed (placeholder `<media:sticker>`)
- animated TGS: skipped
- video WEBM: skipped
Sticker context fields:
- `Sticker.emoji`
- `Sticker.setName`
- `Sticker.fileId`
- `Sticker.fileUniqueId`
- `Sticker.cachedDescription`
Sticker cache file:
- `~/.openclaw/telegram/sticker-cache.json`
Stickers are described once (when possible) and cached to reduce repeated vision calls.
Enable sticker actions:
```
{
channels: {
telegram: {
actions: {
sticker: true,
},
},
},
}
```
Sticker senden
```
{
action: "sticker",
channel: "telegram",
to: "123456789",
fileId: "CAACAgIAAxkBAAI...",
}
```
Sticker-Cache
```
{
action: "sticker-search",
channel: "telegram",
query: "cat waving",
limit: 5,
}
message_reaction-Updates von der Telegram API
```
When enabled, OpenClaw enqueues system events like:
- `Telegram reaction added: 👍 by Alice (@alice) on msg 42`
Config:
- `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).
- 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.
```
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.
```
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:
```
{
channels: { telegram: { configWrites: false } },
}
```
Wenn Ihre öffentliche URL abweicht, verwenden Sie einen Reverse Proxy und zeigen Sie `channels.telegram.webhookUrl` auf den öffentlichen Endpunkt.
```
channels.telegram.textChunkLimit segmentiert (Standard 4000).
Optionales Newline-Chunking: Setzen Sie channels.telegram.chunkMode="newline", um vor der Längen-Segmentierung an Leerzeilen (Absatzgrenzen) zu teilen.
Medien-Downloads/Uploads sind durch channels.telegram.mediaMaxMb begrenzt (Standard 5).
Telegram Bot API-Anfragen laufen nach channels.telegram.timeoutSeconds ab (Standard 500 über grammY).
Gruppenverlaufs-Kontext nutzt channels.telegram.historyLimit (oder channels.telegram.accounts.*.historyLimit) und fällt auf messages.groupChat.historyLimit zurück. Setzen Sie 0, um zu deaktivieren (Standard 50).
DM-Verlauf kann mit channels.telegram.dmHistoryLimit begrenzt werden (Benutzer-Turns). Pro-Benutzer-Overrides: channels.telegram.dms["<user_id>"].historyLimit./config set|unset ausgelöste Konfigurationsupdates schreiben.
```
CLI send target can be numeric chat ID or username:
```
Beispiel: `openclaw message send --channel telegram --target 123456789 --message "hi"`.
Fehlerbehebung¶
```
Wenn Sie `channels.telegram.groups.*.requireMention=false` gesetzt haben, muss der **Privacy Mode** der Telegram Bot API deaktiviert sein.
```
```
Wenn `channels.telegram.groups` gesetzt ist, muss die Gruppe gelistet sein oder `"*"` verwenden
```
```
`setMyCommands failed` in Logs bedeutet meist, dass ausgehendes HTTPS/DNS zu `api.telegram.org` blockiert ist.
```
```
- 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.
- Validate DNS answers:
```
Schnellcheck: `dig +short api.telegram.org A` und `dig +short api.telegram.org AAAA`, um zu bestätigen, was DNS zurückgibt.
Weitere Hilfe: Channel troubleshooting.
Konfigurationsreferenz (Telegram)¶
Primary reference:
-
channels.telegram.enabled: Kanalstart aktivieren/deaktivieren. -
channels.telegram.botToken: Bot-Token (BotFather). -
channels.telegram.tokenFile: Token aus Dateipfad lesen. -
channels.telegram.dmPolicy:pairing | allowlist | open | disabled(Standard: Pairing). -
channels.telegram.allowFrom: DM-Allowlist (IDs/Benutzernamen).openerfordert"*".openclaw doctor --fixcan resolve legacy@usernameentries to IDs. -
channels.telegram.groupPolicy:open | allowlist | disabled(Standard: Allowlist). -
channels.telegram.groupAllowFrom: Gruppen-Absender-Allowlist (IDs/Benutzernamen).openclaw doctor --fixcan resolve legacy@usernameentries to IDs. -
channels.telegram.groups: Gruppen-Standards + Allowlist (verwenden Sie"*"für globale Defaults). channels.telegram.groups.<id>.groupPolicy: Gruppenspezifisches Override für groupPolicy (open | allowlist | disabled).channels.telegram.groups.<id>.requireMention: Standard für Mention-Gating.channels.telegram.groups.<id>.skills: Skill-Filter (weglassen = alle Skills, leer = keine).channels.telegram.groups.<id>.allowFrom: Gruppenspezifisches Absender-Allowlist-Override.channels.telegram.groups.<id>.systemPrompt: Zusätzliches System-Prompt für die Gruppe.channels.telegram.groups.<id>.enabled: Deaktiviert die Gruppe, wennfalse.- .topics.
channels.telegram.groups.<id>.*: Themenspezifische Overrides (gleiche Felder wie Gruppe). channels.telegram.groups.<id>.topics.<threadId>.groupPolicy: Themenspezifisches Override für groupPolicy (open | allowlist | disabled).-
.topics.
channels.telegram.groups.<id>.requireMention: Themenspezifisches Mention-Gating-Override. -
channels.telegram.capabilities.inlineButtons:off | dm | group | all | allowlist(Standard: Allowlist). -
channels.telegram.accounts.<account>.capabilities.inlineButtons: Kontospezifisches Override. -
channels.telegram.replyToMode:off | first | all(Standard:first). -
channels.telegram.textChunkLimit: Ausgehende Chunk-Größe (Zeichen). -
channels.telegram.chunkMode:length(Standard) odernewline, um vor der Längen-Segmentierung an Leerzeilen (Absatzgrenzen) zu teilen. -
channels.telegram.linkPreview: Link-Vorschauen für ausgehende Nachrichten umschalten (Standard: true). -
channels.telegram.streamMode:off | partial | block(Entwurfs-Streaming). -
channels.telegram.mediaMaxMb: Eingehende/ausgehende Medienbegrenzung (MB). -
channels.telegram.retry: Wiederholungsrichtlinie für ausgehende Telegram-API-Aufrufe (Versuche, minDelayMs, maxDelayMs, Jitter). -
channels.telegram.network.autoSelectFamily: Override für Node autoSelectFamily (true=aktivieren, false=deaktivieren). Standardmäßig auf Node 22 deaktiviert, um Happy-Eyeballs-Timeouts zu vermeiden. -
channels.telegram.proxy: Proxy-URL für Bot-API-Aufrufe (SOCKS/HTTP). -
channels.telegram.webhookUrl: Webhook-Modus aktivieren (erfordertchannels.telegram.webhookSecret). -
channels.telegram.webhookSecret: Webhook-Secret (erforderlich, wenn webhookUrl gesetzt ist). -
channels.telegram.webhookPath: Lokaler Webhook-Pfad (Standard/telegram-webhook). -
Der lokale Listener bindet an
0.0.0.0:8787und stellt standardmäßigPOST /telegram-webhookbereit. -
channels.telegram.actions.reactions: Telegram-Werkzeugreaktionen steuern. -
channels.telegram.actions.sendMessage: Telegram-Werkzeug-Nachrichtensendungen steuern. -
channels.telegram.actions.deleteMessage: Telegram-Werkzeug-Nachrichtenlöschungen steuern. -
channels.telegram.actions.sticker: Telegram-Sticker-Aktionen steuern — Senden und Suchen (Standard: false). -
channels.telegram.reactionNotifications:off | own | all— steuert, welche Reaktionen Systemereignisse auslösen (Standard:own, wenn nicht gesetzt). -
channels.telegram.reactionLevel:off | ack | minimal | extensive— steuert die Reaktionsfähigkeit des Agenten (Standard:minimal, wenn nicht gesetzt). -
Vollständige Konfiguration: Konfiguration
Telegram-specific high-signal fields:
- startup/auth:
enabled,botToken,tokenFile,accounts.* - Befehle erfordern Autorisierung, selbst in Gruppen mit
groupPolicy: "open" - command/menu:
commands.native,customCommands - threading/replies:
replyToMode - Optional (nur für
streamMode: "block"): - formatting/delivery:
textChunkLimit,chunkMode,linkPreview,responsePrefix - media/network:
mediaMaxMb,timeoutSeconds,retry,network.autoSelectFamily,proxy - Webhook-Modus: Setzen Sie
channels.telegram.webhookUrlundchannels.telegram.webhookSecret(optionalchannels.telegram.webhookPath). - actions/capabilities:
capabilities.inlineButtons,actions.sendMessage|editMessage|deleteMessage|reactions|sticker - Reaktionsbenachrichtigungen
- writes/history:
configWrites,historyLimit,dmHistoryLimit,dms.*.historyLimit