Signing in

Most of Telegram’s API methods are gated behind an account login. But before you can interact with the API at all, you will need to obtain an API ID and hash pair for your application.

Registering your Telegram application

Before working with Telegram’s API, you (as the application developer) need to get an API ID and hash:

  1. Login to your Telegram account with the phone number of the developer account to use.

  2. Click under API Development tools.

  3. A Create new application window will appear. Fill in your application details. There is no need to enter any URL, and only the first two fields (App title and Short name) can currently be changed later.

  4. Click on Create application at the end. Remember that your API hash is secret and Telegram won’t let you revoke it. Don’t post it anywhere!

This API ID and hash can now be used to develop an application using Telegram’s API. Telethon consumes this API ID and hash in order to make the requests to Telegram.

It is important to note that this API ID and hash is attached to a developer account, and can be used to develop applications or otherwise using libraries such as Telethon.

The users of the application you develop do not need to provide their own API ID and hash. The API ID and hash values are meant to be hardcoded in the application. Any user is then able to login with just their phone number or bot token, even if they have not registered an application themselves.

Important

The API ID and hash are meant to be secret, but Python is often distributed in source-code form. These two things conflict with eachother! You can opt to obfuscate the values somehow, or perhaps distribute an executable binary file instead. Depending on what you are developing, it might be reasonable to expect users to provide their own API ID and hash instead.

Official applications also must embed the API ID and hash, but these are often distributed as binary files. Whatever you do, do not use other people’s API ID and hash! Telegram may detect this as suspicious and ban the accounts.

If you receive an error, Telegram is likely blocking the registration of a new applications. The best you can do is wait and try again later. If the issue persists, you may try contacting them, using a proxy or using a VPN. Be aware that some phone numbers are not eligible to register applications with.

Interactive login

The library offers a method for “quick and dirty” scripts known as interactive_login(). This method will first check whether the account was previously logged-in, and if not, ask for a phone number to be input.

You can write the code in a file (such as hello.py) and then run it, or use the built-in asyncio-enabled REPL. For this tutorial, we’ll be using the asyncio REPL:

python -m asyncio

Important

If you opt to write your code in a file, do not call your script telethon.py! Python will try to import from there and it will fail with an error such as “ImportError: cannot import name …”.

The first thing we need to do is import the Client class and create an instance of it:

from telethon import Client

client = Client('name', 12345, '0123456789abcdef0123456789abcdef')

The second and third parameters must be the API ID and hash, respectively. We have a client instance now, but we can’t send requests to Telegram until we connect! So the next step is to connect():

await client.connect()

If all went well, you will have connected to one of Telegram’s servers. If you run into issues, you might need to try a different hosting provider or use some sort of proxy.

Once you’re connected, we can begin the interactive_login():

await client.interactive_login()

Do as the prompts say on the terminal, and you will have successfully logged-in!

Once you’re done, make sure to disconnect() for a graceful shutdown.

To summarize:

from telethon import Client
client = Client('name', 12345, '0123456789abcdef0123456789abcdef')
await client.connect()
await client.interactive_login()

If you want to automatically login as a bot when needed, you can do so without any prompts, too:

from telethon import Client
client = Client('name', 12345, '0123456789abcdef0123456789abcdef')
await client.connect()
await client.interactive_login('54321:hJrIQtVBab0M2Yqg4HL1K-EubfY_v2fEVR')

Note

The bot token obtained from @BotFather looks something like this:

54321:hJrIQtVBab0M2Yqg4HL1K-EubfY_v2fEVR

This is not the API ID and hash separated by a colon! All of it is the bot token. Using a bot with Telethon still requires a separate API ID and hash.

See HTTP Bot API vs MTProto for more details.

Manual login

Tip

You can safely skip to Next steps if you’ve already completed the Interactive login. This section is only of interest if you want more control over how to manually login.

We’ve talked about the second and third parameters of the Client constructor, but not the first:

client = Client('name', 12345, '0123456789abcdef0123456789abcdef')

The first parameter is the “session”. When using a string or a Path, the library will create a SQLite database in that path. The session path can contain directory separators and live anywhere in the file system. Telethon will automatically append the .session extension if you don’t provide any.

Briefly, the session contains some of the information needed to connect to Telegram. This includes the data center belonging to the account logged-in, and the authorization key used for encryption, among other things.

Important

Do not leak the session file! Anyone with that file can login to the account stored in it. If you believe someone else has obtained this file, immediately revoke all active sessions from an official client.

Let’s take a look at what interactive_login() does under the hood.

  1. First, it’s using an equivalent of is_authorized() to check whether the session was logged-in previously.

  2. Then, it will either bot_sign_in() with a bot token or request_login_code() with a phone number.

    • If it logged-in as a bot account, a User is returned and we’re done.

    • Otherwise, a login code was sent. Go to step 3.

  3. Attempt to complete the user sign-in with sign_in(), by entering the login code.

    • If a User is returned, we’re done.

    • Otherwise, a 2FA password is required. Go to step 4.

  4. Use Client.check_password() to check that the password is correct.

    • If the password is correct, User is returned and we’re done.

Put into code, a user can thus login as follows:

from telethon import Client
from telethon.types import User

# SESSION, API_ID, API_HASH should be previously defined in your code
async with Client(SESSION, API_ID, API_HASH) as client:
    if not await client.is_authorized():
        phone = input('phone: ')
        login_token = await client.request_login_code(phone_or_token)

        code = input('code: ')
        user_or_token = await client.sign_in(login_token, code)

        if isinstance(user_or_token, User):
            return user_or_token

        # user_or_token is PasswordToken
        password_token = user_or_token

        import getpass
        password = getpass.getpass("password: ")
        user = await client.check_password(password_token, password)

    ...  # can now use the client and user

A bot account does not need to request login code and cannot have passwords, so the login flow is much simpler:

from telethon import Client

# SESSION, API_ID, API_HASH should be previously defined in your code
async with Client(SESSION, API_ID, API_HASH) as client:
    if not await client.is_authorized():
        bot_token = input('token: ')
        bot_user = await client.bot_sign_in(bot_token)
        bot_user

    ...  # can now use the client and bot_user

To get a bot account, you need to talk with @BotFather.

You may have noticed the async with keywords. The Client can be used in a context-manager. This will automatically call Client.connect() and Client.disconnect() for you.

A good way to structure your code is as follows:

import asyncio
from telethon import Client

SESSION = ...
API_ID = ...
API_HASH = ...

async def main():
    async with Client(SESSION, API_ID, API_HASH) as client:
        ...  # use client to your heart's content

if __name__ == '__main__':
    asyncio.run(main())

This way, both the asyncio event loop and the Client will exit cleanly. Otherwise, you might run into errors such as tasks being destroyed while pending.

Note

Once a Client instance has been connected, you cannot change the asyncio event loop. Methods like asyncio.run() setup and tear-down a new event loop every time. If the loop changes, the client is likely to be “stuck” because its loop cannot advance.

If you want to learn how asyncio works under the hood or need an introduction, you can read my own blog post An Introduction to Asyncio.