Managing Telegram groups and channels through the API
There are two ways to manage Telegram groups and channels through the API. With the Bot API, an admin bot creates invite links, approves join requests, restricts and bans members. A user account (MTProto) adds member lists, slow mode, scheduled posts that Telegram sends itself, and channel statistics. Every action requires the matching admin rights.
Updated:
In short: what you do with which API
An admin bot covers day-to-day moderation: invite links, join requests, restrictions, bans, promoting admins, default permissions and polls are all in the Bot API. What the Bot API lacks — full member lists, enabling slow mode, scheduling messages and channel statistics — is done over MTProto with a user account that is an admin of the chat.
Methods by task: bot vs account
Method names in the Socialift SDK: Telegram (Bot API) on the left, TelegramAccount (MTProto) on the right.
| Task | Bot API (Telegram) | Account (TelegramAccount) |
|---|---|---|
| Additional invite link | create_invite_link (name, expire_date, member_limit, creates_join_request) | create_invite_link (title, expire_date, usage_limit, request_needed) |
| Primary link | export_invite_link — revokes the previous one | invite_link |
| Revoking a link | revoke_invite_link | revoke_invite_link |
| Join requests | chat_join_request update + approve_join_request / decline_join_request | join_requests + approve_join_request(..., approved=...) |
| Promoting and demoting admins | promote_member, demote_member, set_admin_title | promote, demote |
| Restricting (mute) | restrict_member | restrict, mute_member |
| Removing and banning | ban_member, unban_member | kick, ban, unban |
| Default member permissions | set_chat_permissions | set_default_permissions |
| Slow mode | No method | set_slowmode |
| Polls | send_poll, stop_poll | send_poll |
| Scheduled messages | No | send_message(..., schedule=...), scheduled |
| Members | get_chat_administrators, get_chat_member, get_chat_member_count | participants, admins, banned |
| Channel statistics | No | stats |
A private group with join requests: bot setup
Make the bot an admin
Give it at least the invite users right (can_invite_users) — without it, the bot neither sees nor approves requests.
Create a request link
create_invite_link(..., creates_join_request=True). In this mode you can't setmember_limit, so pick one or the other. Addexpire_date(a Unix timestamp) for an expiry.Receive the updates
The bot gets a
chat_join_requestupdate. If you narrowedallowed_updatesmanually, include chat_join_request.Review the request
Using
user_chat_idfrom the update, the bot can message the user for 5 minutes until the request is processed — to ask a quick question, for instance. Check against your CRM or payments database.Decide
Call
approve_join_requestordecline_join_request. Revoke links you no longer need withrevoke_invite_link.
Bot: expiring link and request approval
import time
from socialift import Telegram
async def make_link(bot: Telegram, chat: str) -> str:
link = await bot.create_invite_link(
chat, name="September promo",
expire_date=int(time.time()) + 7 * 86400, # 7 days
creates_join_request=True, # not combined with member_limit
)
return link["invite_link"]
async def on_update(bot: Telegram, update: dict) -> None:
req = update.get("chat_join_request")
if not req:
return
chat_id, user_id = req["chat"]["id"], req["from"]["id"]
if await is_paid_customer(user_id): # your own check
await bot.approve_join_request(chat_id, user_id)
else:
await bot.decline_join_request(chat_id, user_id)Link names are 0–32 characters. member_limit (1–99999) caps how many users who joined through the link can be members at the same time.
export_invite_link regenerates the primary link and revokes the previous one. To keep an ad campaign's link from dying suddenly, give each campaign its own link via create_invite_link. Bots can't use links created by other admins.
Bot: restrict, ban and appoint a moderator
import time
async def moderate(bot, chat_id: int, spammer_id: int, moderator_id: int) -> None:
# Mute for 1 hour (supergroups only)
await bot.restrict_member(chat_id, spammer_id, {"can_send_messages": False},
until_date=int(time.time()) + 3600)
# Full ban: no until_date means forever
await bot.ban_member(chat_id, spammer_id)
# Moderator: a bot can only grant rights it holds itself
await bot.promote_member(chat_id, moderator_id, can_delete_messages=True,
can_restrict_members=True, can_pin_messages=True)
await bot.set_admin_title(chat_id, moderator_id, "Moderator")If until_date is less than 30 seconds or more than 366 days from now, Telegram treats the restriction or ban as permanent.
unban_member defaults to only_if_banned=True; otherwise Telegram would also remove a user who is currently a member. To remove admin rights, use demote_member (in the Bot API that equals passing False for every right).
Account: slow mode, polls and a scheduled post
The account must be an admin of the group or channel with the relevant rights.
from datetime import datetime, timedelta, timezone
from socialift import TelegramAccount
async def weekly_setup() -> None:
async with TelegramAccount.from_env() as tg:
await tg.set_slowmode("@my_group", 30) # 0 turns it off
await tg.send_poll("@my_group", "Which day works for the webinar?",
["Tuesday", "Thursday"])
when = datetime.now(timezone.utc) + timedelta(hours=18)
await tg.send_message("@my_channel", "Morning digest", schedule=when)
queue = await tg.scheduled("@my_channel")A scheduled message goes into a queue on Telegram's servers and Telegram sends it at the set time — your app doesn't need to be running. Each chat has its own queue.
Slow mode only works in supergroups, and Telegram accepts only fixed intervals, returning SECONDS_INVALID otherwise. Admins with the manage chat right aren't affected by it. The SDK's promote() grants many rights by default (all except add_admins), so pass False for the ones you don't want.
Member lists: what is and isn't possible
The Bot API doesn't return a full member list. A bot can get the admin list (get_chat_administrators), one user's status (get_chat_member, reliable when the bot is an admin) and the member count. To track joins and leaves, the bot must be an admin and explicitly list chat_member in allowed_updates — that update isn't delivered by default.
With an account, participants() returns a list, with caveats: only admins can see channel subscribers, supergroup admins can hide the member list, and a complete list isn't guaranteed for very large groups. aggressive=True collects more, but the extra requests raise FLOOD_WAIT risk.
For scale: a supergroup supports up to 200,000 members, while legacy basic groups top out at 200. Channels have no subscriber cap.
Channel statistics
Telegram only gives detailed statistics to admins of channels above a certain size. The exact threshold is a server-side setting, so don't hard-code a number — check the can_view_stats flag.
async def channel_report(tg, channel: str) -> dict | None:
full = await tg.chat_full(channel)
if not full.full_chat.can_view_stats:
return None # channel too small or insufficient rights
stats = await tg.stats(channel)
return {
"followers": stats.followers.current,
"views_per_post": stats.views_per_post.current,
}The response includes follower growth, views, shares and reactions per post, the share of subscribers with notifications enabled, and more.
Ethics and Telegram's anti-spam rules
The groups and channels API is for working with your audience, not for spam. Violations can cost you the account permanently.
- Don't bulk-add strangers to groups. If a user's privacy settings forbid it, Telegram returns USER_PRIVACY_RESTRICTED — send invite links only to people who asked for them.
- Don't message or invite people from bought lists or lists scraped from other groups.
- Don't inflate subscribers or views: Telegram bans such API use permanently.
- Don't automate actions the account owner doesn't know about or hasn't agreed to — that breaks the API Terms of Service.
- Respect limits: a bot can send no more than 20 messages per minute to a group, and an account must wait out FLOOD_WAIT.
- Prefer request links over open joining — they filter out spam bots and random visitors alike.
Frequently asked questions
Can a bot get every member of a group?
No. The Bot API returns only the admin list, a single member's status and the member count. A full list needs an admin account and MTProto, and even then channel subscribers are visible to admins only.
Can an invite link have both a member limit and join requests?
Not in the Bot API: with creates_join_request=True you can't set member_limit. Choose an open link with a limit or a request link; an expiry (expire_date) works with either.
Can a bot turn on slow mode?
The Bot API has no method for setting slow mode — a bot can only read the current value from chat info. Enable it over MTProto with an admin account: set_slowmode("@group", 30) in the SDK, and 0 to turn it off.
Why did exportChatInviteLink kill my old link?
That method regenerates the bot's primary link and revokes the previous one. If you need several active links, use create_invite_link, which creates an additional link and leaves existing ones alone.
Why can't I get channel statistics?
Telegram only shows statistics to admins of channels above a certain size, and the threshold is set server-side. Check the can_view_stats flag in the chat_full() response and make sure the account is a channel admin.
Can a bot post to a channel?
Yes, if the bot is a channel admin with the right to post. The channel's @username works as chat_id. Scheduling a post isn't available in the Bot API, though — use the account's send_message(..., schedule=...) for that.