Telegram 登录 API:验证码、两步验证与 sessionId

发布于 2026年10月9日

Telegram Messaging API 里,除了第一个接口,后面的每次调用都要带一个 sessionId。它代表一个已登录的 Telegram 个人账号,而获取它只需要走一遍很短的登录流程:创建会话,把 Telegram 发给账号的登录验证码交给接口,如果账号开启了两步验证,再提交云密码。状态变成 CONNECTED 之后,同一个 sessionId 就能用于收发消息、查看会话、联系人和群组管理。

本文用 curl 和 Python 把完整流程走一遍:手机号加验证码登录、两步验证密码、扫码登录,以及不用新验证码的会话恢复。请只登录你本人拥有或获得授权的账号,并遵守 Telegram 的服务条款。

登录流程总览

三种方式的起点相同,都是调用 POST create-session,终点也相同,都是 CONNECTED:

  1. 手机号模式:提交手机号,Telegram 把登录验证码发到该账号,你再把验证码交给接口。
  2. 扫码模式:展示一个二维码,账号持有人在 Telegram 的「设备」页面扫描。
  3. 恢复模式:传入之前的 sessionId,直接用已保存的登录重新连接,不需要新的验证码。

每一步之后,都用 get-session 轮询并读取 status。你会看到的状态有 CREATED、WAITING_FOR_SCAN、WAITING_FOR_OTP、CONNECTING、CONNECTED、DISCONNECTED、LOGGED_OUT 和 FAILED。手机号模式下,先轮询到状态为 WAITING_FOR_OTP,提交验证码,再继续轮询直到状态变为 CONNECTED。提交验证码和密码的调用都是异步受理的:接口会立刻返回,真正的结果要从状态里看。

第一步:获取 API Key

注册后在控制台复制一个有效 Key。新账户赠送免费点数,足够你把整套流程测通。

第二步:用手机号创建会话

create-session 接收一段 JSON。手机号模式需要 mode、带国家区号且以 + 开头的完整号码 phoneNumber,以及用来标识设备的 deviceName。这段 JSON 要作为字符串放进 body 字段:

curl -X POST 'https://api.opendata-api.com/api/project/telegram-messaging/create-session?key=YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"body":"{\"mode\":\"phone\",\"phoneNumber\":\"+15551234567\",\"deviceName\":\"My Bot\"}"}'

响应被包了两层,形如 {"code": 200, "message": "success", "data": {"code": 201, "data": {...}}}:外层由平台返回,内层来自消息服务,它始终返回 HTTP 200,失败时在自己的 code、title、detail 里说明原因。新会话的标识是最内层数据里的 id 字段,也就是原始 JSON 中的 data.data.id。请保存好它,因为之后每次调用都要把它作为查询参数 sessionId 带上。然后轮询会话,直到状态变为 WAITING_FOR_OTP,再提交登录验证码。

第三步:等待会话要求验证码

call() 会拆开两层响应,把 200、201、202、204 都视为成功,其余情况带着完整响应体抛出异常;wait_for() 负责轮询 get-session。

import json
import time
import requests

API_KEY = "YOUR_API_KEY"
BASE = "https://api.opendata-api.com/api/project/telegram-messaging"
SUCCESS_CODES = {200, 201, 202, 204}


def call(method, operation, payload=None, **params):
    """Call one operation and return the innermost payload (dict, list or None)."""
    params["key"] = API_KEY
    kwargs = {"params": params, "timeout": 60}
    if payload is not None:
        kwargs["json"] = {"body": json.dumps(payload)}
    resp = requests.request(method, f"{BASE}/{operation}", **kwargs)
    if not resp.ok:
        raise RuntimeError(f"{operation} failed: HTTP {resp.status_code} {resp.text}")
    body = resp.json()
    # Peel both envelopes: {"code": 200, "data": {"code": 201, "data": {...}}}
    while isinstance(body, dict) and "code" in body:
        if body["code"] not in SUCCESS_CODES:
            raise RuntimeError(f"{operation} failed: {body}")
        body = body.get("data")
    return body


def wait_for(session_id, wanted, timeout=120, stop_on_2fa=False):
    """Poll get-session until `status` is in `wanted`, or until 2FA is requested."""
    deadline = time.time() + timeout
    while time.time() < deadline:
        state = call("GET", "get-session", sessionId=session_id)
        status = state.get("status")
        if status in wanted or (stop_on_2fa and state.get("twoFactorRequired")):
            return state
        if status in ("FAILED", "LOGGED_OUT"):
            raise RuntimeError(f"login ended with status {status}")
        time.sleep(2)
    raise TimeoutError("session did not reach the expected status in time")

get-session 除了状态,还会返回登录方式和手机号;登录等待期间还会带上 qrImage 或 twoFactorRequired 标记。如果账号已保存但当前离线,调用它还会顺带把账号重新连上。

第四步:提交验证码(OTP)

登录验证码会发到该账号的 Telegram 应用内,而不是短信。在状态为 WAITING_FOR_OTP 时,用 verify-otp 提交;其他状态下提交无效。

curl -X POST 'https://api.opendata-api.com/api/project/telegram-messaging/verify-otp?key=YOUR_API_KEY&sessionId=YOUR_SESSION_ID' \
  -H 'Content-Type: application/json' \
  -d '{"body":"{\"code\":\"12345\"}"}'

因为是异步受理,请不要把立刻返回的响应当作最终结果。再次轮询 get-session:要么变成 CONNECTED,要么出现 twoFactorRequired=true,表示该账号还设置了云密码(此时状态本身仍是 WAITING_FOR_OTP)。

第五步:需要时提交两步验证密码

如果账号开启了两步验证,就用 submit-password 提交密码。它只在会话显示 twoFactorRequired=true 时有效(此时状态仍是 WAITING_FOR_OTP):手机号模式出现在验证码之后,扫码模式出现在扫码之后。

import getpass

session = call("POST", "create-session",
               {"mode": "phone", "phoneNumber": "+15551234567", "deviceName": "My Bot"})
# The identifier is the "id" field; "sessionId" is only the query-parameter name.
session_id = (session or {}).get("id")
if not session_id:
    raise RuntimeError(f"no session id in the response: {session}")

wait_for(session_id, {"WAITING_FOR_OTP"})
code = input("Login code from the Telegram app: ").strip()
call("POST", "verify-otp", {"code": code}, sessionId=session_id)

state = wait_for(session_id, {"CONNECTED"}, stop_on_2fa=True)
if state.get("status") != "CONNECTED":
    password = getpass.getpass("Telegram cloud password: ")
    call("POST", "submit-password", {"password": password}, sessionId=session_id)
    state = wait_for(session_id, {"CONNECTED"}, timeout=60)

print("status:", state.get("status"))
print("session id to keep for restore:", state.get("id", session_id))
print("account:", call("GET", "get-account", sessionId=session_id))

这段脚本是交互式读取验证码和密码的,并且不会保存它们。在真实产品里,应当在你自己的界面上通过 HTTPS 收集这两项信息,转发一次即可,千万不要写进日志。最后的 get-account 能确认会话连接的究竟是哪个账号。

扫码登录

如果账号持有人不方便接收验证码,可以改用 qr 模式创建会话:

curl -X POST 'https://api.opendata-api.com/api/project/telegram-messaging/create-session?key=YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"body":"{\"mode\":\"qr\",\"deviceName\":\"My Bot\"}"}'

创建响应会返回 qrPageUrl,打开这个链接就能实时查看登录进度。如果想在自己的界面里绘制二维码,就轮询 get-session,渲染它返回的 qrImage(base64 数据 URI)。账号持有人在手机上依次打开 Telegram、设置、设备、链接桌面设备,然后扫描二维码即可。账号设置了云密码的话,扫码之后同样用 submit-password 收尾。

恢复已保存的会话

服务重启之后不需要重新登录。把之前的 ID 传给 create-session 的 restore 模式,已保存的登录会直接重新连接,无需新的验证码:

curl -X POST 'https://api.opendata-api.com/api/project/telegram-messaging/create-session?key=YOUR_API_KEY' \
  -H 'Content-Type: application/json' \
  -d '{"body":"{\"mode\":\"restore\",\"sessionId\":\"PREVIOUS_SESSION_ID\"}"}'

连接成功后,会话 ID 会变成由账号派生的稳定 ID,原来的 ID 和稳定 ID 都继续有效。请读取登录后 get-session 返回的 id 并保存下来,用于以后的恢复调用;恢复模式的请求体里,这个字段叫 sessionId,如上所示。

退出登录与断开连接

disconnect-session 是一个 DELETE 调用。默认只断开实时连接、保留已保存的登录,之后随时可以恢复。加上 logout=true 则会同时远程退出 Telegram 并删除已保存的登录,此后账号必须重新用验证码或扫码登录。

curl -X DELETE 'https://api.opendata-api.com/api/project/telegram-messaging/disconnect-session?key=YOUR_API_KEY&sessionId=YOUR_SESSION_ID&logout=false'

常见问题排查

  • 一直停在 WAITING_FOR_OTP。 请到账号的 Telegram 应用里找验证码,而不是看短信。验证码只在状态为 WAITING_FOR_OTP 时才会被接受。
  • verify-otp 被拒绝。 它只在状态为 WAITING_FOR_OTP 时有效,多半是会话已经处于其他状态,先读一下 get-session。
  • 验证码通过后出现 twoFactorRequired=true。 这对设置了云密码的账号是正常现象,继续调用 submit-password 即可。
  • 状态为 FAILED、LOGGED_OUT 或 DISCONNECTED。 调用 get-session 会把已保存但离线的账号重新连上。如果已保存的登录已经没了,例如用 logout=true 调用过 disconnect-session,就重新创建会话并再登录一次。

安全与合规

登录验证码、云密码和 sessionId 都属于账号持有人的敏感信息。只能向持有人本人收集,绝不写入日志,sessionId 放进密钥管理服务,API Key 一旦泄露就立即更换。只操作你本人拥有或明确获得授权的账号。登录之后的下一步,请看用 Python 发送和读取 Telegram 消息;如果只想在不建立会话的情况下查询某个号码或用户名是否存在于 Telegram,可以用 Telegram 号码检测;想看 WhatsApp 上同类的扫码与配对码流程,请阅读如何通过 API 发送 WhatsApp 消息。

常见问题

Telegram 的登录验证码会通过短信发送吗? 在这个流程里,验证码会发到账号的 Telegram 应用内。请在已登录该账号的设备上打开 Telegram,查看验证码消息,并在会话状态为 WAITING_FOR_OTP 时通过 verify-otp 提交。

账号开启了两步验证怎么办? 提交验证码(或完成扫码)之后,会话会显示 twoFactorRequired=true。这时用 submit-password 提交云密码,再轮询 get-session,直到状态变为 CONNECTED。

可以不输验证码就登录吗? 可以,有两种办法。扫码模式让账号持有人在 Telegram 的设备页面扫描二维码;恢复模式则用已保存的 sessionId 重新连接之前登录过的账号,不需要任何新的验证码。

会话能保持多久? 普通的 disconnect-session 会保留已保存的登录,之后可以随时恢复;加上 logout=true 则会删除它,账号需要重新用验证码或扫码登录。重启之后用 create-session 的 restore 模式恢复即可,只是收件箱和会话列表的记录会被清空。

为什么 verify-otp 立刻返回了,却没有结果? 验证码和密码的提交都是异步处理的,立即返回的响应只表示请求已被受理。请轮询 get-session,直到状态变成 CONNECTED、出现 twoFactorRequired=true,或者提示失败。

立即体验

在 Telegram Messaging 页面可以直接在线跑通整个流程,也可以阅读 create-session、verify-otp、submit-password 与 get-session 的接口文档。查看定价了解每次请求的成本。