miniproto
miniproto is a fast, async-first Telegram MTProto client core for Python. It owns protocol correctness, authorization, encrypted sessions, raw Layer 228 bindings, updates, peers, messages, and bounded media transfers while a bundled Rust/PyO3 extension accelerates measured hot paths.
The first public line is 0.1.x Alpha: the implementation is substantial, but breaking changes remain possible while the API and operational defaults settle. Start with the documentation website or the five-minute quickstart.
Install
python -m pip install miniproto
The package requires Python 3.13 or newer. Release automation targets normal CPython 3.13 and 3.14 plus free-threaded CPython 3.14t, with native wheels for Linux glibc/musl, Windows, and macOS on x86-64 and ARM64. CPython 3.13t and ARMv7 are not supported. Until the first Alpha artifacts are published, contributors can install the checkout with uv sync --extra dev,docs and uv run maturin develop.
Secure minimal quickstart
This deliberately uses in-memory storage, so it contacts Telegram but does not retain an authorization credential on disk:
import os
from miniproto import Client, ClientConfig, InMemorySessionStorage, event_loop
async def main() -> None:
config = ClientConfig(
api_id=int(os.environ["MINIPROTO_API_ID"]),
api_hash=os.environ["MINIPROTO_API_HASH"],
session_storage=InMemorySessionStorage(),
)
async with Client(config) as client:
await client.sign_in_bot(os.environ["MINIPROTO_BOT_TOKEN"])
me = await client.get_me()
print(f"authorized bot ID: {me.id}")
event_loop.run(main())
For a durable client, omit session_storage, provide MINIPROTO_SESSION_KEY through a secret manager, and use a distinct session_path for each account. The default encrypted SQLite storage refuses to initialize without adequate key material; InMemorySessionStorage is intentionally ephemeral. See Session Security before persisting or moving authorization state.
Authorization and identity
Phone authorization accepts sync or async callbacks for the login code and optional two-step-verification password:
import getpass
await client.sign_in_phone(
"+12025550123",
code_callback=lambda: getpass.getpass("Telegram login code: "),
password_callback=lambda: getpass.getpass("Two-step password: "),
)
me = await client.get_me()
Bots use await client.sign_in_bot(token). Neither flow grants permissions Telegram has not assigned to the account, and no credentialed example is part of the offline test suite.
Raw Layer 228 calls
The generated raw API exposes every pinned Telegram function and constructor while Client.invoke() owns request wrapping, result validation, datacenter migration, eligible retries, flood-wait handling, and optional quick acknowledgements:
from miniproto.raw import functions
telegram_config = await client.invoke(functions.HelpGetConfig())
print(telegram_config.this_dc)
The generated Telegram reference cross-links functions, parameters, result families, constructors, known RPC errors, and Python import names. For a non-idempotent request, do not force retry=True unless the operation has an application-owned deduplication guarantee.
Messages and files
The convenience surface stays intentionally small:
message = await client.send_message("@your_test_chat", "Hello from miniproto")
edited = await client.edit_message("@your_test_chat", message.id, "Updated text")
await client.delete_messages("@your_test_chat", [edited.id], revoke=True)
uploaded = await client.send_file("@your_test_chat", "report.pdf", caption="Nightly report")
send_message() and the final send step of send_file() can request a transport quick acknowledgement. That receipt means Telegram accepted the encrypted packet for processing; the awaited RPC result remains the operation’s completion signal.
Ordered updates
from miniproto import Update
async def consume_updates() -> None:
async for update in client.iter_updates():
if isinstance(update, Update):
await process(update)
Update recovery persists MTProto state before public delivery, handles difference recovery, and preserves FIFO order for the normalized events it emits. It is not an application-level exactly-once guarantee: durable side effects still need application-owned idempotency, and a blocked iterator task must be cancelled during shutdown.
Bounded media transfers
from pathlib import Path
result = await client.download_media(message.media, Path("download.bin"), concurrency=4, verify_plain_hashes=True)
with Path("stream.bin").open("wb") as output:
async for chunk in client.iter_download(message.media, concurrency=2, max_in_flight_bytes=4 * 1024 * 1024):
output.write(chunk)
Uploads and downloads use bounded request windows, shared byte-weighted per-DC schedulers, dedicated media lanes, migration-aware pools, file-reference refresh, cancellation cleanup, mandatory CDN integrity checks, and optional ordinary upload.getFileHashes verification. iter_download() yields ordered chunks without materializing the whole file; download_media() additionally supports memory, paths, caller-owned destinations, ranges, resuming, caching, and eligible bot multi-session downloads.
Sessions, native code, and fallbacks
Native miniproto session strings can be exported as a checksummed bearer value or protected with Scrypt and AES-256-GCM. Telethon v1 and Pyrogram compatibility formats are supported with explicitly lossy field mappings. Every session string is a bearer credential, even when encrypted at rest.
The private miniproto._native extension provides crypto, MTProto envelope, transport framing, TL, and session hot paths. Public wrappers select capabilities rather than assuming that one successful import implements everything; supported Python/cryptography paths remain available when a native capability cannot load. Reproducible benchmark commands and result interpretation are documented in Performance and benchmarks; no local timing is presented as a universal Telegram throughput claim.
miniproto versus mpgram
miniproto is the reusable protocol SDK: transports, authorization, sessions, DC migration, raw invocation, generated bindings, updates, peers, core message helpers, and media primitives. The future mpgram package is the application-framework boundary for routers, filters, decorators, middleware, commands, plugins, dependency/context helpers, conversations, bound message methods, and broad high-level Telegram ergonomics.
Documentation and project links
- Documentation — authored guides plus searchable generated Python, Telegram, and Rust reference pages.
- Documentation backup — in case the main site is down, always reflect the latest changes on the
masterbranch. - Architecture — ownership boundaries and the Python/schema/Rust execution model.
- Development commands — schema, docs, quality, tests, benchmarks, builds, and release diagnostics.
- Release guide — attested build artifacts, OIDC publishing, immutable releases, and recovery boundaries.
- Contributing — local setup and verification expectations.
- Security policy — supported Alpha line, secret handling, and private vulnerability reporting.
- Changelog — complete
0.1.0Alpha capability and limitation summary.
The project takes API-design inspiration from Telethon, Pyrogram and its forks, Grammers, TDLib, GramJS, mtcute, Telegram Web K/tweb, and Telegram’s official MTProto documentation without copying copyleft implementation code. Telegram controls account permissions, limits, and service behavior; users remain responsible for Telegram’s Terms of Service, API rules, account consent, and lawful data handling.