Developer docs
English

Pabal API

Pabal API (MTProto)

For building clients that connect to the server the same way the app does: connection details, the server public key, the sign-in flow, updates and what's supported.

The Pabal app talks to the server over MTProto 2.0. Read this page when you're building a program that connects the same way โ€” another app, automation running on a user account, a research client. If you're building a bot, the simpler Bot API is enough.

Read Telegram's documentation alongside this page

Pabal follows Telegram's published protocol, so the detailed definitions of the protocol and methods are in the MTProto and API methods documentation. This page describes what's different when connecting to a Pabal server, and what's supported.

Connection details

ItemValue
Address122.34.175.215
Port8443 (TCP)
DCDCs 1โ€“5 all share the same address. You can connect to any DC; 2 is the usual choice
ProtocolMTProto 2.0, API layer 216
TransportsAbridged, Intermediate, Padded Intermediate, Full โ€” each also with obfuscation (obfuscated2)
Server public keyserver-key.pem ยท fingerprint 8724853375441383205
api_id ยท api_hashNot checked. Use any values

There's no HTTP transport, WebSocket transport or MTProxy yet. The client device's clock must be right โ€” MTProto message IDs are derived from the time, so if the clock is far off, the server drops the messages.

Server public key

When an MTProto client first connects, it encrypts the auth key exchange with the server's RSA public key. Telegram clients have Telegram's public key built in, so to connect to Pabal you have to put in this key instead (or as well). This key stops other servers from pretending to be the Pabal server.

-----BEGIN RSA PUBLIC KEY-----
MIIBCgKCAQEA4hH74xPQsUwr/pyXPdF4tVicYr6QbfeDrKC7mUOVrPLSL4FtmgGn
w+O4u6lVvOf3Udd1KY6+OL4fUZdMBlLzwsoGLoniiVR09dnvyXHE8LhQSS+i1LmI
oJbhQwXplLnUJf272fLXkD23e7ppKLkjYk+jeYObueCy5HYMSThklVeXEzbZVGZv
47o/mjU2vyFoRpa6wCIE4rpj1UIPtOMpekMI/TocIlGVJ+ch6cAVNxIDro53a1eG
/1oZRLQH4oViEGxeMMjBMY5gk5HPkZvjbqy4h8TjXEz7O5o0BRsSqG/OPtP/dRQV
X4ewPhj2WCU4e6l5X59ZKIcv4sQLOwClqQIDAQAB
-----END RSA PUBLIC KEY-----
curl -s -o server-key.pem https://pabal.me/docs/server-key.pem

This key is created once, when the server first starts, and never changes. Check that the Loaded RSA key โ€ฆ (fingerprint โ€ฆ) value in the server log matches the fingerprint above.

Connecting with Telethon

This example uses Python's Telethon to sign in to a user account and send and receive messages. Sign up in the app first to create the account (see below).

# pabal_client.py โ€” pip install telethon==1.42.0
# server-key.pem (the server public key downloaded above) in the same folder
import asyncio

from telethon import TelegramClient, events
from telethon.crypto import rsa

rsa.add_key(open("server-key.pem").read(), old=False)          # the Pabal server's public key

client = TelegramClient("pabal", api_id=1, api_hash="0" * 32)  # sign-in is saved in pabal.session
client.session.set_dc(2, "122.34.175.215", 8443)


@client.on(events.NewMessage(incoming=True))
async def show(event):
    sender = await event.get_sender()
    print(f"{sender.first_name}: {event.raw_text}")


async def main():
    await client.start(phone=lambda: input("Phone number (+8210โ€ฆ): "))   # enter the code once, the first time
    me = await client.get_me()
    print(f"Signed in: {me.first_name} (id {me.id})")
    await client.send_message("BotFather", "/help")
    await client.run_until_disconnected()


asyncio.run(main())
  • Use Telethon 1.42. It's the version that speaks layer 216. Newer versions try to read responses with a higher layer and fail with TypeNotFoundError.
  • Telethon blocks signing up new accounts (sign_up()). Sign up in the app, or call auth.signUp directly.
  • The sign-in is saved in the pabal.session file, so you won't be asked for a code again. This file is the key to the account, so keep it safe.

Sign-in flow

1 ยท Auth key (once) req_pq_multi โ†’ req_DH_params set_client_DH_params 2048-bit auth keyProtected by server key 2 ยท Sign-in (once per auth key) auth.sendCodePhone number sentCodeTypeSmsSMS or via the admin SetUpEmailRequiredEmail โ†’ asks for address account.sendVerifyEmailCodepurpose: loginSetup auth.signInphone_code or email code auth.authorizationSigned in authorizationSignUpRequiredNew number โ†’ auth.signUp(name) Code received
Create an auth key, then sign in with a code

About this diagram

  • Two stages: the top one creates the auth key used for encryption (the protocol), and the bottom one attaches an account to that key by signing in (the API). Libraries handle the top stage for you.
  • A sign-in is attached to the auth key: once a key is signed in, every session you open with it is signed in too. If you lose the key (by deleting the session file), you have to sign in again.
  • The server operator decides how codes are delivered: for SMS or delivery by an administrator you get sentCodeTypeSms; for email you get sentCodeTypeSetUpEmailRequired, and the client asks for an email address and calls account.sendVerifyEmailCode (the middle row).
  • The red dashed line is the path for a new number: if the code is right but there's no account, authorizationSignUpRequired comes back; call auth.signUp with a name and the sign-up is complete. Signing up is only possible after entering the right code.
  • Bots skip the bottom stage and sign in with a single auth.importBotAuthorization call (with the bot token).
ErrorWhen
PHONE_NUMBER_INVALIDThe number is wrong, or it's a new number while the server has closed new sign-ups
PHONE_NUMBER_BANNEDA number the operator has blocked
FLOOD_WAIT_n (420)Codes were requested too often. Try again after n seconds
PHONE_CODE_INVALIDThe code is wrong (after the set number of tries, it's locked)
PHONE_CODE_EXPIREDThe code has expired or is locked, or the phone_code_hash is unknown โ€” start again from sendCode
EMAIL_INVALID, EMAIL_NOT_ALLOWEDThe email address is invalid / the account already exists and this isn't its registered sign-in email
AUTH_KEY_UNREGISTERED (401)A method that needs sign-in was called with a key that isn't signed in
Test numbers

On a server where the operator has turned on test numbers, numbers of the form +99966XYYYY sign in with the code XXXXX (X five times), without any code actually being delivered. This is meant for development servers only, and it's off on production servers.

Receiving updates

  • Real time: while the connection is open, the server immediately sends new messages, edits and deletions as updateShortMessage and updates. The session that sent a request gets the result as the RPC response, so the same thing isn't pushed to it a second time.
  • pts: each user's changes get a sequence number (pts). If there's a gap in the pts a client receives, it has missed something.
  • Catching up: remember the current pts with updates.getState, and when you reconnect, call updates.getDifference(pts, date, qts) to get the new messages and deletions in between, along with the related users and groups. If the client's pts is ahead of the server's (for example, when the server's data has been reset), you get differenceTooLong; reload the chat list in that case.
  • Libraries such as Telethon take care of all this for you.

IDs and peers

WhatIDNotes
PeopleFrom 100001peerUser. @BotFather is 100000
BotsSame numbering as peopleuser.bot = true. The number at the front of the token is the bot ID
Basic groupsFrom 1000001peerChat. In the Bot API they appear as negative numbers (-chat_id)
MessagesFrom 1 in each message boxIn a one-to-one chat each participant has their own copy with their own number. The same message can have different numbers for the two people

Store access_hash exactly as the server gives it to you and use it from there (it comes along with username lookups, chat lists and updates).

Files

  • Uploading: upload parts with upload.saveFilePart and reference them with inputFileUploadedโ€ฆ. upload.saveBigFilePart for large files doesn't exist yet, so the practical limit is 10 MB.
  • Sending: messages.sendMedia with inputMediaUploadedPhoto (a new photo) or inputMediaPhoto (a photo already on the server). Other media give MEDIA_INVALID.
  • Downloading: upload.getFile with inputPhotoFileLocation (message photos) or inputPeerPhotoFileLocation (profile photos). Up to 1 MB at a time.
  • Profile photos: photos.uploadProfilePhoto, photos.updateProfilePhoto, photos.getUserPhotos, photos.deletePhotos.
  • Photos are stored in one size only, the original (no separate thumbnails are generated).

What's supported

The server has handlers for 408 layer 216 methods and can read requests for all of them, but the methods below are the ones verified end to end with real clients. The rest answer in the right format, but their contents may be empty or may not be recorded.

AreaVerified methods
ConnectioninitConnection, invokeWithLayer, help.getConfig, auth.bindTempAuthKey (PFS temporary keys), auth.exportAuthorization/importAuthorization
Sign-inauth.sendCode, auth.signIn, auth.signUp, auth.logOut, auth.importBotAuthorization, account.sendVerifyEmailCode
Users and contactsusers.getUsers, users.getFullUser, contacts.resolveUsername, contacts.importContacts, contacts.search
Messagesmessages.sendMessage, messages.sendMedia (photos), messages.getHistory, messages.getDialogs, messages.getMessages, messages.editMessage, messages.deleteMessages
Groupsmessages.createChat, messages.deleteChatUser, messages.editChatTitle (messages.addChatUser verified with the official app only)
Botsmessages.getBotCallbackAnswer, messages.setBotCallbackAnswer, messages with buttons (reply_markup)
Updatesupdates.getState, updates.getDifference, real-time push
Files and photosupload.saveFilePart, upload.getFile, photos.* (above)

We have also confirmed that the official Telegram Desktop 6.2.6 works without modification for signing up, signing in, chats, photos, groups and reconnecting. The roughly 60 methods the app calls at startup have their response formats checked separately.

Errors

Errors arrive as a standard rpc_error (error_code + error_message). error_message is always made of uppercase letters, digits and underscores (PEER_ID_INVALID), followed by : description when needed.

CodeMeaning
400Bad request โ€” PEER_ID_INVALID, MESSAGE_ID_INVALID, MEDIA_INVALID, USERNAME_NOT_OCCUPIED โ€ฆ
401Sign-in required โ€” AUTH_KEY_UNREGISTERED
403Not allowed โ€” for example, a group you're not a member of
420FLOOD_WAIT_n โ€” wait n seconds
500Internal server error
Transport error -404The server doesn't know this auth key โ€” create a new key and sign in again (permanent key) or bind again (temporary key)

Not available yet

  • Channels and supergroups (channels.* answers, but doesn't display properly in the app), secret chats, calls
  • Media other than photos, upload.saveBigFilePart, thumbnails
  • Two-step verification (SRP) โ€” it can't be set up, and actions that require two-step verification are refused
  • HTTP and WebSocket transports, MTProxy, sending msgs_ack, replacing bad_server_salt
  • Splitting across several servers โ€” a single server handles all of DCs 1โ€“5

Connecting the official Telegram app to Pabal

The Telegram app builds the server address and public key into itself at build time. So instead of changing a setting, you have to modify the source and rebuild it. That's how the Pabal app (Pabal.app) was made. If you're a server operator, see Server installation โ€” connecting the app.

ยฉ 2026 Pabal.me ยท Based on the Pabal server as of 2026-09-19 Docs home ยท Pabal.me