Skip to main content
Socialift
Documentation sections
SDK reference

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.

python
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

Calls 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.

Deletes 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,
) -> bool

from_env

classmethod

Creates 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 — ConfigurationError is raised on the first request (unless that call passes token=).

get_me

async

Returns 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) -> dict
  • can_read_all_group_messages is true when privacy mode is disabled.
  • The SDK maps an HTTP 401 or "Unauthorized" response to AuthError.
Example — python
me = await bot.get_me()

Returns 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,
) -> list

log_out

async

Logs 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 logOut and close in its universal call.

Sets 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

Removes 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,
) -> bool
Example — python
await bot.delete_webhook()

Fetches 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 timeout at the client timeout minus 10 seconds (default 30 s client → 20 s wait); for longer waits create Telegram(token=..., timeout=90).
  • limit is 1–100 (default 100).
Example — python
updates = await bot.get_updates(limit=50, timeout=0)

Returns 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, url is an empty string.
Example — python
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 RateLimitError it waits retry_after (or 5 s); on other API errors it logs a warning to the socialift.telegram logger and retries after 5 s — an invalid token or an active webhook won't stop the loop, so check get_me() and get_webhook_info() first.
  • The offset lives only in memory: after a restart the last unconfirmed batch may arrive again — deduplicate by update_id.

Tells 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_token is 1–256 characters of A-Z, a-z, 0-9, _ and -.
  • While a webhook is set, get_updates and poll receive nothing.
  • chat_member, message_reaction and message_reaction_count aren't sent by default — request them in allowed_updates; omitting the parameter keeps the previous setting.
Example — python
await bot.set_webhook("https://siz.uz/tg", secret_token="...", allowed_updates=["message"])

verify_webhook

staticmethod

Checks 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_token anyone who knows the URL can send fake updates.
  • The comparison is constant-time; an empty secret_token always returns False. The same function is available as socialift.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-Token spelling 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

Copies 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).

Copies 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.

Forwards 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; use call("forwardMessage", ...) for newer parameters.

Forwards 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

async

SDK 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_parameters yourself — it's already set, and a duplicate argument raises TypeError in Python.

Shows 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.

Sends 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,
) -> dict

Sends 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 🎲.

Sends 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,
) -> dict
  • live_period is 60–86400 seconds, or 0x7FFFFFFF for a live location that can be edited indefinitely.
  • Update a live location with call("editMessageLiveLocation", ...).

Sends 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_mode is HTML, MarkdownV2 or legacy Markdown.
  • When a group becomes a supergroup its ID changes: a request with the old ID raises ApiError, and the new ID is in exc.payload["parameters"]["migrate_to_chat_id"].
  • message_thread_id targets a forum topic; parameters not in the signature (e.g. allow_paid_broadcast) go through **extra.
Example — python
await bot.send_message("@mening_kanalim", "Salom!", parse_mode="HTML")

Sends 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; options is 1–12 items, officially InputPollOption objects: [{"text": "Yes"}, {"text": "No"}].
  • Since Bot API 9.6 quizzes take correct_option_ids (a list) instead of correct_option_id — pass it via **extra: correct_option_ids=[0].
  • Polls are anonymous by default (is_anonymous defaults to true).

Sends 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,
) -> dict

Sets 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.

Stops 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,
) -> dict

Media & 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

SDK 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 ApiError with the token in url replaced by <token>.

Returns 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 getFile again 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,
) -> dict

Sends 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,
) -> dict

Sends 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,
) -> dict

Sends 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 .PDF and .ZIP files are guaranteed to work.
  • With raw bytes the SDK uses the parameter name (document) as the file name; use InputFile(content=..., filename="report.pdf") to set a proper one.
Example — python
with open("hisobot.pdf", "rb") as f:
    await bot.send_document("@kanal", f.read(), caption="Hisobot")

Sends 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": "..."}.

Sends 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_id from the response to resend the file without uploading it again (it's valid only for this bot).

Sends 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.

Sends 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.
  • thumbnail must be a JPEG under 200 kB, at most 320×320, and is used only when the video itself is uploaded.

Sends 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_id or a file to upload (bytes/InputFile).

Sends 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/ogg and 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

Deletes 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_messages right.
  • Service messages about supergroup, channel or forum topic creation can't be deleted.

Deletes 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.
Example — python
await bot.delete_messages("@kanal", [41, 42])

Changes 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 True for inline messages.

Replaces 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:// with call("editMessageMedia", ..., media={"type": "photo", "media": "attach://p"}, p=InputFile(...)).
  • Inline messages can't get a newly uploaded file — use a file_id or 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 True for inline messages.

Edits 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 True for inline messages.
  • Business messages not sent by the bot and without an inline keyboard can only be edited within 48 hours.
Example — python
await bot.edit_message_text("Yangi matn", chat_id="@kanal", message_id=42)

Pins 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 with can_edit_messages; private chats need no rights.
Example — python
await bot.pin_message("@kanal", 42, disable_notification=True)

Clears 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_messages in groups or can_edit_messages in channels; not needed in private chats.

Unpins 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_messages in groups, can_edit_messages in channels.
Example — python
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

Bans 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,
) -> bool
  • until_date is 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_member and then unban_member.
  • The bot must be an admin with the appropriate rights.
Example — python
await bot.ban_member("@guruh", 123456789)
await bot.unban_member("@guruh", 123456789)

Deletes 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,
) -> bool

SDK 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_members and can only demote admins it promoted, directly or indirectly.

Returns 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) -> dict
Example — python
chat = 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.participants for that.
Example — python
admins = await bot.get_chat_administrators("@guruh")

Returns 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.
Example — python
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,
) -> int

Makes the bot leave a group, supergroup or channel (leaveChat).

await bot.leave_chat(chat_id: Union[int, str], *, token: Optional[str] = None) -> bool

Promotes 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 False for all rights demotes the user — demote_member does exactly that.

Restricts 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,
) -> bool
  • until_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.

Sets 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.

Changes 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.
Example — python
await bot.set_chat_title("@kanal", "Yangi nom")
await bot.set_chat_description("@kanal", "Tavsif")

Sets 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_messages and can_add_web_page_previews imply the media permissions, and can_send_polls implies can_send_messages.

Sets 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.

Changes 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.
Example — python
await bot.set_chat_title("@kanal", "Yangi nom")
await bot.set_chat_description("@kanal", "Tavsif")

Lifts 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=False Telegram removes the user if they're still in the chat — afterwards they're not a member but can join.
Example — python
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

Approves 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_request updates don't arrive either.

Declines 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.

Forum topics

Create and manage topics in forum supergroups or private chats with the bot.

create_forum_topicdelete_forum_topicedit_forum_topic

Creates 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=...).

Deletes 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.

Changes 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.
  • text is 0–200 characters; cache_time (seconds) defaults to 0.

Sends 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_time defaults to 300 seconds.
  • Enable inline mode with /setinline in @BotFather.

Low-level call

Call any Bot API method by name.

call

call

async

Calls 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 is ApiError with the raw response in exc.payload.
  • In ApiError.url the token is replaced with <token>.
  • Unwrapped methods also work as attributes: bot.get_chat_menu_button(chat_id=1) → getChatMenuButton (keyword arguments only).
Example — python
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

async

Sends 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,
) -> Any
  • None values in params are not sent.
  • Rate limits (RateLimitError) and transient server errors (HTTP 429, 500, 502, 503, 504) are retried according to RetryPolicy; a Retry-After header is honoured. Network failures are raised as TransportError.

get

async

Shorthand for request("GET", ...).

await bot.get(url: str, **kw) -> Any

post

async

Shorthand for request("POST", ...).

await bot.post(url: str, **kw) -> Any

delete

async

Shorthand for request("DELETE", ...).

await bot.delete(url: str, **kw) -> Any

Follows 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_size sets the limit of each request.

close

async

Closes 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() -> None

Frequently 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.

Sources

  1. Telegram Bot API
  2. Bot API changelog
  3. Telegram Bot FAQ
  4. Telegram Bot Features — BotFather and privacy mode

Related pages