Telegram bot client (Bot API): method reference
Telegram is the Bot API client in the Socialift Python SDK. It works asynchronously with a BotFather token: it sends messages and media, receives updates through a webhook or long polling, and manages groups and channels. For each of the 76 methods below you'll find which Bot API method it calls, when to use it and the limits Telegram enforces. Methods without a wrapper are reachable through call().
from socialift import Telegram76 methodsas of socialift 1.3.0Updated:
How do you set up the Telegram bot client?
Get a token from @BotFather: the /newbot command asks for a name and username and returns a token like 123456:AA.... Anyone with the token controls the bot, so keep it out of your code. If it leaks, generate a new one with /token in BotFather.
Create the client with Telegram(token=...) or Telegram.from_env(), which reads the token from TELEGRAM_BOT_TOKEN and the license key from SOCIALIFT_LICENSE_KEY. Every method also accepts token=, so one client can serve several bots. Leaving the async with block closes the HTTP session.
There are two ways to receive updates, and they are mutually exclusive. A webhook (set_webhook) makes Telegram POST each update to your HTTPS URL — the natural fit for a server, protected with secret_token. Long polling (get_updates or poll()) needs no public URL and suits scripts and local development. Telegram keeps undelivered updates for at most 24 hours.
import asyncio
from socialift import Telegram
async def main():
# TELEGRAM_BOT_TOKEN and SOCIALIFT_LICENSE_KEY are read from the environment
async with Telegram.from_env() as bot:
me = await bot.get_me()
print("Bot:", me["username"])
# No webhook set — use long polling
async for update in bot.poll(allowed_updates=["message"]):
message = update.get("message")
if message and "text" in message:
await bot.reply(
message["chat"]["id"], message["message_id"], "Got it"
)
asyncio.run(main())Bot & setup
Token check, the command menu and moving the bot to another Bot API server.
close_botdelete_my_commandsfrom_envget_meget_my_commandslog_outset_my_commands
close_bot
asyncCalls the Bot API close method, closing the bot instance before moving it from one local Bot API server to another. It's named close_bot because close() on SDK clients closes the HTTP session.
await bot.close_bot(*, token: Optional[str] = None) -> bool- Delete the webhook first so the bot isn't launched again after the server restarts.
- Telegram returns error 429 during the first 10 minutes after the bot is launched.
delete_my_commands
asyncDeletes the command list for a scope and language (deleteMyCommands). Users then see the higher-level list, such as the default scope.
await bot.delete_my_commands(
*,
scope: Optional[dict] = None,
language_code: Optional[str] = None,
token: Optional[str] = None,
) -> boolfrom_env
classmethodCreates a client with the token read from the TELEGRAM_BOT_TOKEN environment variable; other arguments (timeout, retry, license_key, session) go to the constructor. The recommended way to keep the token out of code.
Telegram.from_env(**kwargs) -> Telegram- An empty variable still creates the client —
ConfigurationErroris raised on the first request (unless that call passestoken=).
get_me
asyncReturns the bot's profile (getMe) as a dict: id, username, can_join_groups, can_read_all_group_messages and more. The simplest way to check that the token works.
await bot.get_me(*, token: Optional[str] = None) -> dictcan_read_all_group_messagesistruewhen privacy mode is disabled.- The SDK maps an HTTP 401 or "Unauthorized" response to
AuthError.
me = await bot.get_me()get_my_commands
asyncReturns the commands set for the given scope and language_code (getMyCommands). An empty list means no commands are set for that combination.
await bot.get_my_commands(
*,
scope: Optional[dict] = None,
language_code: Optional[str] = None,
token: Optional[str] = None,
) -> listlog_out
asyncLogs the bot out of Telegram's cloud Bot API server (logOut). Only needed before moving the bot to your own (local) Bot API server.
await bot.log_out(*, token: Optional[str] = None) -> bool- After the call the bot can't log back in to the cloud server for 10 minutes.
- The SDK only sends requests to
https://api.telegram.org, so this client won't work against a local server afterwards. - The dashboard Playground blocks
logOutandclosein its universal call.
set_my_commands
asyncSets the command list shown in the bot menu (setMyCommands), optionally per scope (e.g. only group admins) and language_code. Format: [{"command": "start", "description": "..."}].
await bot.set_my_commands(
commands: list,
*,
scope: Optional[dict] = None,
language_code: Optional[str] = None,
token: Optional[str] = None,
) -> bool- Up to 100 commands; a command is 1–32 characters (lowercase English letters, digits,
_), a description 1–256 characters. - Telegram shows the most specific list that is set: chat + language first, the default scope last.
Updates & webhooks
Long polling, webhook setup and checking that a request really came from Telegram.
delete_webhookget_updatesget_webhook_infopollset_webhookverify_webhook
delete_webhook
asyncRemoves the webhook (deleteWebhook) so you can switch back to get_updates or poll. drop_pending_updates=True discards updates that haven't been delivered yet.
await bot.delete_webhook(
*,
drop_pending_updates: Optional[bool] = None,
token: Optional[str] = None,
) -> boolawait bot.delete_webhook()get_updates
asyncFetches new updates with long polling (getUpdates) and returns a list of Update dicts. To confirm processed updates, pass offset = last update_id + 1 on the next call.
await bot.get_updates(
*,
offset: Optional[int] = None,
limit: Optional[int] = None,
timeout: int = 30,
allowed_updates: Optional[list[str]] = None,
token: Optional[str] = None,
) -> list- Doesn't work while a webhook is set; Telegram keeps undelivered updates for at most 24 hours.
- The SDK caps
timeoutat the client timeout minus 10 seconds (default 30 s client → 20 s wait); for longer waits createTelegram(token=..., timeout=90). limitis 1–100 (default 100).
updates = await bot.get_updates(limit=50, timeout=0)get_webhook_info
asyncReturns the webhook status (getWebhookInfo): url, pending_update_count, last_error_date, last_error_message, max_connections, allowed_updates. Check it first when updates stop arriving.
await bot.get_webhook_info(*, token: Optional[str] = None) -> dict- If the bot uses
getUpdates,urlis an empty string.
info = await bot.get_webhook_info()SDK helper: an endless async for stream on top of getUpdates that advances offset automatically. Meant for scripts and workers without a public HTTPS URL.
bot.poll(
*,
allowed_updates: Optional[list[str]] = None,
timeout: int = 30,
token: Optional[str] = None,
) -> AsyncIterator[dict]- On
RateLimitErrorit waitsretry_after(or 5 s); on other API errors it logs a warning to thesocialift.telegramlogger and retries after 5 s — an invalid token or an active webhook won't stop the loop, so checkget_me()andget_webhook_info()first. - The offset lives only in memory: after a restart the last unconfirmed batch may arrive again — deduplicate by
update_id.
set_webhook
asyncTells Telegram to deliver updates as HTTPS POST requests to your url (setWebhook). Always pass secret_token so you can check incoming requests with verify_webhook.
await bot.set_webhook(
url: str,
*,
secret_token: Optional[str] = None,
allowed_updates: Optional[list[str]] = None,
drop_pending_updates: Optional[bool] = None,
max_connections: Optional[int] = None,
certificate: Union[bytes, socialift.telegram.InputFile, NoneType] = None,
token: Optional[str] = None,
ip_address: Optional[str] = None,
**extra: Any,
) -> bool- Ports: 443, 80, 88, 8443.
secret_tokenis 1–256 characters ofA-Z,a-z,0-9,_and-. - While a webhook is set,
get_updatesandpollreceive nothing. chat_member,message_reactionandmessage_reaction_countaren't sent by default — request them inallowed_updates; omitting the parameter keeps the previous setting.
await bot.set_webhook("https://siz.uz/tg", secret_token="...", allowed_updates=["message"])verify_webhook
staticmethodChecks that the X-Telegram-Bot-Api-Secret-Token header of an incoming webhook request equals the secret_token you set in set_webhook, returning True/False. A synchronous static method with no network call.
Telegram.verify_webhook(headers, secret_token: str) -> bool- Bot API webhooks carry no body signature (unlike Meta's X-Hub-Signature-256) — this header is the only check, so without
secret_tokenanyone who knows the URL can send fake updates. - The comparison is constant-time; an empty
secret_tokenalways returnsFalse. The same function is available associalift.webhooks.verify_telegram_request. - Pass your framework's case-insensitive headers object; a plain dict is only checked for the exact
X-Telegram-Bot-Api-Secret-Tokenspelling and the all-lowercase one.
Sending messages
Text, replies, forwarding and copying, locations, polls, reactions and chat actions.
copy_messagecopy_messagesforward_messageforward_messagesreplysend_chat_actionsend_contactsend_dicesend_locationsend_messagesend_pollsend_venueset_reactionstop_poll
copy_message
asyncCopies a message without a link to the original (copyMessage) and returns only the new message_id (MessageId), not a full Message. caption replaces the media caption; if omitted, the original caption is kept.
await bot.copy_message(
chat_id: Union[int, str],
from_chat_id: Union[int, str],
message_id: int,
*,
caption: Optional[str] = None,
token: Optional[str] = None,
**extra: Any,
) -> dict- Service, paid media, giveaway, giveaway winners and invoice messages can't be copied.
- A quiz can be copied only if the bot knows its correct answers (
correct_option_ids).
copy_messages
asyncCopies 1–100 messages without links to the originals (copyMessages), keeping album grouping. Returns a list of MessageId.
await bot.copy_messages(
chat_id: Union[int, str],
from_chat_id: Union[int, str],
message_ids: Iterable[int],
*,
token: Optional[str] = None,
**extra: Any,
) -> list- IDs in strictly increasing order; messages that can't be found or copied are skipped.
forward_message
asyncForwards one message with a "Forwarded from" header (forwardMessage) and returns the new Message. Use copy_message when the source must not be shown.
await bot.forward_message(
chat_id: Union[int, str],
from_chat_id: Union[int, str],
message_id: int,
*,
message_thread_id: Optional[int] = None,
disable_notification: Optional[bool] = None,
protect_content: Optional[bool] = None,
token: Optional[str] = None,
**extra: Any,
) -> dict- Service messages and messages with protected content can't be forwarded.
- This wrapper has no
**extra; usecall("forwardMessage", ...)for newer parameters.
forward_messages
asyncForwards 1–100 messages in one request (forwardMessages) and returns a list of MessageId objects (IDs only). Album grouping is kept.
await bot.forward_messages(
chat_id: Union[int, str],
from_chat_id: Union[int, str],
message_ids: Iterable[int],
*,
token: Optional[str] = None,
**extra: Any,
) -> list- IDs must be in strictly increasing order.
- Messages that can't be found or forwarded are skipped without an error.
reply
asyncSDK shortcut: send_message with reply_parameters={"message_id": message_id}, so the new message shows as a reply. Any other send_message argument is passed through.
await bot.reply(
chat_id: Union[int, str],
message_id: int,
text: str,
**kwargs: Any,
) -> dict- Don't pass
reply_parametersyourself — it's already set, and a duplicate argument raisesTypeErrorin Python.
send_chat_action
asyncShows a status like "typing…" or "sending photo…" in the chat while the bot prepares a response (sendChatAction). The default action is typing.
await bot.send_chat_action(
chat_id: Union[int, str],
action: str = 'typing',
*,
message_thread_id: Optional[int] = None,
token: Optional[str] = None,
**extra: Any,
) -> bool- The status lasts 5 seconds or less and clears when the bot's message arrives — repeat it during long operations.
- Actions:
typing,upload_photo,record_video,upload_video,record_voice,upload_voice,upload_document,choose_sticker,find_location,record_video_note,upload_video_note.
send_contact
asyncSends a phone contact card (sendContact): phone_number, first_name and optional last_name. Returns the sent Message.
await bot.send_contact(
chat_id: Union[int, str],
phone_number: str,
first_name: str,
*,
last_name: Optional[str] = None,
token: Optional[str] = None,
**extra: Any,
) -> dictsend_dice
asyncSends an animated emoji with a random value (sendDice): dice, darts, basketball, football, bowling or slot machine. The result is in dice.value of the returned Message.
await bot.send_dice(
chat_id: Union[int, str],
*,
emoji: Optional[str] = None,
token: Optional[str] = None,
**extra: Any,
) -> dict- Values: 1–6 for 🎲 🎯 🎳, 1–5 for 🏀 ⚽, 1–64 for 🎰; the default emoji is 🎲.
send_location
asyncSends a point on the map (sendLocation). With live_period it becomes a live location that can be updated.
await bot.send_location(
chat_id: Union[int, str],
latitude: float,
longitude: float,
*,
live_period: Optional[int] = None,
token: Optional[str] = None,
**extra: Any,
) -> dictlive_periodis 60–86400 seconds, or0x7FFFFFFFfor a live location that can be edited indefinitely.- Update a live location with
call("editMessageLiveLocation", ...).
send_message
asyncSends a text message to a user, group or channel (sendMessage) and returns the sent Message dict. chat_id is a numeric ID or the @username of a public channel or supergroup.
await bot.send_message(
chat_id: Union[int, str],
text: str,
*,
parse_mode: Optional[str] = None,
entities: Optional[list] = None,
link_preview_options: Optional[dict] = None,
disable_notification: Optional[bool] = None,
protect_content: Optional[bool] = None,
message_thread_id: Optional[int] = None,
reply_parameters: Optional[dict] = None,
reply_markup: Optional[dict] = None,
business_connection_id: Optional[str] = None,
message_effect_id: Optional[str] = None,
token: Optional[str] = None,
**extra: Any,
) -> dict- Text is 1–4096 characters after entity parsing;
parse_modeisHTML,MarkdownV2or legacyMarkdown. - When a group becomes a supergroup its ID changes: a request with the old ID raises
ApiError, and the new ID is inexc.payload["parameters"]["migrate_to_chat_id"]. message_thread_idtargets a forum topic; parameters not in the signature (e.g.allow_paid_broadcast) go through**extra.
await bot.send_message("@mening_kanalim", "Salom!", parse_mode="HTML")send_poll
asyncSends a native poll (sendPoll) — regular, or a quiz with type="quiz". Returns the Message with the poll object.
await bot.send_poll(
chat_id: Union[int, str],
question: str,
options: list,
*,
is_anonymous: Optional[bool] = None,
allows_multiple_answers: Optional[bool] = None,
type: Optional[str] = None,
correct_option_id: Optional[int] = None,
token: Optional[str] = None,
correct_option_ids: Optional[Sequence[int]] = None,
**extra: Any,
) -> dict- The question is 1–300 characters;
optionsis 1–12 items, officiallyInputPollOptionobjects:[{"text": "Yes"}, {"text": "No"}]. - Since Bot API 9.6 quizzes take
correct_option_ids(a list) instead ofcorrect_option_id— pass it via**extra:correct_option_ids=[0]. - Polls are anonymous by default (
is_anonymousdefaults totrue).
send_venue
asyncSends a venue (sendVenue) — a map point with a title and an address. Returns the sent Message.
await bot.send_venue(
chat_id: Union[int, str],
latitude: float,
longitude: float,
title: str,
address: str,
*,
token: Optional[str] = None,
**extra: Any,
) -> dictset_reaction
asyncSets the bot's reaction on a message (setMessageReaction), e.g. reaction=[{"type": "emoji", "emoji": "👍"}]; is_big=True plays the big animation.
await bot.set_reaction(
chat_id: Union[int, str],
message_id: int,
*,
reaction: Optional[list] = None,
is_big: Optional[bool] = None,
token: Optional[str] = None,
) -> bool- As a non-premium user, a bot can set at most one reaction per message and can't use paid reactions.
- A custom emoji reaction works only if it's already on the message or allowed by the chat admins.
stop_poll
asyncStops a poll sent by the bot (stopPoll) and returns the final Poll object with its results.
await bot.stop_poll(
chat_id: Union[int, str],
message_id: int,
*,
reply_markup: Optional[dict] = None,
token: Optional[str] = None,
**extra: Any,
) -> dictMedia & files
Photos, videos, documents, audio, stickers, albums and downloading files.
downloadget_fileget_user_profile_photossend_animationsend_audiosend_documentsend_media_groupsend_photosend_stickersend_videosend_video_notesend_voice
download
asyncSDK helper: calls getFile, downloads the file and returns its contents as bytes. Handy for saving photos or documents users send to the bot.
await bot.download(file_id: str, *, token: Optional[str] = None) -> bytes- The cloud Bot API's 20 MB limit applies; the whole file is read into memory.
- On an HTTP error it raises
ApiErrorwith the token inurlreplaced by<token>.
get_file
asyncReturns file metadata (getFile), including the file_path needed to download it. Use download() to get the bytes in one step.
await bot.get_file(file_id: str, *, token: Optional[str] = None) -> dict- The download link is valid for at least 1 hour; call
getFileagain when it expires. - Through the cloud Bot API, bots can download files up to 20 MB.
- The original file name and MIME type may not be preserved — save them from the incoming message.
Returns a user's profile photos (getUserProfilePhotos): total_count and photos, each in several sizes. Page with offset and limit (1–100, default 100).
await bot.get_user_profile_photos(
user_id: int,
*,
offset: Optional[int] = None,
limit: Optional[int] = None,
token: Optional[str] = None,
) -> dictsend_animation
asyncSends a GIF or a silent H.264/MPEG-4 AVC video as an animation (sendAnimation). Up to 50 MB uploaded.
await bot.send_animation(
chat_id: Union[int, str],
animation: Union[str, bytes, socialift.telegram.InputFile],
*,
token: Optional[str] = None,
**extra: Any,
) -> dictsend_audio
asyncSends a music file (sendAudio) that Telegram clients show in the music player. Format .MP3 or .M4A, up to 50 MB uploaded; for voice notes use send_voice.
await bot.send_audio(
chat_id: Union[int, str],
audio: Union[str, bytes, socialift.telegram.InputFile],
*,
caption: Optional[str] = None,
token: Optional[str] = None,
**extra: Any,
) -> dictsend_document
asyncSends any file as a document (sendDocument) and returns the Message with the document object. Up to 50 MB when uploaded.
await bot.send_document(
chat_id: Union[int, str],
document: Union[str, bytes, socialift.telegram.InputFile],
*,
caption: Optional[str] = None,
token: Optional[str] = None,
**extra: Any,
) -> dict- By URL, only
.PDFand.ZIPfiles are guaranteed to work. - With raw
bytesthe SDK uses the parameter name (document) as the file name; useInputFile(content=..., filename="report.pdf")to set a proper one.
with open("hisobot.pdf", "rb") as f:
await bot.send_document("@kanal", f.read(), caption="Hisobot")send_media_group
asyncSends an album of 2–10 photos, videos, documents or audio files (sendMediaGroup) and returns a list of Messages. To upload bytes, set "media": "attach://name" in the item and pass name=InputFile(...) as an extra argument.
await bot.send_media_group(
chat_id: Union[int, str],
media: list,
*,
token: Optional[str] = None,
**extra: Any,
) -> list- Documents and audio can only be grouped with items of the same type.
- Each item is an
InputMedia*dict, e.g.{"type": "photo", "media": "<file_id or URL>", "caption": "..."}.
send_photo
asyncSends a photo (sendPhoto) from a file_id, an HTTP(S) URL, bytes or an InputFile — the SDK switches to a multipart upload automatically. has_spoiler=True hides it under a spoiler.
await bot.send_photo(
chat_id: Union[int, str],
photo: Union[str, bytes, socialift.telegram.InputFile],
*,
caption: Optional[str] = None,
parse_mode: Optional[str] = None,
has_spoiler: Optional[bool] = None,
reply_markup: Optional[dict] = None,
token: Optional[str] = None,
**extra: Any,
) -> dict- Up to 10 MB uploaded, 5 MB by URL; width + height ≤ 10000 and aspect ratio ≤ 20.
- Caption is 0–1024 characters.
- Reuse the
file_idfrom the response to resend the file without uploading it again (it's valid only for this bot).
send_sticker
asyncSends a sticker (sendSticker): static .WEBP, animated .TGS or video .WEBM. Returns the sent Message.
await bot.send_sticker(
chat_id: Union[int, str],
sticker: Union[str, bytes, socialift.telegram.InputFile],
*,
token: Optional[str] = None,
**extra: Any,
) -> dict- Only .WEBP stickers can be sent by URL.
send_video
asyncSends an MPEG4 video (sendVideo); other formats can be sent as a document. duration, width, height, supports_streaming and thumbnail are optional.
await bot.send_video(
chat_id: Union[int, str],
video: Union[str, bytes, socialift.telegram.InputFile],
*,
caption: Optional[str] = None,
duration: Optional[int] = None,
width: Optional[int] = None,
height: Optional[int] = None,
supports_streaming: Optional[bool] = None,
thumbnail: Union[str, bytes, socialift.telegram.InputFile, NoneType] = None,
token: Optional[str] = None,
**extra: Any,
) -> dict- Up to 50 MB uploaded, 20 MB by URL.
thumbnailmust be a JPEG under 200 kB, at most 320×320, and is used only when the video itself is uploaded.
send_video_note
asyncSends a round video message (sendVideoNote) — a square MPEG4 video up to 1 minute long.
await bot.send_video_note(
chat_id: Union[int, str],
video_note: Union[str, bytes, socialift.telegram.InputFile],
*,
token: Optional[str] = None,
**extra: Any,
) -> dict- Can't be sent by URL — pass a
file_idor a file to upload (bytes/InputFile).
send_voice
asyncSends a playable voice message (sendVoice). The Bot API accepts .OGG with OPUS, .MP3 or .M4A; other formats may be sent as audio or a document.
await bot.send_voice(
chat_id: Union[int, str],
voice: Union[str, bytes, socialift.telegram.InputFile],
*,
token: Optional[str] = None,
**extra: Any,
) -> dict- Up to 50 MB uploaded; by URL the file must be
audio/oggand at most 1 MB (1–20 MB files arrive as documents).
Editing, deleting & pinning
Change text, captions, media and buttons of sent messages; delete and pin them.
delete_messagedelete_messagesedit_message_captionedit_message_mediaedit_message_reply_markupedit_message_textpin_messageunpin_all_messagesunpin_message
delete_message
asyncDeletes one message, including service messages (deleteMessage). Returns True on success.
await bot.delete_message(
chat_id: Union[int, str],
message_id: int,
*,
token: Optional[str] = None,
) -> bool- Only messages sent less than 48 hours ago can be deleted.
- In private chats a bot can delete both its own and incoming messages; in groups it deletes others' messages only as an admin, and in supergroups and channels with the
can_delete_messagesright. - Service messages about supergroup, channel or forum topic creation can't be deleted.
delete_messages
asyncDeletes 1–100 messages in one request (deleteMessages), with the same limits as delete_message. Returns True.
await bot.delete_messages(
chat_id: Union[int, str],
message_ids: Iterable[int],
*,
token: Optional[str] = None,
) -> bool- Messages that can't be found are skipped.
await bot.delete_messages("@kanal", [41, 42])edit_message_caption
asyncChanges the caption of a media message (editMessageCaption). The message is identified the same way as in edit_message_text.
await bot.edit_message_caption(
*,
caption: Optional[str] = None,
chat_id: Union[int, str, NoneType] = None,
message_id: Optional[int] = None,
inline_message_id: Optional[str] = None,
parse_mode: Optional[str] = None,
reply_markup: Optional[dict] = None,
token: Optional[str] = None,
**extra: Any,
) -> Any- Caption is 0–1024 characters; returns the Message, or
Truefor inline messages.
edit_message_media
asyncReplaces the media in a message (animation, audio, document, photo, video) or turns a text message into a media one (editMessageMedia). media is an InputMedia dict such as {"type": "photo", "media": "<file_id or URL>"}.
await bot.edit_message_media(
media: dict,
*,
chat_id: Union[int, str, NoneType] = None,
message_id: Optional[int] = None,
inline_message_id: Optional[str] = None,
reply_markup: Optional[dict] = None,
token: Optional[str] = None,
**extra: Any,
) -> Any- In an album, audio can only become audio, a document only a document, and a photo/video a photo or video.
- This wrapper takes no extra arguments, so upload a new file via
attach://withcall("editMessageMedia", ..., media={"type": "photo", "media": "attach://p"}, p=InputFile(...)). - Inline messages can't get a newly uploaded file — use a
file_idor URL.
Replaces only the inline keyboard (reply_markup) without touching the text (editMessageReplyMarkup) — e.g. to update buttons after a callback.
await bot.edit_message_reply_markup(
*,
reply_markup: Optional[dict] = None,
chat_id: Union[int, str, NoneType] = None,
message_id: Optional[int] = None,
inline_message_id: Optional[str] = None,
token: Optional[str] = None,
**extra: Any,
) -> Any- Returns the Message, or
Truefor inline messages.
edit_message_text
asyncEdits a message's text (editMessageText). Identify the message with chat_id + message_id, or inline_message_id if it was sent in inline mode.
await bot.edit_message_text(
text: str,
*,
chat_id: Union[int, str, NoneType] = None,
message_id: Optional[int] = None,
inline_message_id: Optional[str] = None,
parse_mode: Optional[str] = None,
reply_markup: Optional[dict] = None,
token: Optional[str] = None,
**extra: Any,
) -> Any- Returns the edited Message, or
Truefor inline messages. - Business messages not sent by the bot and without an inline keyboard can only be edited within 48 hours.
await bot.edit_message_text("Yangi matn", chat_id="@kanal", message_id=42)pin_message
asyncPins a message in a chat (pinChatMessage); disable_notification=True pins it without notifying members.
await bot.pin_message(
chat_id: Union[int, str],
message_id: int,
*,
disable_notification: Optional[bool] = None,
token: Optional[str] = None,
**extra: Any,
) -> bool- In groups the bot must be an admin with
can_pin_messages, in channels withcan_edit_messages; private chats need no rights.
await bot.pin_message("@kanal", 42, disable_notification=True)unpin_all_messages
asyncClears all pinned messages in a chat (unpinAllChatMessages).
await bot.unpin_all_messages(
chat_id: Union[int, str],
*,
token: Optional[str] = None,
) -> bool- Requires
can_pin_messagesin groups orcan_edit_messagesin channels; not needed in private chats.
unpin_message
asyncUnpins a message (unpinChatMessage). Without message_id, the most recent pinned message (by send date) is unpinned.
await bot.unpin_message(
chat_id: Union[int, str],
*,
message_id: Optional[int] = None,
token: Optional[str] = None,
**extra: Any,
) -> bool- Same rights as
pin_message:can_pin_messagesin groups,can_edit_messagesin channels.
await bot.unpin_message("@kanal", message_id=42)Chats, moderation & admins
Chat info and settings, bans, restrictions and admin rights.
ban_memberdelete_chat_photodemote_memberget_chatget_chat_administratorsget_chat_memberget_chat_member_countleave_chatpromote_memberrestrict_memberset_admin_titleset_chat_descriptionset_chat_permissionsset_chat_photoset_chat_titleunban_member
ban_member
asyncBans a user (banChatMember): in supergroups and channels they can't return, even via invite links, until unbanned. revoke_messages=True deletes their messages in the group (always the case in supergroups and channels).
await bot.ban_member(
chat_id: Union[int, str],
user_id: int,
*,
until_date: Optional[int] = None,
revoke_messages: Optional[bool] = None,
token: Optional[str] = None,
) -> booluntil_dateis Unix time; less than 30 seconds or more than 366 days from now means a permanent ban (supergroups and channels only).- To just kick a user (they may rejoin), call
ban_memberand thenunban_member. - The bot must be an admin with the appropriate rights.
await bot.ban_member("@guruh", 123456789)
await bot.unban_member("@guruh", 123456789)delete_chat_photo
asyncDeletes the chat photo (deleteChatPhoto). Not available for private chats; the bot must be an admin with the appropriate rights.
await bot.delete_chat_photo(
chat_id: Union[int, str],
*,
token: Optional[str] = None,
) -> booldemote_member
asyncSDK helper: calls promoteChatMember with every admin right set to False, removing the user's admin status.
await bot.demote_member(
chat_id: Union[int, str],
user_id: int,
*,
token: Optional[str] = None,
) -> bool- The bot needs
can_promote_membersand can only demote admins it promoted, directly or indirectly.
get_chat
asyncReturns up-to-date full chat information (getChat, ChatFullInfo): type, title, description, pinned message, permissions and more. Also a handy way to resolve a @username to a numeric id.
await bot.get_chat(chat_id: Union[int, str], *, token: Optional[str] = None) -> dictchat = await bot.get_chat("@kanal")Returns the chat's administrators as ChatMember dicts (getChatAdministrators): status, rights, custom_title.
await bot.get_chat_administrators(
chat_id: Union[int, str],
*,
token: Optional[str] = None,
return_bots: Optional[bool] = None,
**extra: Any,
) -> list- Other bots are omitted by default; include them with
call("getChatAdministrators", chat_id=..., return_bots=True)— this wrapper takes no extra arguments. - The Bot API has no method that lists all members; use the account client's
TelegramAccount.participantsfor that.
admins = await bot.get_chat_administrators("@guruh")get_chat_member
asyncReturns one member's status (getChatMember): creator, administrator, member, restricted, left or kicked, with their rights. Often used to check a channel subscription.
await bot.get_chat_member(
chat_id: Union[int, str],
user_id: int,
*,
token: Optional[str] = None,
) -> dict- For other users it's only guaranteed to work if the bot is an admin in the chat.
member = await bot.get_chat_member("@guruh", 123456789)Returns the number of members in a chat as an integer (getChatMemberCount).
await bot.get_chat_member_count(
chat_id: Union[int, str],
*,
token: Optional[str] = None,
) -> intleave_chat
asyncMakes the bot leave a group, supergroup or channel (leaveChat).
await bot.leave_chat(chat_id: Union[int, str], *, token: Optional[str] = None) -> boolpromote_member
asyncPromotes a user to admin or changes their rights (promoteChatMember); pass rights as keyword arguments such as can_delete_messages=True, can_restrict_members=True.
await bot.promote_member(
chat_id: Union[int, str],
user_id: int,
*,
token: Optional[str] = None,
**rights: Any,
) -> bool- Works in supergroups and channels; the bot must be an admin with the appropriate rights and can only grant a subset of its own (
can_promote_members). - Passing
Falsefor all rights demotes the user —demote_memberdoes exactly that.
restrict_member
asyncRestricts a supergroup member with a permissions dict (restrictChatMember) — e.g. {"can_send_messages": False} to mute them. Pass True for all permissions to lift restrictions.
await bot.restrict_member(
chat_id: Union[int, str],
user_id: int,
permissions: dict,
*,
until_date: Optional[int] = None,
use_independent_chat_permissions: Optional[bool] = None,
token: Optional[str] = None,
) -> booluntil_date: less than 30 seconds or more than 366 days from now means restricted forever.- The bot must be an admin with the appropriate rights.
set_admin_title
asyncSets a custom title for a supergroup admin promoted by the bot (setChatAdministratorCustomTitle).
await bot.set_admin_title(
chat_id: Union[int, str],
user_id: int,
custom_title: str,
*,
token: Optional[str] = None,
) -> bool- 0–16 characters, no emoji.
set_chat_description
asyncChanges the description of a group, supergroup or channel (setChatDescription), 0–255 characters.
await bot.set_chat_description(
chat_id: Union[int, str],
description: str,
*,
token: Optional[str] = None,
) -> bool- The bot must be an admin with the appropriate rights.
await bot.set_chat_title("@kanal", "Yangi nom")
await bot.set_chat_description("@kanal", "Tavsif")set_chat_permissions
asyncSets default permissions for all regular members of a group or supergroup (setChatPermissions), e.g. {"can_send_messages": False} for a read-only chat.
await bot.set_chat_permissions(
chat_id: Union[int, str],
permissions: dict,
*,
use_independent_chat_permissions: Optional[bool] = None,
token: Optional[str] = None,
) -> bool- The bot must be an admin with
can_restrict_members. - Without
use_independent_chat_permissions=True,can_send_other_messagesandcan_add_web_page_previewsimply the media permissions, andcan_send_pollsimpliescan_send_messages.
set_chat_photo
asyncSets a new chat photo (setChatPhoto). Only an uploaded file (bytes or InputFile) is accepted — not a file_id or URL.
await bot.set_chat_photo(
chat_id: Union[int, str],
photo: Union[bytes, socialift.telegram.InputFile],
*,
token: Optional[str] = None,
) -> bool- Not available for private chats; the bot must be an admin with the appropriate rights.
set_chat_title
asyncChanges the chat title (setChatTitle), 1–128 characters. Not available for private chats.
await bot.set_chat_title(
chat_id: Union[int, str],
title: str,
*,
token: Optional[str] = None,
) -> bool- The bot must be an admin with the appropriate rights.
await bot.set_chat_title("@kanal", "Yangi nom")
await bot.set_chat_description("@kanal", "Tavsif")unban_member
asyncLifts a ban in a supergroup or channel (unbanChatMember); the user doesn't return automatically but can rejoin via a link.
await bot.unban_member(
chat_id: Union[int, str],
user_id: int,
*,
only_if_banned: bool = True,
token: Optional[str] = None,
) -> bool- The SDK defaults to
only_if_banned=True(the Bot API default is false), so a current member who isn't banned isn't removed by mistake. - With
only_if_banned=FalseTelegram removes the user if they're still in the chat — afterwards they're not a member but can join.
await bot.ban_member("@guruh", 123456789)
await bot.unban_member("@guruh", 123456789)Invite links & join requests
Primary and additional links, revoking them, approving join requests.
approve_join_requestcreate_invite_linkdecline_join_requestedit_invite_linkexport_invite_linkrevoke_invite_link
approve_join_request
asyncApproves a join request (approveChatJoinRequest) — for example in response to a chat_join_request update from a link with creates_join_request=True.
await bot.approve_join_request(
chat_id: Union[int, str],
user_id: int,
*,
token: Optional[str] = None,
) -> bool- The bot must be an admin with
can_invite_users; without it,chat_join_requestupdates don't arrive either.
create_invite_link
asyncCreates an additional invite link (createChatInviteLink) with name, expire_date, member_limit or creates_join_request, returning a ChatInviteLink dict — for example one link per ad campaign.
await bot.create_invite_link(
chat_id: Union[int, str],
*,
name: Optional[str] = None,
expire_date: Optional[int] = None,
member_limit: Optional[int] = None,
creates_join_request: Optional[bool] = None,
token: Optional[str] = None,
) -> dictnameis 0–32 characters,member_limit1–99999;member_limitcan't be combined withcreates_join_request=True.- The bot must be an admin with the appropriate rights.
link = await bot.create_invite_link("@guruh", name="Reklama", member_limit=100)decline_join_request
asyncDeclines a join request (declineChatJoinRequest).
await bot.decline_join_request(
chat_id: Union[int, str],
user_id: int,
*,
token: Optional[str] = None,
) -> bool- The bot must be an admin with
can_invite_users.
edit_invite_link
asyncEdits a non-primary invite link created by the bot (editChatInviteLink); pass name, expire_date, member_limit or creates_join_request as keyword arguments. Returns the updated ChatInviteLink.
await bot.edit_invite_link(
chat_id: Union[int, str],
invite_link: str,
*,
token: Optional[str] = None,
**extra: Any,
) -> dictexport_invite_link
asyncGenerates a new primary invite link and returns it as a string (exportChatInviteLink). The previous primary link is revoked.
await bot.export_invite_link(
chat_id: Union[int, str],
*,
token: Optional[str] = None,
) -> str- Bots can't use links created by other admins. For an extra link that doesn't break existing ones, use
create_invite_link. - The bot must be an admin with the appropriate rights.
revoke_invite_link
asyncRevokes an invite link created by the bot and returns it (revokeChatInviteLink). If the primary link is revoked, Telegram generates a new one automatically.
await bot.revoke_invite_link(
chat_id: Union[int, str],
invite_link: str,
*,
token: Optional[str] = None,
) -> dictForum topics
Create and manage topics in forum supergroups or private chats with the bot.
create_forum_topicdelete_forum_topicedit_forum_topic
create_forum_topic
asyncCreates a topic in a forum supergroup or a private chat with a user (createForumTopic) and returns a ForumTopic dict with message_thread_id. icon_color and icon_custom_emoji_id go through **extra.
await bot.create_forum_topic(
chat_id: Union[int, str],
name: str,
*,
token: Optional[str] = None,
**extra: Any,
) -> dict- The name is 1–128 characters.
- In a supergroup the bot must be an admin with
can_manage_topics. - Post into the topic with
send_message(..., message_thread_id=...).
delete_forum_topic
asyncDeletes a forum topic along with all its messages (deleteForumTopic).
await bot.delete_forum_topic(
chat_id: Union[int, str],
message_thread_id: int,
*,
token: Optional[str] = None,
) -> bool- In a supergroup the bot must be an admin with
can_delete_messages.
edit_forum_topic
asyncChanges a topic's name or icon (icon_custom_emoji_id) (editForumTopic); fields you don't pass stay unchanged.
await bot.edit_forum_topic(
chat_id: Union[int, str],
message_thread_id: int,
*,
token: Optional[str] = None,
**extra: Any,
) -> bool- In a supergroup it requires
can_manage_topics, unless the bot created the topic.
Inline mode & callbacks
Answering inline button presses and inline queries.
answer_callback_queryanswer_inline_query
Answers an inline keyboard button press (answerCallbackQuery) with an optional notification (text) or an alert (show_alert=True). Call it for every callback_query, even without text.
await bot.answer_callback_query(
callback_query_id: str,
*,
text: Optional[str] = None,
show_alert: Optional[bool] = None,
url: Optional[str] = None,
cache_time: Optional[int] = None,
token: Optional[str] = None,
) -> bool- Until you answer, Telegram clients show a progress indicator on the button.
textis 0–200 characters;cache_time(seconds) defaults to 0.
answer_inline_query
asyncSends results for an inline query (answerInlineQuery), triggered when a user types @your_bot query in any chat. results is a list of InlineQueryResult dicts; cache_time, is_personal and next_offset go through **extra.
await bot.answer_inline_query(
inline_query_id: str,
results: list,
*,
token: Optional[str] = None,
**extra: Any,
) -> bool- At most 50 results per query; the server-side
cache_timedefaults to 300 seconds. - Enable inline mode with
/setinlinein @BotFather.
Low-level call
Call any Bot API method by name.
call
asyncCalls any Bot API method by name and returns its result — for methods without a dedicated wrapper, e.g. await bot.call("getChatMenuButton", chat_id=...). Arguments set to None are dropped, and bytes/InputFile values switch the request to multipart automatically.
await bot.call(method: str, *, token: Optional[str] = None, **params: Any) -> Any- Errors: 401 →
AuthError, 403 →PermissionError, 404 or "not found" in the description →NotFoundError, 429 →RateLimitError; anything else isApiErrorwith the raw response inexc.payload. - In
ApiError.urlthe token is replaced with<token>. - Unwrapped methods also work as attributes:
bot.get_chat_menu_button(chat_id=1)→getChatMenuButton(keyword arguments only).
commands = await bot.call("getMyCommands")Methods shared by all clients
Every HTTP client (Telegram, Facebook, Instagram, LinkedIn, TikTok, Ads) has these low-level methods — for calling an endpoint the SDK doesn't wrap yet or for reading pages of results. The connection is closed automatically when the async with block ends.
request
asyncSends an arbitrary HTTP request and returns the JSON response — for endpoints the SDK doesn't wrap with a dedicated method yet. You pass the token and signing parameters yourself in params or headers (access_token, and for Meta appsecret_proof via socialift.crypto.appsecret_proof).
await bot.request(
method: str,
url: str,
*,
params: Optional[Mapping[str, Any]] = None,
data: Optional[Any] = None,
json: Optional[Any] = None,
headers: Optional[Mapping[str, str]] = None,
) -> AnyNonevalues inparamsare not sent.- Rate limits (
RateLimitError) and transient server errors (HTTP 429, 500, 502, 503, 504) are retried according toRetryPolicy; aRetry-Afterheader is honoured. Network failures are raised asTransportError.
get
asyncShorthand for request("GET", ...).
await bot.get(url: str, **kw) -> Anypost
asyncShorthand for request("POST", ...).
await bot.post(url: str, **kw) -> Anydelete
asyncShorthand for request("DELETE", ...).
await bot.delete(url: str, **kw) -> Anypaginate
asyncFollows Meta's cursor pagination (paging.next) and returns every data item as a single list.
await bot.paginate(
url: str,
*,
params: Optional[Mapping[str, Any]] = None,
max_items: int = 500,
page_size: int = 100,
) -> list[dict]max_items(default 500) is a safety cap — a large account can have tens of thousands of records.page_sizesets thelimitof each request.
close
asyncCloses the HTTP session the SDK created itself (a session you passed in is left open). Called automatically when you use async with Client(...).
await bot.close() -> NoneFrequently asked questions
Where do I get a Telegram bot token?
Send /newbot to @BotFather: it asks for a name and username and gives you a token. Anyone holding the token can control your bot, so store it in the TELEGRAM_BOT_TOKEN environment variable. If it leaks, generate a new one with the /token command in BotFather.
Should I use a webhook or getUpdates?
If you have a server with a public HTTPS URL, use a webhook: set_webhook(url, secret_token=...) on port 443, 80, 88 or 8443. For scripts and local development use poll() (long polling). They don't work together: while a webhook is set, getUpdates returns nothing, so call delete_webhook() to switch back.
Why doesn't my bot see messages in a group?
Privacy mode is on by default: in groups the bot only receives commands meant for it, replies to it and service messages. A bot that is a group admin receives all messages. You can disable privacy mode in BotFather, but the bot must be re-added to the group for it to take effect; can_read_all_group_messages in the get_me() response shows the current state.
Can a bot get the full list of group members?
No. The Bot API only returns the admin list (get_chat_administrators), a single member's status (get_chat_member) and the member count (get_chat_member_count). For the full list or message history use the MTProto-based TelegramAccount client, which acts as a user account rather than a bot.
How many messages per second can a Telegram bot send?
According to Telegram's Bot FAQ: no more than about one message per second to a single chat, 20 messages per minute to a group, and roughly 30 messages per second for bulk notifications. Beyond that Telegram returns 429; the SDK retries and raises RateLimitError if the limit persists. Bots with paid broadcasts enabled in BotFather (eligibility rules apply) can send up to 1000 messages per second.