開発者ドキュメント
日本語

Pabal API

Pabal API(MTProto)

アプリと同じ方式でサーバーに接続するクライアントを作るとき:接続情報、サーバーの公開鍵、認証の流れ、アップデート、サポート範囲。

Pabal アプリは、サーバーと MTProto 2.0 でやり取りします。同じ方式で接続するプログラム — 別のアプリ、人のアカウントで動く自動化、研究用のクライアント — を作るときは、このドキュメントを参照してください。ボットを作るなら、よりシンプルな Bot API で十分です。

Telegram のドキュメントもあわせて参照してください

Pabal は Telegram の公開プロトコルに従っているため、プロトコルとメソッドの詳しい定義は MTProtoAPI メソッドのドキュメントが基準です。このドキュメントには、Pabal サーバーに接続するときの違いとサポート範囲を記載しています。

接続情報

項目
アドレス122.34.175.215
ポート8443(TCP)
DC1〜5 はすべて同じアドレスです。どの DC に接続してもよく、通常は 2 を使います
プロトコルMTProto 2.0、API レイヤー 216
トランスポートAbridged、Intermediate、Padded Intermediate、Full — それぞれ難読化(obfuscated2)を含む
サーバーの公開鍵server-key.pem · fingerprint 8724853375441383205
api_id · api_hash検証しません。任意の値を入れてください

HTTP トランスポート、WebSocket トランスポート、MTProxy はまだありません。クライアント端末の時計が正確である必要があります — MTProto のメッセージ番号は時刻から作られるため、時計が大きくずれていると、サーバーがメッセージを破棄します。

サーバーの公開鍵

MTProto クライアントは、はじめて接続するときに、サーバーの RSA 公開鍵で認証キーの交換を暗号化します。Telegram クライアントには Telegram の公開鍵が組み込まれているため、Pabal に接続するにはこの鍵を代わりに(または追加で)組み込む必要があります。この鍵によって、別のサーバーが Pabal サーバーになりすますことを防ぎます。

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

この鍵はサーバーの初回起動時に一度だけ作られ、その後は変わりません。サーバーログの Loaded RSA key … (fingerprint …) の値と、上の fingerprint が一致するか確認してください。

Telethon で接続する

Python の Telethon で人のアカウントにログインし、メッセージをやり取りする例です。アカウントは先にアプリで登録しておいてください(下記参照)。

# pabal_client.py — pip install telethon==1.42.0
# 同じフォルダーに server-key.pem(上でダウンロードしたサーバーの公開鍵)
import asyncio

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

rsa.add_key(open("server-key.pem").read(), old=False)          # Pabal サーバーの公開鍵

client = TelegramClient("pabal", api_id=1, api_hash="0" * 32)  # 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("電話番号 (+8190…): "))   # 初回に一度だけコードを入力
    me = await client.get_me()
    print(f"ログイン: {me.first_name} (id {me.id})")
    await client.send_message("BotFather", "/help")
    await client.run_until_disconnected()


asyncio.run(main())
  • Telethon 1.42 を使ってください。レイヤー 216 を話すバージョンです。より新しいバージョンはより高いレイヤーでレスポンスを読もうとするため、TypeNotFoundError で失敗します。
  • 新規アカウントの登録は、Telethon 側で無効にされていますsign_up())。アプリで登録するか、auth.signUp を直接呼んでください。
  • ログインは pabal.session ファイルに保存され、次回からはコードを聞かれません。このファイルはアカウントの鍵なので、大切に守ってください。

ログインの流れ

1 · 認証キー (1 回) req_pq_multi → req_DH_params set_client_DH_params 認証キー 2048 ビットサーバー公開鍵で保護 2 · ログイン (認証キーごとに 1 回) auth.sendCode電話番号 sentCodeTypeSmsSMS または管理者が伝達 SetUpEmailRequiredメール方式 → アドレスを入力 account.sendVerifyEmailCodepurpose: loginSetup auth.signInphone_code または email コード auth.authorizationログイン完了 authorizationSignUpRequired新しい番号 → auth.signUp(名前) コードが届いたら
認証キーを作り、コードでログインする

図の説明

  • 2 つの段階:上は暗号化に使う認証キーを作る段階(プロトコル)、下はそのキーにアカウントを結び付けるログインの段階(API)です。上の段階は、ライブラリが自動的に処理します。
  • ログインは認証キーに紐づきます:一度ログインしたキーで複数のセッションを開いても、すべてログイン状態です。キーを失うと(セッションファイルを削除した場合など)、再度ログインする必要があります。
  • コードの届け方は、サーバーの運営者が決めます:SMS・管理者による伝達なら sentCodeTypeSms、メールなら sentCodeTypeSetUpEmailRequired が返り、クライアントがメールアドレスを尋ねて account.sendVerifyEmailCode を呼びます(中央の行)。
  • 赤い点線は新しい番号の経路です:コードは正しいのにアカウントがない場合は authorizationSignUpRequired が返り、名前を入れて auth.signUp を呼ぶと登録が完了します。登録は、コードが正しかった場合にのみ可能です。
  • ボットは下の段階の代わりに、auth.importBotAuthorization(ボットトークン)の 1 回でログインします。
エラー発生する場面
PHONE_NUMBER_INVALID番号が正しくない、またはサーバーが新規登録を停止している状態での新しい番号
PHONE_NUMBER_BANNED運営者がブロックした番号
FLOOD_WAIT_n(420)コードを頻繁に要求しすぎた。n 秒後に再試行
PHONE_CODE_INVALIDコードが正しくない(規定の回数を超えるとロック)
PHONE_CODE_EXPIREDコードの期限切れ・ロック、または不明な phone_code_hash — sendCode からやり直す
EMAIL_INVALID, EMAIL_NOT_ALLOWEDメールアドレスが正しくない / 既存のアカウントで、登録済みのログイン用メールアドレスではない
AUTH_KEY_UNREGISTERED(401)ログインしていないキーで、ログインが必要なメソッドを呼んだ
テスト番号

運営者がテスト番号を有効にしたサーバーでは、+99966XYYYY 形式の番号が、実際のコード配信なしにコード XXXXX(X を 5 回)でログインできます。開発用サーバー専用の機能で、本番サーバーでは無効になっています。

アップデートの受信

  • リアルタイム:接続が開いていれば、サーバーは新しいメッセージ・編集・削除を updateShortMessageupdates ですぐに送ります。リクエストを送ったセッションは、その結果を RPC のレスポンスとして受け取るため、同じものがプッシュでもう一度届くことはありません。
  • pts:ユーザーごとに、変化に通し番号(pts)が付きます。受け取った pts に抜けがあれば、クライアントは何かを見逃しています。
  • 追いつきupdates.getState で現在の pts を覚えておき、再接続したら updates.getDifference(pts, date, qts) で、その間の新しいメッセージ・削除と、関連するユーザー・グループを受け取ります。クライアントの持つ pts がサーバーより進んでいる場合(サーバーのデータが初期化された場合など)は differenceTooLong が返るので、会話一覧を読み込み直してください。
  • Telethon のようなライブラリは、この処理をすべて自動で行います。

ID とピア

対象IDメモ
100001 からpeerUser。@BotFather は 100000
ボット人と同じ番号体系user.bot = true。トークンの先頭の数字がボット ID
基本グループ1000001 からpeerChat。Bot API では負の数(-chat_id)として見えます
メッセージメッセージボックスごとに 1 から1:1 の会話では、参加者がそれぞれ自分のコピーと自分の番号を持ちます。同じメッセージでも、2 人で番号が異なることがあります

access_hash は、サーバーから受け取った値をそのまま保存しておいて使ってください(ユーザー名の検索・会話一覧・アップデートと一緒に届きます)。

ファイル

  • アップロードupload.saveFilePart で分割してアップロードし、inputFileUploaded… で参照します。大きなファイル用の upload.saveBigFilePart はまだないため、事実上 10MB までです。
  • 送信messages.sendMediainputMediaUploadedPhoto(新しい写真)または inputMediaPhoto(サーバー上の写真)。ほかのメディアは MEDIA_INVALID
  • 受信upload.getFileinputPhotoFileLocation(メッセージの写真)、inputPeerPhotoFileLocation(プロフィール写真)。一度に最大 1MB。
  • プロフィール写真photos.uploadProfilePhotophotos.updateProfilePhotophotos.getUserPhotosphotos.deletePhotos
  • 写真は原本の 1 サイズだけで保存します(サムネイルは別途作りません)。

サポート範囲

サーバーにはレイヤー 216 の 408 メソッド分のハンドラーがあり、すべてリクエストを読み取れますが、実際のクライアントで最後まで確認したものは下のメソッドです。それ以外は形式どおりに応答しますが、内容が空だったり、記録されなかったりすることがあります。

分野確認したメソッド
接続initConnection, invokeWithLayer, help.getConfig, auth.bindTempAuthKey(PFS の一時キー), auth.exportAuthorization/importAuthorization
ログインauth.sendCode, auth.signIn, auth.signUp, auth.logOut, auth.importBotAuthorization, account.sendVerifyEmailCode
ユーザー・連絡先users.getUsers, users.getFullUser, contacts.resolveUsername, contacts.importContacts, contacts.search
メッセージmessages.sendMessage, messages.sendMedia(写真), messages.getHistory, messages.getDialogs, messages.getMessages, messages.editMessage, messages.deleteMessages
グループmessages.createChat, messages.deleteChatUser, messages.editChatTitlemessages.addChatUser は公式アプリでのみ確認)
ボットmessages.getBotCallbackAnswer, messages.setBotCallbackAnswer, ボタン(reply_markup)付きのメッセージ
アップデートupdates.getState, updates.getDifference, リアルタイムプッシュ
ファイル・写真upload.saveFilePart, upload.getFile, photos.*(上記)

公式の Telegram Desktop 6.2.6 が、登録・ログイン・会話・写真・グループ・再接続まで、改変なしで動作することも確認しました。アプリの起動時に呼ばれる約 60 個のメソッドは、レスポンスの形式を個別に検査しています。

エラー

エラーは標準の rpc_errorerror_code + error_message)で返ります。error_message は常に大文字・数字・アンダースコア(PEER_ID_INVALID)の形式で、必要に応じて : 説明 が付きます。

コード意味
400リクエストが正しくない — PEER_ID_INVALID, MESSAGE_ID_INVALID, MEDIA_INVALID, USERNAME_NOT_OCCUPIED
401ログインが必要 — AUTH_KEY_UNREGISTERED
403権限がない — メンバーではないグループなど
420FLOOD_WAIT_n — n 秒待つ
500サーバー内部エラー
トランスポートエラー -404サーバーがこの認証キーを知らない — 新しいキーを作って再ログイン(永続キー)、または再バインド(一時キー)

まだないもの

  • チャンネル・スーパーグループ(channels.* は応答するが、アプリで正しく表示されない)、シークレットチャット、通話
  • 写真以外のメディア、upload.saveBigFilePart、サムネイル
  • 2 段階認証(SRP)— 設定できず、2 段階認証が必要な操作は拒否されます
  • HTTP・WebSocket トランスポート、MTProxy、msgs_ack の送信、bad_server_salt によるソルトの切り替え
  • 複数サーバーへの分散 — 1 台のサーバーが DC 1〜5 をすべて担当します

公式 Telegram アプリを Pabal に接続するには

Telegram アプリは、サーバーのアドレスと公開鍵をビルド時に組み込みます。そのため、設定画面ではなく、ソースを修正して再ビルドする必要があります。Pabal アプリ(Pabal.app)は、そのようにして作られたものです。サーバーの運営者なら、サーバーのインストール — アプリの接続を参照してください。