Telegram logoTelegram
权限管理
Bot命令
权限
群组
API
角色
配置

Telegram Bot Fine-Grained Command Permissions Setup Guide

Telegram Technical Team
December 21, 2025
Telegram Bot command permissions, fine-grained access control Telegram, how to restrict bot commands in group, Telegram Bot API permission models, role-based command control Telegram, member operation limits Telegram, Telegram group admin vs bot permissions, hierarchical command authorization Telegram, Telegram bot permission troubleshooting, step by step Telegram bot command security
Learn how to lock down Telegram Bot commands per role, group size and risk level with Bot API 8.0 fine-grained permissions, plus migration tips and rollback paths.

Why Fine-Grained Command Permissions Matter in 2025

Telegram Bot API 8.0 (Oct 2025) finally exposes the same ACL engine Telegram uses internally for channels. Instead of the old binary “group admin vs. member” switch, you can now grant a bot command to a single user, a forum topic, or even a time window. For communities above 20 k members this is the difference between a usable help desk and a spam magnet.

The feature is backward-compatible: bots that never declare permissions keep the legacy “any member can invoke” behaviour. Once you publish a /mycommand@mybot scope list, Telegram starts enforcing it silently. That silent flip is the migration risk we will neutralise below.

Capability vs. Constraint: What You Can and Cannot Lock

Granular Levers You Control

  • User ID whitelist – single user or a CSV list up to 100 entries per command.
  • Role mask – owner, admin with a specific custom title, or member.
  • Chat type – groups, super-groups, channels, forum topics, voice chats.
  • Time window – start/end Unix timestamp; useful for AMAs.
  • Rate limit – max invocations per user per 60 s window (1–60).

These levers are evaluated server-side before the update reaches your bot, so rejected traffic never burns your CPU or connection pool. Yet they are static: once published, a scope cannot reference live data such as on-chain balances or off-chain reputation scores. Design your command surface accordingly.

Hard Limits You Must Accept

Telegram still treats message read and callback query as separate flows; permissions apply only to slash commands. Inline bots, WebApp buttons and payment invoices ignore the ACL list—those surfaces require manual checks inside your handler. Another constraint: a bot can publish at most 200 scoped commands globally; after that you must reuse identifiers or create a second bot.

Version Map: Where the UI Lives on Each Client

PlatformPath (10.9+)Fallback if missing
AndroidGroup ➜ Manage bot ➜ Command permissionsLong-press any /command message ➜ Restrict
iOSGroup Info ➜ Bots ➜ ⋯ ➜ Edit Command RightsSame long-press entry point
Desktop (tdesktop 5.2+)⋯ menu ➜ Manage group ➜ Bots ➜ Command ACLRight-click user ➜ Restrict ➜ Commands tab

If you run a self-managed bot and the entry point is missing, the group is probably a legacy basic group; convert it to a super-group first (automatic once membership > 200).

Step-by-Step: Publishing Scoped Commands via BotFather

  1. Open @BotFather, send /mycommands, pick your bot.
  2. Choose Edit command list ➜ Add new scope.
  3. Input template (JSON, max 3 kB):
    {"command":"report","scope":{"type":"chat_member","chat_id":-1001234567890,"user_id":678901234},"language":"en"}
  4. BotFather replies with a fingerprint; save it—this is your rollback ticket.
  5. Repeat for every command/scope pair, then publish with /publishcommands.

The new list becomes active within 30 s; existing groups cache the old ACL for up to 5 min, so test with a fresh super-group to avoid false negatives.

Programmatic Route: setMyCommands with scope object

If you run continuous-deployment, editing via BotFather is tedious. The HTTP endpoint https://api.telegram.org/bot{token}/setMyCommands now accepts a scope parameter:

curl -d '{"commands":[{"command":"stats","description":"Hourly KPI"}],"scope":{"type":"chat_administrators","chat_id":-1001234567890}}' \
-H "Content-Type: application/json" \
-X POST https://api.telegram.org/bot$TOKEN/setMyCommands

The call is idempotent; send an empty commands array to delete that scope. Remember to URL-encode the bearer token if you embed it in CI logs.

Migration Playbook: From Legacy All-Open to Scoped

Stage 1 – Audit Current Usage

Enable /echo debugging for 24 h and log every user_id + command. Sort by frequency; anything below 0.5 % daily usage is a candidate for restriction or deletion.

Stage 2 – Shadow Mode

Publish the new scoped list but keep your code’s manual checks in place. If a user is rejected by both layers, write a metric acl_double_deny. When that metric is zero for 48 h, it is safe to remove the manual gate.

Stage 3 – Rollback Plan

Store the BotFather fingerprint from step 4. Rolling back is one message: /revertcommands {fingerprint}. The operation is atomic and reverts in under 60 s, so you can afford to experiment during peak hours.

Compatibility Matrix: Which Clients Obey the ACL?

Client/VersionRespects command ACLGraceful fallback
Official iOS ≥10.5✅Hides command in menu
Official Android ≥10.5✅Same
Telegram Desktop ≥5.2✅Shows but greyed out
WebK / WebA (2025-12)✅Silent ignore
Third-party wrappers (Nicegram, Plus)⚠️May still display; enforcement server-side

Even if a legacy client displays the command, the server returns error 400: COMMAND_NOT_ALLOWED, so your bot never receives the update—safe for compliance.

Risk Scenarios and Mitigations

Accidental Admin Lockout

If you restrict /recover to owner only and the owner leaves, no one can reclaim the bot. Always create a break-glass command scoped to chat_member with a trusted backup account.

Rate-Limit DoS

Setting the per-user rate to 1/60 s sounds secure, but a 20 k group can still hammer the bot with 20 k requests per minute. Combine ACL with IP-level throttling in your reverse proxy.

Fragmented Permissions in Forum Topics

Topics inherit the parent group’s ACL, yet each topic has its own message_thread_id. If your bot logic branches by topic, verify scope.type=forum_topic explicitly; otherwise a user may invoke a command in Topic-A and unintentionally affect Topic-B.

Concrete Example: 10 k-Member NFT Channel

Project “PixelPanda” runs public mint announcements in a super-group (ID -1001122334455). Commands:

  • /mint – open mint URL (high risk, only mods)
  • /price – floor price (any member)
  • /report – spam reporter (any member, 1 per 60 s)

They publish three scopes:

scope 1: chat_administrators → /mint
scope 2: all_chat_members → /price
scope 3: all_chat_members + rate=1 → /report

Outcome: mint links stopped leaking, yet support volume stayed flat because /price remained self-serve. Over 30 days, acl_double_deny logged zero hits, so they removed legacy manual checks, shaving 120 ms off median response time.

Verification & Observability

Add a structured JSON log line for every denied call:

{"t":"acl_denied","uid":123,"cmd":"mint","scope":"chat_administrators","chat":-1001122334455,"ts":1703001234}

In Grafana, plot rate(acl_denied[5m]) by cmd. A sudden spike either signals an attack or mis-configuration. Combine with bot_command_total to keep the deny ratio below 1 % for healthy communities.

When NOT to Use Fine-Grained ACLs

  • Small private groups (< 300 users) – manual admin approval is faster.
  • Commands that must stay available during Telegram outages – ACL checks run on Telegram servers; if their core API hiccups, your command surface is down too.
  • Highly dynamic lists (raffle participants changing every minute) – the 200 scope ceiling and 30 s propagation make real-time updates impractical.
Work assumption: scopes are cached for 5 min at the edge. If you need instant revocation, keep an in-memory deny list in your handler and treat ACL as a first filter only.

Best-Practice Checklist (Copy-Paste Ready)

  1. Always keep one break-glass command scoped to owner.
  2. Document the fingerprint after every BotFather publish.
  3. Log denials with enough granularity to replay incidents.
  4. Test rate limits with gnuplot or vegeta before going live.
  5. Convert basic groups to super-groups first; saves a support ticket.
  6. Remove legacy manual checks only after 48 h of zero acl_double_deny.
  7. Re-audit quarterly; stale admin scopes are a social-engineering vector.

Case Study 1: 40 k-Member Gaming Super-Group

Context: A gaming community ran weekly tournaments and needed /register open only during a 90-minute window.

Implementation: They created a time-window scope start=1704000000 end=1704005400 for /register and left other commands untouched. Registration traffic peaked at 3 000 invocations within 30 min; ACL automatically rejected 120 late attempts without server load.

Result: Manual moderation dropped from 5 mods to 1. Post-event survey showed 97 % of users found the process “clear and fair”.

Revisit: The only hiccup was timezone confusion—always store Unix timestamps in UTC and surface a countdown bot message 15 min before open.

Case Study 2: 250-Member Startup Internal Channel

Context: A startup wanted interns to run /deploy_staging but not /deploy_prod.

Implementation: They scoped /deploy_prod to a CSV whitelist of 5 senior engineers and left /deploy_staging open to all_chat_members. Deployment frequency remained unchanged; no accidental prod pushes occurred during the 3-month observation window.

Result: On-call incidents related to “wrong environment” dropped to zero. Intern onboarding time shortened by one day because security rules were enforced by infrastructure, not tribal knowledge.

Revisit: When a senior engineer left, removing his UID from the whitelist took 30 s via setMyCommands, eliminating the usual “Did we revoke Jenkins too?” panic.

Monitoring & Rollback Runbook

1. Alerting Signals

  • acl_denied rate > 5 % of total commands for any 5-min window.
  • COMMAND_NOT_ALLOWED errors spike > 100 / min (possible mis-configuration).
  • Median response latency drops suddenly after ACL publish (can indicate upstream caching issues).

2. Locating the Fault

  1. Filter logs by chat_id and cmd to isolate offending scope.
  2. Compare scope fingerprint in log with latest BotFather receipt.
  3. Use /getMyCommands with the same scope object to verify Telegram’s view.

3. Rollback Instructions

Send BotFather: /revertcommands {fingerprint}. Confirm reply “Commands reverted” within 60 s. Re-run your audit query; denials should fall to zero immediately.

4. Quarterly Drill Checklist

  1. Create dummy command /drill_YYYYMMDD scoped to yourself.
  2. Invoke from another account—expect denial.
  3. Revert and ensure denial stops.
  4. Archive logs for compliance.

FAQ

Q: Can I mix scoped and legacy commands in the same bot?
A: Yes. Commands without a scope remain world-invokable. Be careful—publishing even one scope turns on enforcement for that command globally.
Q: What happens if I hit the 200 scope ceiling?
A: Telegram returns 400 SCOPE_LIMIT_EXCEEDED. You must reuse command identifiers or spin up a second bot; there is no paid tier to raise the limit.
Q: Do rate limits apply per chat or per user?
A: Per user per command. Two different users each get 60 invocations / 60 s; one user cannot consume another’s quota.
Q: Can scopes reference channel usernames instead of IDs?
A: No. Only numeric chat_id and user_id are accepted; usernames are resolved at publish time and then replaced.
Q: Are ACL checks logged by Telegram for audit?
A: Telegram does not expose server-side logs. You must log update reception or lack thereof in your own infrastructure.
Q: How long can a time-window scope be?
A: Up to 1 year (31 536 000 s). There is no recurring schedule; recreate scopes weekly or automate via CI.
Q: Does the fingerprint change after rollback?
A: Yes. Each publish generates a new fingerprint; old ones become invalid.
Q: Can I scope a command to a linked discussion group?
A: Yes. Use the super-group chat_id of the linked group; channel and group scopes are independent.
Q: Will editing a message affect ACL retroactively?
A: No. ACL is checked at invocation time; edited messages do not re-trigger validation.
Q: Is there IPv6 or IP-based scope?
A: Not at present. IP restrictions must be implemented in your own reverse proxy.

Glossary

TermDefinitionFirst Seen
ACLAccess-control list; set of rules deciding who may invoke a commandIntroduction
ScopeJSON object attached to a command defining ACL constraintssetMyCommands
FingerprintUnique token returned by BotFather after publishing scopesStep 4
Shadow modeRunning new ACL alongside legacy manual checks for safetyMigration
Basic groupLegacy group with < 200 members; lacks ACL UIVersion Map
Super-groupUpgraded group supporting admin roles and ACLVersion Map
Role maskBitwise enumeration: owner, admin, member, custom_titleGranular Levers
Rate limitMax 60 invocations per user per 60-second sliding windowGranular Levers
Break-glassEmergency command scoped to owner for recoveryRisk Mitigation
Double denyRejection by both ACL and manual code checkShadow Mode
COMMAND_NOT_ALLOWEDServer error returned when ACL blocks invocationCompatibility
Forum topicThread inside a super-group with its own message_thread_idFragmented Permissions
Time-window scopeScope valid only between two Unix timestampsGranular Levers
BotFather fingerprintRollback token; changes on every publishStep 4
200 scope ceilingGlobal hard cap per bot; no exceptionsHard Limits
Conditional scopeRumoured future type binding on-chain stateRoadmap

Risk & Boundary Summary

  • Scopes are cached for ~5 min; instant revocation requires in-bot deny list.
  • Commands outside the slash namespace (inline, WebApp, pay) ignore ACL—keep manual checks.
  • ACL enforcement depends on Telegram uptime; mission-critical bots should duplicate checks client-side.
  • There is no IPv6, country, or device-based scope; use your reverse proxy for such rules.
  • The 200-scope cap is fixed; shard across multiple bots if necessary.

Future Trends / Version Expectations

Strings extracted from 10.9 beta suggest Telegram is testing conditional scopes that query external NFT or token contracts. If shipped, admins will be able to allow /airdrop only for holders of a given collection. Early indicators show scope.type=conditional_contract already parses in the UI, but no stable release date has been announced. Operators of Web3 communities should future-proof by storing user wallet addresses today; a migration guide will likely require mapping Ethereum or TON addresses to Telegram user IDs and signing a nonce to prove ownership.

Bottom Line

Fine-grained command permissions turn Telegram from a friendly chat app into a hardened multi-role platform. The setup cost is a one-time JSON file and a handful of BotFather messages, but the payoff is immediate: fewer support nightmares, cleaner audit trails, and a bot surface that scales to 200 k members without drama. Migrate gradually, log religiously, and keep that rollback fingerprint under your pillow.