Skip to main content
Socialift
Documentation sections
SDK reference

TelegramAccount: automate a Telegram user account in Python over MTProto

TelegramAccount is an async Python client that acts as a regular Telegram user over MTProto, built on Telethon. It covers what the Bot API cannot: reading chat history, listing group members, joining groups and channels on its own, creating channels, posting stories and scheduling messages. You log in once with a phone number, the login code and, if enabled, the 2FA password, then reuse the session string.

from socialift import TelegramAccount90 methodsas of socialift 1.3.0Updated:

How do I set up TelegramAccount and log in?

First get an api_id and api_hash: log in to my.telegram.org with your Telegram number, open API development tools and fill in the form. Per Telegram's rules, each phone number can currently have only one api_id. Keep the keys out of your code, in the TELEGRAM_API_ID and TELEGRAM_API_HASH environment variables.

Install with pip install "socialift[telegram]" — Telethon comes in as an optional extra (Python 3.11+). The license key is read from SOCIALIFT_LICENSE_KEY or the license_key= argument and checked on connect(). async with TelegramAccount(...) as tg: opens the connection and closes it when the block exits.

Login takes three steps: send_code() → sign_in() → sign_in_password() if the account has a 2FA password. Store the session string from the result; next time TelegramAccount.from_env() reads it from TELEGRAM_SESSION and no code is needed. If the steps run in separate HTTP requests, also pass the intermediate session returned by send_code() to the next step: the phone_code_hash is only valid inside that session.

Treat the session string like a password: it holds the authorization key and grants full account access. Store it encrypted, never log it and never send it to a browser. If it leaks, call log_out() or terminate the session from another device. To try methods without code, connect the account under Ulanishlar (Connections) in the dashboard and call them from the Playground.

python
import asyncio
import os

from socialift import TelegramAccount

PHONE = "+14155550123"


async def login() -> str:
    # Once: phone -> code -> (if enabled) 2FA password
    async with TelegramAccount(
        api_id=os.environ["TELEGRAM_API_ID"],
        api_hash=os.environ["TELEGRAM_API_HASH"],
    ) as tg:
        sent = await tg.send_code(PHONE)
        code = input("Code from Telegram: ")
        result = await tg.sign_in(PHONE, code, phone_code_hash=sent["phone_code_hash"])
        if result["two_factor_required"]:
            result = await tg.sign_in_password(input("2FA password: "))
        return result["session"]  # store encrypted -> TELEGRAM_SESSION


async def main() -> None:
    # Afterwards: TELEGRAM_API_ID, TELEGRAM_API_HASH, TELEGRAM_SESSION
    async with TelegramAccount.from_env() as tg:
        me = await tg.me()
        await tg.send_message("me", f"Hello, {me.first_name}!")


asyncio.run(main())  # first run: print(asyncio.run(login()))

Connection & login

Create the client, log in with phone, code and 2FA password, export the session string, manage active sessions.

closeconnectdisconnectexport_sessionfrom_envis_authorizedlog_outreset_sessionsend_codesessionssign_insign_in_password

close

async

Alias of disconnect(), matching the close() name used by the other SDK clients.

await tg.close() -> None

connect

async

Opens the MTProto connection and checks the license, but does not check account authorization — the login flow needs a connection before it is authorized. async with TelegramAccount(...) calls it for you.

await tg.connect() -> TelegramAccount
  • Most methods connect on their own, but some (raw, export_session, join, create_channel, stats, contacts, resolve) expect an open connection — use async with or call connect() first.
  • Calling it on a connected client is safe and does nothing.

Closes the connection; called automatically when an async with block exits. The Telegram session stays valid, so the stored session string keeps working.

await tg.disconnect() -> None
  • To also terminate the session on Telegram's side, use log_out().

Returns the current session as a StringSession string so you can reconnect later with TelegramAccount(session=...) without a code. Synchronous, but needs an open connection.

tg.export_session() -> str
  • The string holds the data-center address and the authorization key, i.e. full account access. Store it encrypted and never log it.
  • If it leaks: log_out(), or reset_session() from another session.

from_env

classmethod

Builds the client from environment variables: TELEGRAM_API_ID, TELEGRAM_API_HASH and the optional TELEGRAM_SESSION. Extra keyword arguments (license_key, proxy, device_model ...) go to the constructor.

TelegramAccount.from_env(**kwargs) -> TelegramAccount
  • With an empty TELEGRAM_SESSION the client has no session, so you must log in first (send_code → sign_in).
  • A missing or non-positive TELEGRAM_API_ID, or an empty TELEGRAM_API_HASH, raises ConfigurationError.

Whether the current session is logged in — True or False. Handy for checking that a stored session still works.

await tg.is_authorized() -> bool
  • If the session was terminated from another device, other methods raise AuthError and the account must be reconnected.
Example — python
ok = await tg.is_authorized()

log_out

async

Terminates the session on Telegram (auth.logOut) and closes the connection. The stored session string stops working; reconnecting needs the phone number and a code again.

await tg.log_out() -> bool
  • To just close the connection and keep the session, use disconnect().
Example — python
await tg.log_out()

Terminates a session on another device by its hash from sessions() (account.resetAuthorization).

await tg.reset_session(session_id: int) -> Any
  • Telegram refuses to log out other sessions if the current one logged in less than 24 hours ago (FRESH_RESET_AUTHORISATION_FORBIDDEN).
Example — python
await tg.reset_session(session_hash)

Login step 1: requests a login code for the phone number and returns the phone_code_hash plus an intermediate session string. Pass the number in international format; spaces and dashes are stripped for you.

await tg.send_code(phone: str) -> dict
  • The code may arrive in a Telegram app where the account is already logged in rather than by SMS; the type field tells you where it went.
  • The phone_code_hash is only valid inside that session: if the steps run in separate requests, continue with TelegramAccount(..., session=sent["session"]).
  • If the session is already authorized, no code is sent and already_authorized: True is returned.
Example — python
sent = await tg.send_code("+998901234567")

Lists every active session (device) on the account via account.getAuthorizations. Each entry has the device, app, activity time and a hash.

await tg.sessions() -> Any
  • The hash identifies the session for reset_session().
Example — python
sessions = await tg.sessions()

sign_in

async

Login step 2: signs in with the received code and phone_code_hash. On success it returns authorized: True, the permanent session string and user (id, username, phone, name).

await tg.sign_in(
    phone: str,
    code: str,
    *,
    phone_code_hash: Optional[str] = None,
) -> dict
  • If the account has a 2FA password, no exception is raised; you get two_factor_required: True and call sign_in_password() next.
  • A wrong or expired code, an invalid phone number or a bad api_id/api_hash pair raises AuthError with a readable message.
Example — python
result = await tg.sign_in("+998901234567", code="12345", phone_code_hash=sent["phone_code_hash"])

Login step 3: completes sign-in with the two-factor (2FA) password and returns the same result shape as sign_in().

await tg.sign_in_password(password: str) -> dict
  • The password is never sent in plain text: Telegram uses the SRP protocol and Telethon computes the proof locally.
  • A wrong password raises AuthError. Do not log or store the password.
Example — python
result = await tg.sign_in_password("mening-parolim")

Profile & account

Current account, name and bio, username, profile photos.

delete_profile_photosmeprofile_photosset_profile_photoset_usernameupdate_profile

Deletes profile photos; without photos it deletes every profile photo on the account.

await tg.delete_profile_photos(photos: Optional[Sequence[Any]] = None) -> Any
  • To delete a single photo, pass its object from profile_photos() in a list — calling without arguments removes them all.

me

async

The current account as a User: id, name, username, phone. Useful to confirm whose session you hold.

await tg.me() -> Any
Example — python
me = await tg.me()

Profile photos of a user, group or channel; defaults to your own, up to 20.

await tg.profile_photos(entity: Union[int, str, Any] = 'me', *, limit: int = 20) -> list

Uploads and sets a new profile photo from a file path, bytes or a file object.

await tg.set_profile_photo(file: Any) -> Any

Sets the account's public @username; an empty string removes it.

await tg.set_username(username: str) -> Any
  • Usernames are 5–32 characters: a–z, 0–9 and underscores.
  • A taken name gives USERNAME_OCCUPIED, a bad format USERNAME_INVALID; both surface as ApiError.

Changes first name, last name and bio (about); fields you omit stay unchanged (account.updateProfile).

await tg.update_profile(
    *,
    first_name: Optional[str] = None,
    last_name: Optional[str] = None,
    about: Optional[str] = None,
) -> Any
  • Bio length is limited, with separate limits for regular and Premium accounts (about_length_limit_* in the client config).

Dialogs & messages

Chat list, history, sending, editing, deleting, forwarding, pinning, reactions, polls and scheduled messages.

actionarchivedelete_dialogdelete_messagesdialogsedit_messageforward_messagesmark_readmessagemessagesmutepin_dialogpin_messagereactscheduledsend_messagesend_pollunmuteunpin_message

action

async

Shows a chat status such as "typing..." or "sending photo...". Values: typing, cancel, photo, video, record-video, audio, record-audio, document, location, contact, game.

await tg.action(entity: Union[int, str, Any], action: str = 'typing') -> Any
  • The status lasts 6 seconds; repeat the call or use async with tg.client.action(entity, "typing"): to keep it visible longer.
Example — python
await tg.action("@durov", "typing")

archive

async

Moves a dialog to the archive (archived=True) or back out of it (archived=False).

await tg.archive(entity: Union[int, str, Any], *, archived: bool = True) -> Any

Removes a dialog: leaves a channel or supergroup, leaves a basic group and clears its history, or deletes a private chat's history.

await tg.delete_dialog(entity: Union[int, str, Any], *, revoke: bool = False) -> Any
  • revoke=True deletes a private chat's history for the other person too; it has no effect on channels and supergroups.

Deletes messages by ID. revoke=True (default) deletes them for everyone; False only for you, in private chats and basic groups.

await tg.delete_messages(
    entity: Union[int, str, Any],
    message_ids: Iterable[int],
    *,
    revoke: bool = True,
) -> Any
  • In supergroups and channels messages are always deleted for everyone; deleting other people's messages needs the delete_messages admin right.
  • Service messages cannot be deleted (MESSAGE_DELETE_FORBIDDEN → PermissionError).
  • Deletion can also be time-limited (revoke_time_limit, revoke_pm_time_limit).
Example — python
await tg.delete_messages("me", [101, 102], revoke=True)

dialogs

async

Lists dialogs — private chats, groups and channels — by recent activity. Defaults to 50; archived=True returns only the archive, folder selects a folder ID.

await tg.dialogs(
    *,
    limit: int = 50,
    archived: Optional[bool] = None,
    folder: Optional[int] = None,
) -> list
  • limit=None fetches everything, which on a large account means many requests and flood-wait risk — fetch only what you need.
  • The archive folder ID is 1; all other chats are in 0.
Example — python
dialogs = await tg.dialogs(limit=50)

Edits the text, media or buttons of a sent message. Normally only your own messages; channel posts need the edit_messages admin right.

await tg.edit_message(
    entity: Union[int, str, Any],
    message_id: int,
    text: Optional[str] = None,
    *,
    file: Optional[Any] = None,
    parse_mode: Optional[str] = 'md',
    link_preview: bool = True,
    buttons: Optional[Any] = None,
) -> Any
  • Editing is time-limited: old messages give MESSAGE_EDIT_TIME_EXPIRED (the threshold is edit_time_limit in the client config).
  • If nothing changed, Telegram returns MESSAGE_NOT_MODIFIED.
Example — python
await tg.edit_message("me", message_id, "Tahrirlangan matn")

Forwards messages from from_entity to to_entity (argument order: destination, IDs, source). drop_author=True hides the original author; schedule delays delivery.

await tg.forward_messages(
    to_entity: Union[int, str, Any],
    message_ids: Iterable[int],
    from_entity: Union[int, str, Any],
    *,
    silent: bool = False,
    drop_author: bool = False,
    schedule: Optional[datetime.datetime] = None,
) -> Any
  • Messages from a protected chat cannot be forwarded — CHAT_FORWARDS_RESTRICTED.
  • The number of messages per call is limited (forwarded_count_max).
Example — python
await tg.forward_messages("me", [42], "@kanal", drop_author=True)

Marks a dialog as read; with message, up to that message.

await tg.mark_read(
    entity: Union[int, str, Any],
    *,
    message: Optional[Any] = None,
) -> Any
Example — python
await tg.mark_read("@guruh")

message

async

Fetches a single message by ID; returns None instead of raising when it does not exist.

await tg.message(entity: Union[int, str, Any], message_id: int) -> Any
Example — python
msg = await tg.message("@kanal", 42)
Example — python
msg = await tg.message("@kanal", 42)
data = await tg.download(msg)

Reads chat history, which the Bot API has no method for. Newest first; narrow with search, from_user, filter, min_id/max_id, or fetch exact messages with ids.

await tg.messages(
    entity: Union[int, str, Any],
    *,
    limit: int = 50,
    offset_id: int = 0,
    min_id: int = 0,
    max_id: int = 0,
    search: Optional[str] = None,
    from_user: Union[int, str, Any, NoneType] = None,
    reverse: bool = False,
    ids: Union[int, Sequence[int], NoneType] = None,
    filter: Optional[Any] = None,
) -> list
  • Pagination: for the next page pass the smallest message.id of the previous page as offset_id; reverse=True goes oldest to newest.
  • With ids the list length is preserved — messages that are not found come back as None.
Example — python
history = await tg.messages("@durov", limit=50)

mute

async

Mutes a dialog's notifications. until is a unix timestamp in seconds; without it the mute is effectively permanent.

await tg.mute(
    entity: Union[int, str, Any],
    *,
    until: Union[int, datetime.datetime, NoneType] = None,
) -> Any
  • until=0 is also treated as permanent — use unmute() to turn notifications back on.

Pins a dialog to the top of the chat list, or unpins it with pinned=False.

await tg.pin_dialog(entity: Union[int, str, Any], *, pinned: bool = True) -> Any
  • The number of pinned dialogs is limited (dialogs_pinned_limit_default for non-Premium accounts).

Pins a message in a chat, silently by default (notify=False). pm_oneside=True pins it only on your side of a private chat.

await tg.pin_message(
    entity: Union[int, str, Any],
    message_id: int,
    *,
    notify: bool = False,
    pm_oneside: bool = False,
) -> Any
  • Groups and channels require the pin right, otherwise CHAT_ADMIN_REQUIRED or PIN_RESTRICTED.
Example — python
await tg.pin_message("me", 42, notify=False)

react

async

Adds an emoji reaction to a message; emoji=None removes it and big=True plays the larger animation.

await tg.react(
    entity: Union[int, str, Any],
    message_id: int,
    emoji: Optional[str] = None,
    *,
    big: bool = False,
) -> Any
  • Admins can restrict which reactions are allowed (available_reactions in chat_full()); a disallowed emoji gives REACTION_INVALID.
Example — python
await tg.react("@guruh", 42, "👍")

Scheduled messages in a chat that have not been sent yet — those queued with send_message(..., schedule=...) or send_file(..., schedule=...).

await tg.scheduled(entity: Union[int, str, Any]) -> Any
Example — python
scheduled = await tg.scheduled("me")

Sends a message to a private chat, group or channel; entity is an @username, numeric ID, t.me/... link or "me" (Saved Messages). Supports replies, files, buttons, silent delivery and comments on channel posts (comment_to).

await tg.send_message(
    entity: Union[int, str, Any],
    message: str = '',
    *,
    reply_to: Optional[int] = None,
    parse_mode: Optional[str] = 'md',
    link_preview: bool = True,
    file: Optional[Any] = None,
    silent: bool = False,
    schedule: Optional[datetime.datetime] = None,
    buttons: Optional[Any] = None,
    formatting_entities: Optional[list] = None,
    comment_to: Optional[int] = None,
) -> Any
  • schedule=datetime queues the message on Telegram's servers and Telegram sends it at that time — your app does not need to be running.
  • The default parse_mode="md" turns **, __, ~~ or [text](url) in user-supplied text into formatting. Use parse_mode=None for raw text.
  • Unsolicited bulk messages are spam, and accounts that use the Telegram API for spamming are banned permanently.
Example — python
await tg.send_message("@mening_guruhim", "Salom!", silent=True)

Sends a poll or a quiz (quiz=True): options are the answers, multiple allows several choices, public shows who voted for what.

await tg.send_poll(
    entity: Union[int, str, Any],
    question: str,
    options: Sequence[str],
    *,
    multiple: bool = False,
    quiz: bool = False,
    correct: Optional[int] = None,
    public: bool = False,
) -> Any
  • A quiz requires correct (zero-based index of the right answer); without it the SDK raises ConfigurationError before sending anything.
Example — python
await tg.send_poll("@guruh", "Qaysi kun?", ["Dushanba", "Juma"], multiple=False)

unmute

async

Turns a dialog's notifications back on.

await tg.unmute(entity: Union[int, str, Any]) -> Any

Unpins a message; without message_id it unpins every pinned message in the chat.

await tg.unpin_message(
    entity: Union[int, str, Any],
    message_id: Optional[int] = None,
) -> Any
Example — python
await tg.unpin_message("me", 42)

Media & files

Send photos, videos, documents and albums; download media and pre-upload files.

downloadsend_albumsend_fileupload

Downloads a message's media: returns bytes by default, or writes to disk and returns the path when file is a path.

await tg.download(message: Any, *, file: Any = <class 'bytes'>) -> Any
Example — python
msg = await tg.message("@kanal", 42)
data = await tg.download(msg)

Sends several files as one album (media group); accepts caption and the other send_file() parameters.

await tg.send_album(
    entity: Union[int, str, Any],
    files: Sequence[Any],
    *,
    caption: Optional[str] = None,
    **kwargs: Any,
) -> Any
  • Telegram allows up to 10 media per album; with more files Telethon splits them into several albums of 10.

Sends a photo, video, document, voice message or round video note; file is a path, bytes, file object, URL or an upload() result. Supports caption, reply_to, silent and schedule.

await tg.send_file(
    entity: Union[int, str, Any],
    file: Any,
    *,
    caption: Optional[str] = None,
    force_document: bool = False,
    voice_note: bool = False,
    video_note: bool = False,
    silent: bool = False,
    reply_to: Optional[int] = None,
    thumb: Optional[Any] = None,
    attributes: Optional[list] = None,
    schedule: Optional[datetime.datetime] = None,
    parse_mode: Optional[str] = 'md',
) -> Any
  • Use force_document=True to deliver the file as-is, as a document.
  • voice_note=True sends a voice message; video_note=True sends a round video note.
Example — python
await tg.send_file("me", "photo.jpg", caption="Rasm")

upload

async

Pre-uploads a file to Telegram and returns a handle you can pass to send_file() later (filename sets the visible file name).

await tg.upload(file: Any, *, filename: Optional[str] = None) -> Any
  • Uploaded parts are only kept temporarily, from minutes to a few hours, so use the result promptly.

Stories

Posting, reading, editing and deleting stories. Posting as a user requires Telegram Premium.

can_send_storydelete_storyedit_storysend_storystoriesstory_targets

Checks whether a story can be posted, before posting it (stories.canSendStory). On success it returns the number of free story slots (count); Telegram's documentation requires this call before sending a story.

await tg.can_send_story(entity: Union[int, str, Any] = 'me') -> Any
  • entity="me" checks your own account; pass a channel or supergroup to check posting as that peer.
  • Errors in SDK terms: PREMIUM_ACCOUNT_REQUIRED — the user has no Premium; CHAT_ADMIN_REQUIRED — no post_stories right in the channel (PermissionError); BOOSTS_REQUIRED — the channel lacks boosts; STORIES_TOO_MUCH — the active-story limit is reached.
  • Weekly and monthly limits (STORY_SEND_FLOOD_WEEKLY / STORY_SEND_FLOOD_MONTHLY) arrive as RateLimitError, with the wait in retry_after.
  • It is not a guarantee: if the state changes between the check and send_story() — a story posted from another device, say — the same errors come back at posting time.
Example — python
check = await tg.can_send_story("me")

Deletes one story or a list of them (stories.deleteStories) and returns the IDs that were actually deleted.

await tg.delete_story(
    entity: Union[int, str, Any],
    story_id: Union[int, Iterable[int]],
) -> Any
  • Active, profile-pinned and archived stories are all removed; this cannot be undone.
  • A non-existent ID is not an error — it simply does not appear in the returned list.
Example — python
await tg.delete_story("me", [42, 43])

Edits a published story (stories.editStory): only the fields you pass are sent, everything else stays as it was. Use it to replace the caption or tighten privacy.

await tg.edit_story(
    entity: Union[int, str, Any],
    story_id: int,
    *,
    file: Optional[Any] = None,
    caption: Optional[str] = None,
    privacy: Union[str, Sequence[Any], NoneType] = None,
    allow: Optional[Sequence[Union[int, str, Any]]] = None,
    deny: Optional[Sequence[Union[int, str, Any]]] = None,
    photo: Optional[bool] = None,
    thumb: Optional[Any] = None,
    parse_mode: Optional[str] = None,
    entities: Optional[list] = None,
    media_areas: Optional[list] = None,
) -> Any
  • privacy defaults to None here (unlike send_story, where privacy is mandatory and defaults to "everyone"): leave it out and the story keeps its current audience.
  • Passing no fields at all raises ConfigurationError — an empty edit is a meaningless request for Telegram.
  • With file the media is re-uploaded entirely (same 30 MB limit): per Telegram's docs the file attributes are welded to the media, so there is no other way to change them.
Example — python
await tg.edit_story("me", 42, caption="Tahrirlangan matn")

Posts a story (stories.sendStory): entity is the author ("me" or a channel/supergroup) and file is a vertical photo or video. The response is an Updates object carrying the new story id (updateStoryID).

await tg.send_story(
    entity: Union[int, str, Any],
    file: Any,
    *,
    caption: Optional[str] = None,
    period: Union[int, datetime.timedelta, NoneType] = None,
    privacy: Union[str, Sequence[Any], NoneType] = 'everyone',
    allow: Optional[Sequence[Union[int, str, Any]]] = None,
    deny: Optional[Sequence[Union[int, str, Any]]] = None,
    pinned: bool = False,
    noforwards: bool = False,
    photo: Optional[bool] = None,
    thumb: Optional[Any] = None,
    parse_mode: Optional[str] = None,
    entities: Optional[list] = None,
    media_areas: Optional[list] = None,
    albums: Optional[Sequence[int]] = None,
) -> Any
  • Telegram's rules: posting as a user requires **Telegram Premium** on the account (otherwise PREMIUM_ACCOUNT_REQUIRED); posting as a channel requires the post_stories admin right and enough boosts. Call can_send_story(entity) first so the error appears before the file is uploaded, not after.
  • file is a path, bytes, a file object or a prepared InputFile, at most 30 MB — the limit is checked locally. The type comes from the extension (.jpg/.png means photo, anything else video); force it with photo=True/False.
  • period is how many seconds until the story is archived, and only four values are accepted: 21600 (6 h), 43200 (12 h), 86400 (24 h) and 172800 (48 h); a timedelta works too. Without Premium only 86400 is allowed — Telegram rejects the rest. If omitted, the field is not sent and Telegram applies 24 hours.
  • privacy: "everyone" (default), "contacts", "close_friends" (the list is managed in the Telegram app) or "selected", which requires allow. deny is the exception list and is appended after the other rules ("contacts, except this person").
  • pinned=True keeps the story on the profile after it expires; noforwards=True blocks forwarding and saving.
  • The caption length limit comes from Telegram's config and is not documented as a number, so the SDK does not check it. Without parse_mode the text is sent unformatted: story formatting depends on account configuration and is not available everywhere.
  • Telegram does not document aspect ratio or duration as numbers, so the SDK does not validate them — non-vertical media is cropped badly in the apps.
Example — python
await tg.send_story("me", "story.mp4", caption="Salom!", period=86400,
                    privacy="contacts", pinned=False)

stories

async

Returns a peer's currently active stories (stories.getPeerStories): a stories.PeerStories object holding StoryItem entries. With ids=[...] it fetches exactly those stories instead (stories.getStoriesByID).

await tg.stories(
    entity: Union[int, str, Any] = 'me',
    *,
    ids: Union[int, Iterable[int], NoneType] = None,
) -> Any
  • Some entries can arrive as StoryItemSkipped — Telegram saves bandwidth and omits the full data; request those individually with stories(entity, ids=[...]).
  • Expired stories are not here: they live in the archive (stories.getStoriesArchive) or among the profile's pinned ones (stories.getPinnedStories) — reach those through raw().
Example — python
items = await tg.stories("me")

Returns the channels and supergroups you can post stories as (stories.getChatsToSend). Useful for a "post as" picker in your interface.

await tg.story_targets() -> Any
  • Being on the list does not mean posting will succeed: boosts and limits are checked by can_send_story(entity), so call it anyway.
Example — python
targets = await tg.story_targets()

Contacts, users & blocking

Contacts, blocking, user profiles and resolving usernames or IDs to Telegram objects.

add_contactblockblockedcommon_chatscontactsdelete_contactentityresolveunblockuser_full

Adds a contact by phone number (contacts.importContacts). If the number is on Telegram, the user comes back in imported and users.

await tg.add_contact(phone: str, first_name: str, *, last_name: str = '') -> Any
  • No exception is raised when the number is not found — imported is simply empty, so check the result.
  • retry_contacts lists contacts not imported due to a system limit; retry them later.
Example — python
await tg.add_contact("+998901234567", "Ali", last_name="Valiyev")

block

async

Blocks a user (contacts.block); undo with unblock().

await tg.block(user: Union[int, str, Any]) -> Any
Example — python
await tg.block("@spam_bot")
await tg.unblock("@spam_bot")

blocked

async

Lists blocked users, up to 100 by default.

await tg.blocked(*, limit: int = 100) -> Any
Example — python
blocked = await tg.blocked(limit=100)

Groups and channels you share with the given user, up to 100 by default.

await tg.common_chats(user: Union[int, str, Any], *, limit: int = 100) -> Any
Example — python
chats = await tg.common_chats("@foydalanuvchi")

The account's contact list (contacts.getContacts): contact entries plus their users objects.

await tg.contacts() -> Any
Example — python
contacts = await tg.contacts()

Removes a user from your contacts.

await tg.delete_contact(user: Union[int, str, Any]) -> Any
Example — python
await tg.delete_contact("@foydalanuvchi")

entity

async

Resolves an @username, numeric ID, t.me/... link or phone number to a Telegram object (User, Chat, Channel). Other methods use it internally.

await tg.entity(entity: Union[int, str, Any]) -> Any
  • Numeric IDs only work for objects already in the session's in-memory cache (e.g. after dialogs() or participants()); the session string does not persist that cache. Not found raises NotFoundError.

resolve

async

Looks up an @username directly on Telegram (contacts.resolveUsername), with or without the @. The response has peer, users and chats.

await tg.resolve(username: str) -> Any
  • Unlike the cache-aware entity(), every call hits the server, so prefer entity() for repeated lookups.

unblock

async

Unblocks a user.

await tg.unblock(user: Union[int, str, Any]) -> Any
Example — python
await tg.block("@spam_bot")
await tg.unblock("@spam_bot")

Full user info (users.getFullUser): bio, number of common chats and other profile fields.

await tg.user_full(user: Union[int, str, Any]) -> Any
Example — python
user = await tg.user_full("@durov")

Groups & channels

Create, join, leave, delete; title, description, photo, slow mode and default permissions.

chat_fullcreate_channelcreate_groupdelete_chatjoinleaveset_aboutset_default_permissionsset_photoset_slowmodeset_title

Full group or channel info: description, member count, invite link, linked discussion group, pending join requests. Uses channels.getFullChannel for supergroups/channels and messages.getFullChat for basic groups.

await tg.chat_full(entity: Union[int, str, Any]) -> Any
  • Useful flags inside full_chat: can_view_stats (statistics available), can_view_participants (member list visible to you), slowmode_seconds (current slow mode).
Example — python
info = await tg.chat_full("@kanal")

Creates a channel (broadcast=True, default) or a supergroup (broadcast=False); about is the description.

await tg.create_channel(title: str, *, about: str = '', broadcast: bool = True) -> Any
  • The new channel has no public username, so it starts out private.
Example — python
channel = await tg.create_channel("Yangiliklar", about="Kompaniya yangiliklari")

Creates a group: megagroup=True (default) makes a supergroup, megagroup=False a basic group with users.

await tg.create_group(
    title: str,
    users: Sequence[Union[int, str, Any]],
    *,
    megagroup: bool = True,
    about: str = '',
) -> Any
  • With megagroup=True the users are not added — invite them afterwards with invite(). about is ignored for basic groups.
  • Basic groups hold up to 200 members, supergroups up to 200,000.
Example — python
group = await tg.create_group("Playground guruhi", ["@do'stim"], megagroup=True)

Permanently deletes a group or channel for everyone; members and history cannot be restored. Requires creator rights, otherwise PermissionError.

await tg.delete_chat(entity: Union[int, str, Any]) -> Any
  • Channels and supergroups with more than 1,000 members cannot be deleted through the API — CHANNEL_TOO_LARGE.
Example — python
await tg.delete_chat("@mening_kanalim")

join

async

Joins a group or channel from a public @username or a t.me/+... / t.me/joinchat/... invite link — the SDK picks the right TL request.

await tg.join(entity: Union[str, int, Any]) -> Any
  • If the link requires admin approval, Telegram returns INVITE_REQUEST_SENT, meaning the request was submitted (an ApiError in the SDK).
  • An account can only be in a limited number of channels and supergroups; beyond that you get CHANNELS_TOO_MUCH.
Example — python
await tg.join("@kanal")

leave

async

Leaves a group or channel; for basic groups your copy of the history is cleared too.

await tg.leave(entity: Union[int, str, Any]) -> Any
Example — python
await tg.leave("@kanal")

Changes a group or channel description (about).

await tg.set_about(entity: Union[int, str, Any], about: str) -> Any
  • Length is limited: too long gives CHAT_ABOUT_TOO_LONG, unchanged text gives CHAT_ABOUT_NOT_MODIFIED.

Sets default permissions for every member (e.g. send_messages=False to stop everyone posting). As in restrict(), False means forbidden.

await tg.set_default_permissions(entity: Union[int, str, Any], **rights: bool) -> Any
  • view_messages cannot be used here; it only applies to banning an individual member.
  • Telethon only supports this for supergroups and channels; on a basic group the SDK raises NotFoundError.

Uploads and sets a group or channel photo from a path, bytes or a file object.

await tg.set_photo(entity: Union[int, str, Any], file: Any) -> Any
Example — python
await tg.set_photo("@guruh", "logo.png")

Enables slow mode in a supergroup: each member can send one message every seconds seconds; 0 turns it off.

await tg.set_slowmode(entity: Union[int, str, Any], seconds: int = 0) -> Any
  • Supergroups only. A duration Telegram does not accept returns SECONDS_INVALID.
Example — python
await tg.set_title("@guruh", "Yangi nom")
await tg.set_slowmode("@guruh", 30)

Renames a group or channel; requires the change_info right.

await tg.set_title(entity: Union[int, str, Any], title: str) -> Any
Example — python
await tg.set_title("@guruh", "Yangi nom")
await tg.set_slowmode("@guruh", 30)

Members & moderation

Member lists, inviting, kicking, banning, restricting and admin rights.

adminsbanbanneddemoteinvitekickmute_memberparticipantspermissionspromoterestrictunban

admins

async

Only the admins, with no limit; each user's participant attribute holds their role and rights.

await tg.admins(entity: Union[int, str, Any]) -> list
Example — python
admins = await tg.admins("@guruh")

ban

async

Removes a member and prevents them from rejoining. until (datetime) sets a temporary ban; without it the ban is permanent.

await tg.ban(
    entity: Union[int, str, Any],
    user: Union[int, str, Any],
    *,
    until: Optional[datetime.datetime] = None,
) -> Any
  • Telegram treats durations over 366 days or under 30 seconds as permanent.
  • Works in supergroups and channels (needs ban_users); in basic groups use kick().
Example — python
await tg.ban("@guruh", "@foydalanuvchi")

banned

async

Banned (kicked) members, up to 100 by default.

await tg.banned(entity: Union[int, str, Any]) -> list
  • For members who are only restricted: participants(entity, filter=tg.tl().types.ChannelParticipantsBanned(q="")).
Example — python
banned = await tg.banned("@guruh")

demote

async

Removes admin rights and returns the user to a regular member.

await tg.demote(entity: Union[int, str, Any], user: Union[int, str, Any]) -> Any
Example — python
await tg.demote("@guruh", "@foydalanuvchi")

invite

async

Adds users to a group or channel: one request for supergroups and channels, one per user for basic groups.

await tg.invite(
    entity: Union[int, str, Any],
    users: Sequence[Union[int, str, Any]],
) -> Any
  • If a user's privacy settings forbid it you get USER_PRIVACY_RESTRICTED (PermissionError); send them an invite link instead.
  • missing_invitees in a supergroup/channel response lists users who could not be added.
  • Mass-adding strangers is spam, and accounts that use the Telegram API for spamming are banned permanently.
Example — python
await tg.invite("@guruh", ["@foydalanuvchi"])

kick

async

Removes a member without banning them, so they can rejoin via a link. Use ban() to block them.

await tg.kick(entity: Union[int, str, Any], user: Union[int, str, Any]) -> Any
  • In supergroups and channels Telethon does this as a ban followed immediately by an unban.
Example — python
await tg.kick("@guruh", "@foydalanuvchi")

Stops a member from sending messages — shorthand for restrict(send_messages=False); add until for a time limit.

await tg.mute_member(
    entity: Union[int, str, Any],
    user: Union[int, str, Any],
    *,
    until: Optional[datetime.datetime] = None,
) -> Any

Lists members of a group or channel, which the Bot API cannot do. search matches names or usernames, filter selects admins, bots, banned users and so on, limit=None fetches all.

await tg.participants(
    entity: Union[int, str, Any],
    *,
    limit: Optional[int] = 100,
    search: Optional[str] = None,
    aggressive: bool = False,
    filter: Optional[Any] = None,
) -> list
  • Channel subscriber lists need admin rights (CHAT_ADMIN_REQUIRED → PermissionError); supergroups may hide the list — check can_view_participants in chat_full().
  • The aggressive flag does nothing in current Telethon versions and is kept only for backward compatibility.
  • Messaging people from the list unsolicited or mass-adding them to other chats counts as spam and gets accounts banned.
Example — python
members = await tg.participants("@guruh", limit=200)

One member's status and rights in a chat: creator, admin, restricted, and what they may do (Telethon ParticipantPermissions).

await tg.permissions(entity: Union[int, str, Any], user: Union[int, str, Any]) -> Any
Example — python
rights = await tg.permissions("@guruh", "@foydalanuvchi")

promote

async

Makes a member an admin; each right is its own flag (delete_messages, ban_users, pin_messages ...) and title sets the custom title. add_admins defaults to False, so the new admin cannot appoint others.

await tg.promote(
    entity: Union[int, str, Any],
    user: Union[int, str, Any],
    *,
    title: Optional[str] = None,
    change_info: bool = True,
    post_messages: bool = True,
    edit_messages: bool = True,
    delete_messages: bool = True,
    ban_users: bool = True,
    invite_users: bool = True,
    pin_messages: bool = True,
    add_admins: bool = False,
    manage_call: bool = True,
    anonymous: bool = False,
) -> Any
  • Basic groups have no granular rights — the user simply becomes an admin.
  • anonymous=True hides the admin from the member list and stops them posting as their own account.
Example — python
await tg.promote("@guruh", "@foydalanuvchi", title="Moderator", ban_users=True)

Restricts individual rights of a member: messages, media, stickers, GIFs, links, polls and more. Note: False forbids, True allows; until sets a duration.

await tg.restrict(
    entity: Union[int, str, Any],
    user: Union[int, str, Any],
    *,
    until: Optional[datetime.datetime] = None,
    send_messages: bool = True,
    send_media: bool = True,
    send_stickers: bool = True,
    send_gifs: bool = True,
    send_games: bool = True,
    send_inline: bool = True,
    embed_links: bool = True,
    send_polls: bool = True,
    change_info: bool = True,
    invite_users: bool = True,
    pin_messages: bool = True,
    embed_link_previews: bool = True,
) -> Any
  • Supergroups only: basic groups do not support per-member restrictions (the SDK raises NotFoundError).
  • Omitted flags default to True, so each call rewrites the full set of rights and earlier restrictions are not kept.
Example — python
await tg.restrict("@guruh", "@foydalanuvchi", send_messages=False)

unban

async

Lifts a ban and restrictions. The user is not re-added automatically; they must rejoin or be invited again.

await tg.unban(entity: Union[int, str, Any], user: Union[int, str, Any]) -> Any
Example — python
await tg.unban("@guruh", "@foydalanuvchi")

Invite links & join requests

Create and revoke invite links, list and approve join requests.

approve_join_requestcreate_invite_linkinvite_linkjoin_requestsrevoke_invite_link

Approves (approved=True) or dismisses (approved=False) a join request.

await tg.approve_join_request(
    entity: Union[int, str, Any],
    user: Union[int, str, Any],
    *,
    approved: bool = True,
) -> Any
Example — python
await tg.approve_join_request("@guruh", 123456789, approved=True)

Pending join requests awaiting admin approval (messages.getChatInviteImporters), up to 50 by default; the response has importers and users.

await tg.join_requests(entity: Union[int, str, Any], *, limit: int = 50) -> Any
Example — python
requests = await tg.join_requests("@guruh")

Low level: raw TL requests

Call any MTProto method through Telethon when the SDK has no wrapper for it.

rawtl

raw

async

Sends any Telethon TL request (functions.*Request) and maps errors into the SDK hierarchy (RateLimitError, AuthError, PermissionError, NotFoundError). Use it for features the SDK does not wrap.

await tg.raw(request: Any) -> Any
  • Request fields accept an @username or ID; Telethon converts them to the required Input* type.
  • Parameter names match the TL schema. Unlike tg.client(...), errors arrive as SDK exceptions rather than Telethon ones.
Example — python
from telethon import functions

config = await tg.raw(functions.help.GetConfigRequest())

tl

staticmethod

Returns the telethon.tl module: tg.tl().functions for requests and tg.tl().types for types such as filters and rights. Pairs with raw() and filter= arguments.

TelegramAccount.tl()
  • A static method that works without a connection, but telethon must be installed.

Frequently asked questions

What is the difference between a Telegram bot and TelegramAccount (userbot)?

A bot uses the Bot API with a BotFather token: it cannot start a conversation with a user, and the Bot API has no method for chat history or a full member list. TelegramAccount speaks MTProto as a regular user, so it can read history, list members, join groups and create channels. Use a bot for a service many people talk to, and TelegramAccount to automate your own account and the groups you run.

How do I get a Telegram api_id and api_hash?

Log in to my.telegram.org with your phone number and fill in the application form under API development tools; you receive an api_id (integer) and api_hash (string). Each phone number can currently have only one api_id. In the SDK, TelegramAccount.from_env() reads them from TELEGRAM_API_ID and TELEGRAM_API_HASH.

How should I store a Telethon session string securely?

The string returned by sign_in() or export_session() contains the authorization key: whoever has it can use the account without a code or password. Store it encrypted and keep it out of logs and error messages. If it leaks, call log_out() or terminate it with reset_session() from another session.

What should I do about FLOOD_WAIT errors?

FLOOD_WAIT_X means Telegram requires you to wait X seconds. Telethon sleeps through waits of up to 60 seconds by itself (the call just takes longer); longer waits surface as RateLimitError with retry_after, and you decide what to do. Accounts that use the Telegram API for flooding, spamming or faking subscriber and view counts are banned permanently.

Can I post a Telegram story from Python?

Yes, but only as a user account: send_story() calls MTProto's stories.sendStory, while the Bot API cannot post stories at all. Telegram's rules: posting as a user needs Premium, posting as a channel needs the post_stories right and enough boosts. A story lasts 6, 12, 24 or 48 hours (only 24 without Premium), and the media must be vertical and at most 30 MB. Check with can_send_story() before posting.

How do I get all members of a Telegram group in Python?

await tg.participants("@group", limit=None) returns a list of Telethon User objects; narrow it with search or filter. Listing a channel's subscribers requires admin rights (otherwise PermissionError), and supergroup admins may have hidden the member list. Check can_view_participants in the chat_full() result first.

Sources

  1. Telegram: Obtaining api_id
  2. Telegram: User authorization
  3. Telegram: Error handling (FLOOD_WAIT)
  4. Telegram: Admin, banned and default rights
  5. Telegram: Channel statistics
  6. Telegram: Stories
  7. Telegram Bot API

Related pages