Telegram (Bot API)
Status: grammY를 통한 bot DMs + groups에 대해 production-ready 상태입니다. Long polling이 기본 모드이며 webhook 모드는 선택 사항입니다.Pairing
Channel troubleshooting
Gateway configuration
Quick setup
Create the bot token in BotFather
@BotFather인지 확인)./newbot을 실행하고, 안내에 따라 진행한 뒤 token을 저장합니다.Configure token and DM policy
TELEGRAM_BOT_TOKEN=... (default account only).
Telegram은 openclaw channels login telegram을 사용하지 않습니다. config/env에 token을 설정한 뒤 gateway를 시작하세요.TELEGRAM_BOT_TOKEN은 default account에만 적용됩니다.Telegram side settings
Privacy mode and group visibility
Privacy mode and group visibility
/setprivacy로 privacy mode 비활성화- bot을 그룹 admin으로 지정
Group permissions
Group permissions
Helpful BotFather toggles
Helpful BotFather toggles
/setjoingroups로 그룹 추가 허용/차단/setprivacy로 그룹 가시성 동작 제어
Access control and activation
- DM policy
- Group policy and allowlists
- Mention behavior
channels.telegram.dmPolicy는 direct message 접근을 제어합니다.pairing(default)allowlist(allowFrom에 sender ID가 최소 하나 필요)open(allowFrom에"*"필요)disabled
channels.telegram.allowFrom은 숫자형 Telegram user ID를 받습니다. telegram: / tg: prefix도 허용되고 정규화됩니다.
allowFrom이 비어 있는 dmPolicy: "allowlist"는 모든 DM을 차단하며 config validation에서 거부됩니다.
onboarding wizard는 @username 입력을 받아 숫자 ID로 resolve합니다.
업그레이드 후 config에 @username allowlist 항목이 남아 있다면 openclaw doctor --fix를 실행해 resolve하세요(best-effort이며 Telegram bot token 필요).
이전에 pairing-store allowlist 파일에 의존했다면, openclaw doctor --fix가 allowlist 흐름에서 해당 항목을 channels.telegram.allowFrom으로 복구할 수 있습니다(예: dmPolicy: "allowlist"인데 아직 explicit ID가 없는 경우).한 명의 owner만 사용하는 bot이라면, 이전 pairing approval에 의존하지 말고 durable한 config policy 유지를 위해 explicit numeric allowFrom ID와 함께 dmPolicy: "allowlist"를 사용하는 편이 좋습니다.Finding your Telegram user ID
더 안전한 방법(third-party bot 없음):- bot에 DM을 보냅니다.
openclaw logs --follow를 실행합니다.from.id를 읽습니다.
@userinfobot 또는 @getidsbot.Runtime behavior
- Telegram은 gateway process가 직접 소유합니다.
- routing은 deterministic합니다. Telegram inbound는 다시 Telegram으로 reply됩니다(model이 channel을 선택하지 않음).
- inbound message는 reply metadata와 media placeholder를 포함한 공통 channel envelope로 정규화됩니다.
- group session은 group ID별로 격리됩니다. forum topic은
:topic:<threadId>를 덧붙여 topic 단위로 격리합니다. - DM message는
message_thread_id를 포함할 수 있습니다. OpenClaw는 thread-aware session key로 라우팅하고 reply 시 thread ID를 보존합니다. - Long polling은 grammY runner를 사용하며, chat/thread별 sequencing을 유지합니다. 전체 runner sink concurrency는
agents.defaults.maxConcurrent를 사용합니다. - Telegram Bot API는 read-receipt를 지원하지 않습니다(
sendReadReceipts는 적용되지 않음).
Feature reference
Live stream preview (message edits)
Live stream preview (message edits)
- direct chats: preview message +
editMessageText - groups/topics: preview message +
editMessageText
channels.telegram.streaming은off | partial | block | progress(default:partial)progress는 Telegram에서partial로 매핑됨(cross-channel naming 호환성)- legacy
channels.telegram.streamMode와 booleanstreaming값은 자동 매핑됨
- DM: 같은 preview message를 유지하고 마지막에 그 자리에서 final edit 수행(두 번째 message 없음)
- group/topic: 같은 preview message를 유지하고 마지막에 그 자리에서 final edit 수행(두 번째 message 없음)
sendMessage + editMessageText로 fallback합니다.Telegram-only reasoning stream:/reasoning stream은 생성 중 reasoning을 live preview로 보냄- final answer에는 reasoning text를 포함하지 않음
Formatting and HTML fallback
Formatting and HTML fallback
parse_mode: "HTML"을 사용합니다.- Markdown 비슷한 텍스트는 Telegram-safe HTML로 렌더링됩니다.
- raw model HTML은 Telegram parse failure를 줄이기 위해 escape됩니다.
- Telegram이 parsed HTML을 거부하면 OpenClaw는 plain text로 재시도합니다.
channels.telegram.linkPreview: false로 끌 수 있습니다.Native commands and custom commands
Native commands and custom commands
setMyCommands로 처리됩니다.Native command 기본값:commands.native: "auto"가 Telegram에서 native command를 활성화
- 이름은 정규화됩니다(앞의
/제거, lowercase) - 유효 패턴:
a-z,0-9,_, 길이1..32 - custom command는 native command를 override할 수 없음
- conflict/duplicate는 skip되고 log에 기록됨
- custom command는 menu entry만 추가합니다. 동작을 자동 구현하지는 않습니다.
- plugin/skill command는 Telegram menu에 보이지 않아도 직접 입력하면 동작할 수 있습니다.
setMyCommands failed는 보통api.telegram.org로의 outbound DNS/HTTPS가 막혀 있음을 의미합니다.
Device pairing commands (device-pair plugin)
device-pair plugin이 설치되어 있으면:/pair로 setup code 생성- iOS app에 code 붙여넣기
/pair approve로 최신 pending request 승인
Inline buttons
Inline buttons
Telegram message actions for agents and automation
Telegram message actions for agents and automation
sendMessage(to,content, optionalmediaUrl,replyToMessageId,messageThreadId)react(chatId,messageId,emoji)deleteMessage(chatId,messageId)editMessage(chatId,messageId,content)createForumTopic(chatId,name, optionaliconColor,iconCustomEmojiId)
send, react, delete, edit, sticker, sticker-search, topic-create).Gating control:channels.telegram.actions.sendMessagechannels.telegram.actions.deleteMessagechannels.telegram.actions.reactionschannels.telegram.actions.sticker(default: disabled)
edit 와 topic-create 는 현재 기본적으로 활성화되어 있으며 별도의 channels.telegram.actions.* toggle이 없습니다.
runtime send는 active config/secrets snapshot(startup/reload 시점)을 사용하므로, action path는 send마다 ad-hoc SecretRef 재해석을 하지 않습니다.Reaction removal semantics: /tools/reactionsReply threading tags
Reply threading tags
Forum topics and thread behavior
Forum topics and thread behavior
- topic session key는
:topic:<threadId>를 덧붙임 - reply와 typing은 해당 topic thread를 대상으로 함
- topic config path:
channels.telegram.groups.<chatId>.topics.<threadId>
threadId=1) special-case:- message send에서는
message_thread_id를 생략함(Telegram이sendMessage(...thread_id=1)을 거부함) - typing action에는 계속
message_thread_id를 포함
requireMention, allowFrom, skills, systemPrompt, enabled, groupPolicy).
agentId는 topic 전용이며 group default에서 상속되지 않습니다.Per-topic agent routing: 각 topic은 topic config의 agentId를 설정해 다른 agent로 라우팅할 수 있습니다. 이로써 각 topic은 자신의 isolated workspace, memory, session을 갖습니다. 예:agent:zu:telegram:group:-1001234567890:topic:3Persistent ACP topic binding: forum topic은 top-level typed ACP binding을 통해 ACP harness session을 pin할 수 있습니다.bindings[]와type: "acp"그리고match.channel: "telegram"
/acp spawn <agent> --thread here|auto로 현재 Telegram topic을 새 ACP session에 bind할 수 있습니다.- 이후 같은 topic의 메시지는 bound된 ACP session으로 직접 라우팅됩니다(
/acp steer불필요). - OpenClaw는 bind가 성공하면 spawn confirmation message를 해당 topic에 pin합니다.
channels.telegram.threadBindings.spawnAcpSessions=true가 필요합니다.
MessageThreadIdIsForum
message_thread_id가 있는 private chat은 DM routing을 유지하지만 thread-aware session key/reply target을 사용합니다.
Audio, video, and stickers
Audio, video, and stickers
Audio messages
Telegram은 voice note와 audio file을 구분합니다.- default: audio file 동작
- agent reply에
[[audio_as_voice]]tag를 넣으면 voice-note send 강제
Video messages
Telegram은 video file과 video note를 구분합니다.Message action example:Stickers
inbound sticker 처리:- static WEBP: 다운로드 후 처리(placeholder
<media:sticker>) - animated TGS: 건너뜀
- video WEBM: 건너뜀
Sticker.emojiSticker.setNameSticker.fileIdSticker.fileUniqueIdSticker.cachedDescription
~/.openclaw/telegram/sticker-cache.json
Reaction notifications
Reaction notifications
message_reaction update로 도착합니다(message payload와 분리됨).활성화되면 OpenClaw는 다음과 같은 system event를 queue에 넣습니다.Telegram reaction added: 👍 by Alice (@alice) on msg 42
channels.telegram.reactionNotifications:off | own | all(default:own)channels.telegram.reactionLevel:off | ack | minimal | extensive(default:minimal)
own은 bot이 보낸 message에 대한 user reaction만 의미합니다(best-effort, sent-message cache 기반).- reaction event는 Telegram access control(
dmPolicy,allowFrom,groupPolicy,groupAllowFrom)을 그대로 따르며, 권한 없는 sender는 drop됩니다. - Telegram은 reaction update에 thread ID를 제공하지 않습니다.
- non-forum group은 group chat session으로 라우팅
- forum group은 정확한 originating topic이 아니라 group general-topic session(
:topic:1)으로 라우팅
allowed_updates에는 message_reaction이 자동으로 포함됩니다.Ack reactions
Ack reactions
ackReaction은 inbound message를 처리하는 동안 acknowledgement emoji를 보냅니다.Resolution order:channels.telegram.accounts.<accountId>.ackReactionchannels.telegram.ackReactionmessages.ackReaction- agent identity emoji fallback (
agents.list[].identity.emoji, 없으면"👀")
- Telegram은 unicode emoji를 기대합니다(예:
"👀"). - channel이나 account에서 reaction을 끄려면
""를 사용하세요.
Config writes from Telegram events and commands
Config writes from Telegram events and commands
configWrites !== false).Telegram-triggered write에는 다음이 포함됩니다.channels.telegram.groups를 갱신하기 위한 group migration event(migrate_to_chat_id)/config set과/config unset(command enablement 필요)
Long polling vs webhook
Long polling vs webhook
channels.telegram.webhookUrl설정channels.telegram.webhookSecret설정(webhookUrl이 있으면 필수)- optional
channels.telegram.webhookPath(default/telegram-webhook) - optional
channels.telegram.webhookHost(default127.0.0.1) - optional
channels.telegram.webhookPort(default8787)
127.0.0.1:8787에 bind됩니다.public endpoint가 다르다면 앞단에 reverse proxy를 두고 webhookUrl을 public URL로 지정하세요.
의도적으로 external ingress가 필요할 때는 webhookHost(예: 0.0.0.0)를 설정하세요.Limits, retry, and CLI targets
Limits, retry, and CLI targets
channels.telegram.textChunkLimit기본값은 4000channels.telegram.chunkMode="newline"은 길이 기준 분할 전에 paragraph boundary(빈 줄)를 우선 고려channels.telegram.mediaMaxMb(default 100) 는 inbound/outbound Telegram media 크기를 제한channels.telegram.timeoutSeconds는 Telegram API client timeout을 override함(없으면 grammY 기본값 사용)- group context history는
channels.telegram.historyLimit또는messages.groupChat.historyLimit을 사용(default 50),0이면 비활성화 - DM history 제어:
channels.telegram.dmHistoryLimitchannels.telegram.dms["<user_id>"].historyLimit
channels.telegram.retryconfig는 recoverable outbound API error에 대한 Telegram send helper(CLI/tools/actions)에 적용
openclaw message poll을 사용하며 forum topic도 지원합니다.--poll-duration-seconds(5-600)--poll-anonymous--poll-public- forum topic용
--thread-id(또는:topic:target 사용)
channels.telegram.actions.sendMessage=false는 poll을 포함한 outbound Telegram message를 비활성화channels.telegram.actions.poll=false는 일반 send는 유지한 채 Telegram poll 생성만 비활성화
Exec approvals in Telegram
Exec approvals in Telegram
channels.telegram.execApprovals.enabledchannels.telegram.execApprovals.approverschannels.telegram.execApprovals.target(dm|channel|both, default:dm)agentFilter,sessionFilter
enabled가 false이거나 approvers가 비어 있으면 Telegram은 exec approval client로 동작하지 않습니다. approval request는 다른 configured approval route 또는 exec approval fallback policy로 넘어갑니다.Delivery rule:target: "dm"은 configured approver DM에만 approval prompt 전송target: "channel"은 originating Telegram chat/topic으로 prompt를 다시 보냄target: "both"은 approver DM과 originating chat/topic 모두에 전송
/approve도, Telegram approval button도 사용할 수 없습니다.channel delivery는 chat에 command text를 그대로 보여주므로, channel 또는 both는 trusted group/topic에서만 사용하세요. prompt가 forum topic에 도착하면 OpenClaw는 approval prompt와 post-approval follow-up 모두에 동일한 topic을 유지합니다.inline approval button은 channels.telegram.capabilities.inlineButtons가 target surface(dm, group, all)를 허용해야만 동작합니다.관련 문서: Exec approvalsTroubleshooting
Bot does not respond to non mention group messages
Bot does not respond to non mention group messages
requireMention=false라면 Telegram privacy mode가 전체 가시성을 허용해야 합니다.- BotFather:
/setprivacy-> Disable - 이후 bot을 그룹에서 제거했다가 다시 추가
- BotFather:
openclaw channels status는 config가 non-mention group message를 기대할 때 경고를 표시합니다.openclaw channels status --probe는 explicit numeric group ID를 검사할 수 있습니다. wildcard"*"는 membership probe가 불가합니다.- 빠른 session test:
/activation always.
Bot not seeing group messages at all
Bot not seeing group messages at all
channels.telegram.groups가 존재한다면, 해당 그룹이 목록에 있어야 합니다(또는"*"포함)- bot이 그룹 멤버인지 확인
- skip reason 확인용 로그:
openclaw logs --follow
Commands work partially or not at all
Commands work partially or not at all
- sender identity를 authorize하세요(pairing 및/또는 numeric
allowFrom) - group policy가
open이어도 command authorization은 계속 적용됩니다 setMyCommands failed는 보통api.telegram.org에 대한 DNS/HTTPS reachability 문제입니다
Polling or network instability
Polling or network instability
- Node 22+ + custom fetch/proxy 환경에서는 AbortSignal type mismatch로 즉시 abort가 발생할 수 있습니다.
- 일부 host는
api.telegram.org를 먼저 IPv6로 resolve하며, IPv6 egress가 불안정하면 Telegram API 실패가 간헐적으로 발생할 수 있습니다. - 로그에
TypeError: fetch failed또는Network request for 'getUpdates' failed!가 보이면, OpenClaw는 현재 이를 recoverable network error로 retry합니다. - direct egress/TLS가 불안정한 VPS host에서는
channels.telegram.proxy를 통해 Telegram API 호출을 우회하세요.
- Node 22+ 기본값은
autoSelectFamily=true(WSL2 제외)와dnsResultOrder=ipv4first - host가 WSL2이거나 IPv4-only 동작이 더 안정적이라면 family selection을 강제로 설정하세요.
- Environment override(임시):
OPENCLAW_TELEGRAM_DISABLE_AUTO_SELECT_FAMILY=1OPENCLAW_TELEGRAM_ENABLE_AUTO_SELECT_FAMILY=1OPENCLAW_TELEGRAM_DNS_RESULT_ORDER=ipv4first
- DNS answer 확인:
Telegram config reference pointers
Primary reference:-
channels.telegram.enabled: 채널 startup enable/disable -
channels.telegram.botToken: bot token (BotFather) -
channels.telegram.tokenFile: 일반 파일 경로에서 token 읽기. symlink는 거부됨 -
channels.telegram.dmPolicy:pairing | allowlist | open | disabled(default: pairing) -
channels.telegram.allowFrom: DM allowlist (숫자형 Telegram user ID).allowlist는 최소 하나의 sender ID가 필요하고,open은"*"가 필요합니다.openclaw doctor --fix는 legacy@username항목을 ID로 resolve할 수 있고, allowlist migration 흐름에서 pairing-store 파일의 항목을 복구할 수 있습니다. -
channels.telegram.actions.poll: Telegram poll 생성 enable/disable (default: enabled, 여전히sendMessage필요) -
channels.telegram.defaultTo: CLI--deliver가 explicit--reply-to없이 동작할 때 사용할 기본 Telegram target -
channels.telegram.groupPolicy:open | allowlist | disabled(default: allowlist) -
channels.telegram.groupAllowFrom: group sender allowlist (숫자형 Telegram user ID).openclaw doctor --fix는 legacy@username을 ID로 resolve할 수 있습니다. 숫자가 아닌 항목은 auth 시 무시됩니다. group auth는 DM pairing-store fallback을 사용하지 않습니다(2026.2.25+). -
Multi-account precedence:
- 두 개 이상의 account ID가 구성되어 있다면 default routing을 명확히 하기 위해
channels.telegram.defaultAccount를 설정하거나channels.telegram.accounts.default를 포함하세요. - 둘 다 없으면 OpenClaw는 첫 normalized account ID로 fallback하고
openclaw doctor가 경고합니다. channels.telegram.accounts.default.allowFrom과channels.telegram.accounts.default.groupAllowFrom은defaultaccount에만 적용됩니다.- named account는 account-level 값이 없으면
channels.telegram.allowFrom과channels.telegram.groupAllowFrom을 상속합니다. - named account는
channels.telegram.accounts.default.allowFrom/groupAllowFrom을 상속하지 않습니다.
- 두 개 이상의 account ID가 구성되어 있다면 default routing을 명확히 하기 위해
-
channels.telegram.groups: 그룹별 기본값 + allowlist ("*"로 전역 기본값 설정 가능)channels.telegram.groups.<id>.groupPolicy: groupPolicy의 그룹별 override (open | allowlist | disabled)channels.telegram.groups.<id>.requireMention: mention gating 기본값channels.telegram.groups.<id>.skills: skill filter (omit = 모든 skill, empty = 없음)channels.telegram.groups.<id>.allowFrom: 그룹별 sender allowlist overridechannels.telegram.groups.<id>.systemPrompt: 그룹용 추가 system promptchannels.telegram.groups.<id>.enabled:false일 때 그룹 비활성화channels.telegram.groups.<id>.topics.<threadId>.*: topic별 override (group field + topic 전용agentId)channels.telegram.groups.<id>.topics.<threadId>.agentId: 이 topic을 특정 agent로 라우팅 (group-level 및 binding routing보다 우선)
-
channels.telegram.groups.<id>.topics.<threadId>.groupPolicy: groupPolicy의 topic별 override (open | allowlist | disabled) -
channels.telegram.groups.<id>.topics.<threadId>.requireMention: topic별 mention gating override -
top-level
bindings[]와type: "acp", 그리고match.peer.id에 canonical topic idchatId:topic:topicId: persistent ACP topic binding field (ACP Agents 참고) -
channels.telegram.direct.<id>.topics.<threadId>.agentId: DM topic을 특정 agent로 라우팅 (forum topic과 동일 동작) -
channels.telegram.execApprovals.enabled: 이 account에서 Telegram을 chat-based exec approval client로 활성화 -
channels.telegram.execApprovals.approvers: exec request approve/deny 권한이 있는 Telegram user ID. exec approval이 활성화되면 필수 -
channels.telegram.execApprovals.target:dm | channel | both(default:dm).channel과both는 originating Telegram topic이 있으면 이를 유지 -
channels.telegram.execApprovals.agentFilter: forwarded approval prompt용 optional agent ID filter -
channels.telegram.execApprovals.sessionFilter: forwarded approval prompt용 optional session key filter (substring 또는 regex) -
channels.telegram.accounts.<account>.execApprovals: Telegram exec approval routing과 approver authorization의 account별 override -
channels.telegram.capabilities.inlineButtons:off | dm | group | all | allowlist(default: allowlist) -
channels.telegram.accounts.<account>.capabilities.inlineButtons: account별 override -
channels.telegram.commands.nativeSkills: Telegram native skills command enable/disable -
channels.telegram.replyToMode:off | first | all(default:off) -
channels.telegram.textChunkLimit: outbound chunk 크기(chars) -
channels.telegram.chunkMode:length(default) 또는newline, 길이 기준 chunking 전에 빈 줄(문단 경계)에서 나눔 -
channels.telegram.linkPreview: outbound message의 link preview 토글 (default: true) -
channels.telegram.streaming:off | partial | block | progress(live stream preview, default:partial;progress는partial로 매핑;block은 legacy preview mode compatibility). Telegram preview streaming은 하나의 preview message를 같은 자리에서 edit하는 방식입니다. -
channels.telegram.mediaMaxMb: inbound/outbound Telegram media cap (MB, default: 100) -
channels.telegram.retry: recoverable outbound API error에 대한 Telegram send helper(CLI/tools/actions)의 retry policy (attempts, minDelayMs, maxDelayMs, jitter) -
channels.telegram.network.autoSelectFamily: Node autoSelectFamily override (true=enable, false=disable). Node 22+에서는 기본 활성, WSL2에서는 기본 비활성 -
channels.telegram.network.dnsResultOrder: DNS result order override (ipv4first또는verbatim). Node 22+ 기본값은ipv4first -
channels.telegram.proxy: Bot API 호출용 proxy URL (SOCKS/HTTP) -
channels.telegram.webhookUrl: webhook mode 활성화 (channels.telegram.webhookSecret필요) -
channels.telegram.webhookSecret: webhook secret (webhookUrl이 있으면 필수) -
channels.telegram.webhookPath: local webhook path (default/telegram-webhook) -
channels.telegram.webhookHost: local webhook bind host (default127.0.0.1) -
channels.telegram.webhookPort: local webhook bind port (default8787) -
channels.telegram.actions.reactions: Telegram tool reaction gating -
channels.telegram.actions.sendMessage: Telegram tool message send gating -
channels.telegram.actions.deleteMessage: Telegram tool message delete gating -
channels.telegram.actions.sticker: Telegram sticker action gating - send와 search (default: false) -
channels.telegram.reactionNotifications:off | own | all- 어떤 reaction이 system event를 발생시킬지 제어 (설정되지 않으면 defaultown) -
channels.telegram.reactionLevel:off | ack | minimal | extensive- agent의 reaction capability 제어 (설정되지 않으면 defaultminimal) - Configuration reference - Telegram
- startup/auth:
enabled,botToken,tokenFile,accounts.*(tokenFile은 일반 파일이어야 하며 symlink는 거부됨) - access control:
dmPolicy,allowFrom,groupPolicy,groupAllowFrom,groups,groups.*.topics.*, top-levelbindings[](type: "acp") - exec approvals:
execApprovals,accounts.*.execApprovals - command/menu:
commands.native,commands.nativeSkills,customCommands - threading/replies:
replyToMode - streaming:
streaming(preview),blockStreaming - formatting/delivery:
textChunkLimit,chunkMode,linkPreview,responsePrefix - media/network:
mediaMaxMb,timeoutSeconds,retry,network.autoSelectFamily,proxy - webhook:
webhookUrl,webhookSecret,webhookPath,webhookHost - actions/capabilities:
capabilities.inlineButtons,actions.sendMessage|editMessage|deleteMessage|reactions|sticker - reactions:
reactionNotifications,reactionLevel - writes/history:
configWrites,historyLimit,dmHistoryLimit,dms.*.historyLimit