Skip to main content

GoyGram

GoyGram Logo

Python 3.11+ Rust Core License: AGPL v3 PyPI version PyPI downloads Telegram API Security Docs & Wiki

What is this?

Ultimate hybrid Telegram framework (Python + Rust core) built for production-grade speed, control, and maximum OpSec.

Under the hood: a Python orchestration layer drives two completely independent network transports (Bot API over aiohttp + MTProto over raw TCP with full DH key exchange), both feeding into a single async event bus. Every crypto operation — AES-256-IGE for MTProto packets, AES-256-GCM for session vaults — runs in a Rust .so compiled with LTO and opt-level=3. Hand-written TL codec, no code generation at runtime. QR code login rendering in the terminal via qrcode + Rich. SRP password proofs for 2FA. And the vault: your auth key locked to your machine-id through PBKDF2-SHA256 at 600,000 iterations.

Key Features

  • Hybrid architecture: ergonomic Python layer + blazing-fast Rust extension.
  • Session zeroize: aggressive in-memory cleanup (zeroize strategy for legacy .session files after migration).
  • Vault AES-256-GCM: encrypted local session bootstrap. Key derived from machine-id + session name via PBKDF2 (or bypass with GOYGRAM_VAULT_KEY).
  • TUI auth flow: terminal-first authorization workflow — phone login with SMS code, QR code scanning in ASCII art, 2FA/SRP password challenges. All Rich-styled when a TTY is present.
  • Proxy support: SOCKS5 (with user/pass auth) and HTTP CONNECT tunneling for MTProto connections. Also respects ALL_PROXY / HTTPS_PROXY / HTTP_PROXY env vars.
  • Dual transport: Bot API (HTTP long-polling via aiohttp, multipart uploads, auto-webhook-clear on 409) + MTProto (raw TCP with AES-256-IGE, dynamic salt recovery on bad_server_salt, auto-DC migration on PHONE_MIGRATE_N) — in one app runtime.
  • Bot over MTProto: pass bot_token + api_id/api_hash to authorize a bot through auth.importBotAuthorization and switch between via="api" and via="mtproto" in the same runtime.
  • DC Routing: MTProto uses a built-in map of the five Telegram DC endpoints and selects the preferred DC, falling back to 149.154.167.50:443 (DC 2).
  • Dynamic API dispatch: every Bot API method works via __getattr__ — sendAnimation, getUserProfilePhotos, setMyCommands, whatever. Snake_case auto-converts to CamelCase. mt_ prefix routes to MTProto.
  • Keyboard system: inline keyboards, reply keyboards, force reply, reply removal. All with to_dict() serialization that adapts per transport.
  • Forum topic management: full create/edit/close/reopen/delete lifecycle for forum topics and the General topic. Both transports supported.
  • One dynamic event object: Obj with kind-dispatch; MsgObj, CbObj, PollObj, MemberObj, InlineObj are aliases — lazy raw-field access, no model registry, no per-kind classes.
  • Composable filters: boolean AND/OR/NOT on Filter (filters.text & ~filters.me).
  • Multi-session: named vaults (session_name="worker_1") for farming multiple accounts from the same process. Separate auth keys, separate TCP connections, separate self_id.
  • Portable sessions: a single Session object doubles as memory, file (.vault), and encrypted string (export_string() / from_string()). Rename-safe vaults let you name the file by self_id after login.
  • Durable delivery state: Bot API offsets and MTProto pts/qts/date/seq cursors are persisted atomically with restrictive permissions.
  • Direct media primitives: chunked MTProto upload_file()/download_file() and Bot API download_file() without a heavyweight media framework.

Benchmarks

Cold import, memory footprint, and MTProto crypto (AES-256-IGE) measured against telethon, pyrogram, aiogram and python-telegram-bot. Full methodology and reproduction in benchmarks/.

goygram telethon pyrogram aiogram python-telegram-bot
cold import (ms) 74 272 436 2699 141
RSS delta (MB) 13 48 35 152 19
AES-256-IGE (MB/s, 64 KiB) 1094 14 228 — —

The crypto runs in Rust with AES-NI intrinsics selected at runtime (built in, no separate C extension; tgcrypto 1.2.5 measures 234 MB/s on the same box), GoyGram starts ~36× faster than aiogram, and uses ~12× less memory.

Installation

pip install goygram

Requires Python 3.11+. Pre-built wheels ship for Linux, Windows, macOS, and FreeBSD where the corresponding runner build succeeds. Termux is natively validated in a Termux environment; install the Python package from source there because Android/Termux wheels are not interchangeable with manylinux wheels. Rust is not required for the standard Linux, Windows, and macOS wheels. Installs aiohttp, rich, and qrcode as dependencies.

FreeBSD and Termux

FreeBSD packages are built by the release workflow inside a FreeBSD 15 VM and attached to the GitHub Release because PyPI rejects FreeBSD's nonstandard wheel platform tag. The Rust core is built in the official termux/termux-docker environment and attached as a native validation asset; Termux users should build locally from the source distribution. On a real Termux device, install the Termux toolchain and build from the source distribution:

pkg update
pkg install python rust clang
python -m pip install --no-build-isolation .

Quick Start

1) Bot API (token)

import asyncio
from goygram import GoyGram, filters

app = GoyGram(bot_token="123456:ABC_TOKEN")

@app.on_msg(filt=filters.text)
async def echo(msg):
    await msg.reply("Hello from Bot API")

asyncio.run(app.run())

2) MTProto (no bot token, requires API ID + API Hash)

import asyncio
from goygram import GoyGram

app = GoyGram(api_id=123456, api_hash="0123456789abcdef0123456789abcdef")  # auto-fetches Telegram DC endpoint at startup

@app.on_cmd("ping")
async def ping(msg):
    await msg.reply("pong from MTProto (api_id/api_hash)")

asyncio.run(app.run())

3) Named MTProto sessions (multi-session in one folder)

import asyncio
from goygram import GoyGram

app = GoyGram(
    api_id=123456,
    api_hash="0123456789abcdef0123456789abcdef",
    session_name="farm_worker_1",
)

asyncio.run(app.run())
  • By default, session data is stored in default.vault.
  • With session_name="farm_worker_1", session data is stored in farm_worker_1.vault.
  • If farm_worker_1.session exists, it is migrated to farm_worker_1.vault during bootstrap (securely zeroized after).

4) Bot over MTProto (auth.importBotAuthorization)

A bot can run over raw MTProto instead of the Bot API HTTP transport. Pass bot_token together with api_id/api_hash and GoyGram authorizes the bot through auth.importBotAuthorization — the MTProto equivalent of the Bot API token handshake (with automatic USER_MIGRATE_N DC migration):

import asyncio
from goygram import GoyGram

app = GoyGram(
    bot_token="123456:ABC_TOKEN",
    api_id=123456,
    api_hash="0123456789abcdef0123456789abcdef",
    default_transport="mtproto",   # prefer MTProto for outgoing calls
)

@app.on_cmd("ping")
async def ping(msg):
    await msg.reply("pong via MTProto")

asyncio.run(app.run())

Both transports stay available in one runtime. Switch per call with via="api" (Bot API) or via="mtproto" (MTProto):

await app.send_msg("123456789", "via Bot API", via="api")
await app.send_msg("123456789", "via MTProto", via="mtproto")

default_transport sets the default when via is omitted: "api", "mtproto", or "auto" (Bot API if a token is present, else MTProto).

Dynamic API & Methods

GoyGram can route Bot API method names dynamically, including methods that are not hardcoded as convenience methods:

  • Call Bot API methods directly even if they are not explicitly hardcoded:
    • await app.sendDocument(chat_id=..., document=...)
    • await app.getChat(chat_id=...)
    • await app.getUpdates(timeout=30)
  • Snake-case also works and is converted to Bot API method names:
    • await app.send_document(chat_id=..., document=...) -> sendDocument
  • MTProto actions (authorized with API ID/API Hash) are available with mt_ prefix:
    • await app.mt_get_dialogs(limit=50)
    • await app.mt_get_chat_full(chat_id=...)

This behavior is implemented through dynamic method resolution in the client core (__getattr__) and transport-aware request routing.

For Bot API files, await app.download_file(file_id, destination) downloads a Telegram file to memory or atomically to a local path. MTProto exposes the same low-level chunk control through app.core.mt.upload_file(...) and app.core.mt.download_file(...).

Authentication & Security

Interactive Login

On first run with MTProto, GoyGram launches a Rich-powered TUI:

GoyGram Interactive Login

? Choose login method:
  > QR Code Login
    Phone Number Login

Choose QR code (scan with any Telegram client) or phone number (SMS code). 2FA password is handled automatically via SRP proofs. The resulting session is stored as default.vault — AES-256-GCM encrypted, keyed to your machine.

Vault Encryption

  • Algorithm: AES-256-GCM (authenticated encryption via Rust's aes-gcm crate)
  • Key derivation: PBKDF2-HMAC-SHA256, 600,000 iterations, key material = {machine-id}:{session_name}
  • Override: GOYGRAM_VAULT_KEY env var (base64-encoded 32 bytes) bypasses PBKDF2 entirely The vault does not fall back to silently accepting plaintext after a failed decryption.

Session Migration

Telethon/Pyrogram .session files are auto-detected, read from SQLite, migrated to .vault, and securely zeroized (overwrite + fsync + unlink).

Session: memory, file, and portable string

Every app exposes app.session — a single Session object that is the session in memory, in a file (.vault), and as a portable encrypted string at the same time. No separate MemorySession / StringSession / SQLiteSession classes and no painful conversions.

from goygram import GoyGram, Session

app = GoyGram(api_id=123456, api_hash="0123456789abcdef0123456789abcdef")

# after authorization, read the account id and name the file by it (rename-safe):
await app.session.save(f"{app.session.self_id}.vault")

# or keep it as an encrypted, portable string (not plaintext like Telethon/Pyrogram):
token = app.session.export_string()   # AES-256-GCM encrypted, machine-locked
sess = Session.from_string(token)     # one call to restore
  • Rename-safe vaults: the encryption key no longer depends on the file name, so you can log in first and name/rename the session file afterwards (e.g. by self_id).
  • Encrypted string sessions: export_string() / from_string() carry the session as an authenticated, machine-locked blob — unlike Telethon's and Pyrogram's plaintext StringSession.
  • One object, three forms: session.data, session.save(path), session.load(path), session.export_string(), session.from_string(s). self_id, is_bot, auth_key, server_salt, and dc are exposed as properties.
  • Backward compatible: legacy vaults (and .session migrations) still decrypt; new vaults are written with a GGV2 header that the reader auto-detects.

Pass an existing session explicitly:

app = GoyGram(api_id=..., api_hash=..., session=Session.from_string(token))
app = GoyGram(api_id=..., api_hash=..., session=Session(name="worker_1"))

The constructor still accepts session_name="..." for the plain file-backed case.

Developer Tools (Help)

Use built-in introspection tools:

app.help()            # pretty DX overview in console
print(dir(app))       # inspect available shortcuts + dynamic entries

or:

from goygram.utils import print_methods
print_methods(app)

With type hints on key event aliases (MsgObj, CbObj, MemberObj, PollObj) and filter primitives, modern IDE autocomplete works much better out of the box.

Filters

goygram.filters supports composable boolean operators:

from goygram import filters

smart_filter = filters.text & ~filters.me
another = filters.text | filters.me

@app.on_msg(filt=smart_filter)
async def handler(msg):
    await msg.reply("Filtered")

Built-in filters: filters.text (message has text), filters.me (message from current account/bot). Compose with &, |, ~. Custom filters: Filter(lambda e: ...).

Transport Routing

Messages can be routed explicitly by transport:

# Force Bot API
await app.send_msg("bot:123456789", "via api", via="api")

# Force MTProto
await app.send_msg("mt:123456789", "via mtproto", via="mtproto")

via="api" is an alias for the Bot API transport and via="mtproto" for MTProto (the short forms via="bot" / via="mt" still work). Chat ID prefixes (bot: / mt:) are auto-resolved. When replying, the transport source is preserved automatically — reply to a Bot API message, it goes back via Bot API.

FSM Persistence

The default FSM remains in memory:

app = GoyGram(bot_token="123456:ABC_TOKEN")

For an external store, pass an object with load() and save(snapshot) methods:

class RedisFSM:
    def __init__(self, redis):
        self.redis = redis

    def load(self):
        return self.redis.json().get("goygram:fsm") or []

    def save(self, snapshot):
        self.redis.json().set("goygram:fsm", ".", snapshot)

app = GoyGram(bot_token="123456:ABC_TOKEN", fsm_backend=RedisFSM(redis))

For complete control, use fsm_on_change. It receives a JSON-compatible snapshot after every state change and can write it to Redis, PostgreSQL, a file, or another service:

def persist_fsm(snapshot):
    external_store.write(snapshot)

app = GoyGram(bot_token="123456:ABC_TOKEN", fsm_on_change=persist_fsm)

The active core object is also available as app.fsm. It exposes snapshot() and restore(snapshot) for explicit checkpoints and migrations. Existing set_state, get_state, get_state_data, and clear_state behavior is unchanged.

Event Pipeline

BotNet.spin() ──→ bus.push("bot", data)
                                          ──→ Disp.consume() → your handlers
MTNet.spin() ──→ bus.push("mt", data)

Single asyncio.Queue → dynamic event objects (MsgObj/CbObj/PollObj/MemberObj/InlineObj, aliases of one Obj) → handler lists in registration order. Per-handler error isolation — one crashing handler never takes down the dispatcher.

Logging

GOYGRAM_LOG=DEBUG python app.py   # verbose (raw MTProto packet dumps)
GOYGRAM_LOG=INFO python app.py    # default (startup, errors)
GOYGRAM_LOG=WARNING python app.py # quiet

Logger hierarchy: goygram.app, goygram.botapi, goygram.mtproto, goygram.disp, goygram.security, goygram.dc.

Architecture at a Glance

┌─────────────────────────────────────────────┐
│             GoyGram (Public API)             │  ← User-facing facade
├─────────────────────────────────────────────┤
│        AppCore (Internal Engine)             │  ← Config, hooks, routing
├──────────────────┬──────────────────────────┤
│ BotNet (aiohttp) │   MTNet (TCP/MTProto)    │  ← Independent transports
├──────────────────┴──────────────────────────┤
│          Bus → Disp (Event Pipeline)         │  ← asyncio.Queue + dispatcher
├─────────────────────────────────────────────┤
│  goygram.ext (Rust .so) — AES-IGE/AES-GCM   │  ← Native crypto (LTO, opt=3)
└─────────────────────────────────────────────┘

Wiki

📚 Official documentation and Wiki. There are separate pages for using the client, Bot API, MTProto, events, bytes and TL data. 👉 Open GoyGram Pages · Open GitHub Wiki

License

See LICENSE.

Release files for goygram 0.7.74

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for goygram 0.7.74
File Size Uploaded
goygram-0.7.74.tar.gz 99.4 kB Details

Built distributions (wheels)

Table of built distributions (wheels) for goygram 0.7.74
File Interpreter ABI Platform
goygram-0.7.74-cp311-abi3-win_amd64.whl CPython 3.11 abi3 Windows x86-64 Details
goygram-0.7.74-cp311-abi3-manylinux_2_34_x86_64.whl CPython 3.11 abi3 Linux glibc 2.34+ x86-64 Details
goygram-0.7.74-cp311-abi3-macosx_11_0_arm64.whl CPython 3.11 abi3 macOS 11.0+ ARM64 Details

Total release size: 1.2 MB

Release files / goygram-0.7.74.tar.gz

Download URL goygram-0.7.74.tar.gz
Size 99.4 kB
Tags Source
SHA-256 checksum
How to use checksums
e346a79b8ae313accf43ca230dfc4850c36b585b02c1dc66198c84dfafb5b584
BLAKE2b-256 checksum
How to use checksums
ad3410d473ff3ecec79aca57be0a49d591350e387b11a03f46e76e55c2542236
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / goygram-0.7.74-cp311-abi3-win_amd64.whl

Download URL goygram-0.7.74-cp311-abi3-win_amd64.whl
Size 330.0 kB
Tags CPython 3.11 Windows x86-64 abi3
SHA-256 checksum
How to use checksums
6fe08ef473468dbdd2db97774acc1909b0542eb98102b694248787d8edffba7f
BLAKE2b-256 checksum
How to use checksums
33f6771e201fef64a901159fe8588f77b3cc4f94fdd3cdf374203ff38440439c
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / goygram-0.7.74-cp311-abi3-manylinux_2_34_x86_64.whl

Download URL goygram-0.7.74-cp311-abi3-manylinux_2_34_x86_64.whl
Size 415.6 kB
Tags CPython 3.11 Linux glibc 2.34+ x86-64 abi3
SHA-256 checksum
How to use checksums
6a9bcb9f67a7b4352832f5b341f6f62bc337ccd24ae2351d0b005c11829baa66
BLAKE2b-256 checksum
How to use checksums
a16ccd38067ec7025f439e9b8bc2c47f049c5a07bbca2dcf43afeba9478055f8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release files / goygram-0.7.74-cp311-abi3-macosx_11_0_arm64.whl

Download URL goygram-0.7.74-cp311-abi3-macosx_11_0_arm64.whl
Size 385.9 kB
Tags CPython 3.11 abi3 macOS 11.0+ ARM64
SHA-256 checksum
How to use checksums
3f85efd27ae7e9806fde3b225846b6ad882f0d1f588bed3319b62d5c686c23dc
BLAKE2b-256 checksum
How to use checksums
d8031900c1572f5f55aa80912069465d9a70541a26ab0fe373cbe904dd638761
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via maturin/1.15.0

Release history Release notifications | RSS feed

0.8.7

4 release files

0.8.6

4 release files

0.8.5

4 release files

0.8.4

4 release files

0.8.3

4 release files

0.8.2

4 release files

0.8.1

4 release files

0.8.0

4 release files

0.7.99

4 release files

0.7.98

4 release files

0.7.97

4 release files

0.7.96

4 release files

0.7.95

4 release files

0.7.94

4 release files

0.7.93

4 release files

0.7.92

4 release files

0.7.91

4 release files

0.7.90

4 release files

0.7.89

4 release files

0.7.88

4 release files

0.7.87

4 release files

0.7.86

4 release files

0.7.85

4 release files

0.7.84

4 release files

0.7.82

4 release files

0.7.81

4 release files

0.7.80

4 release files

0.7.79

4 release files

0.7.78

4 release files

0.7.77

4 release files

0.7.76

4 release files

0.7.75

4 release files

This release

0.7.74 This release

4 release files

0.7.63

4 release files

0.7.62

4 release files

0.7.61

4 release files

0.7.60

4 release files

0.7.59

4 release files

0.7.58

4 release files

0.7.57

4 release files

0.7.56

4 release files

0.7.55

4 release files

0.7.54

4 release files

0.7.53

4 release files

0.7.52

4 release files

0.7.51

4 release files

0.7.50

4 release files

0.7.49

4 release files

0.7.48

4 release files

0.7.47

4 release files

0.7.46

4 release files

0.7.45

4 release files

0.7.35

4 release files

0.7.34

4 release files

0.7.33

4 release files

0.7.32

4 release files

0.7.31

4 release files

0.7.30

4 release files

0.7.29

4 release files

0.7.28

4 release files

0.7.27

4 release files

0.7.26

4 release files

0.7.25

4 release files

0.7.24

4 release files

0.7.23

4 release files

0.7.22

4 release files

0.7.21

4 release files

0.7.20

4 release files

0.7.19

4 release files

0.7.18

4 release files

0.7.17

4 release files

0.7.16

4 release files

0.7.15

4 release files

0.7.14

4 release files

0.7.13

4 release files

0.7.9

4 release files

0.7.8

4 release files

0.7.7

4 release files

0.7.6

4 release files

0.7.5

4 release files

0.7.4

4 release files

0.7.3

4 release files

0.7.2

4 release files

0.7.1

4 release files

0.7.0

4 release files

0.6.9

4 release files

0.6.8

4 release files

0.6.7

4 release files

0.6.6

4 release files

0.6.5

4 release files

0.6.4

4 release files

0.6.3

4 release files

0.6.2

4 release files

0.6.1

4 release files

0.6.0

4 release files

0.5.7

4 release files

0.5.6

4 release files

0.5.5

4 release files

0.5.3

4 release files

0.5.1

4 release files

0.5.0

4 release files

0.4.9

4 release files

0.4.8

4 release files

0.4.7

4 release files

0.4.2

4 release files

0.4.1

4 release files

0.4.0

4 release files

0.3.9

4 release files

0.3.8

4 release files

0.3.7

4 release files

0.3.6

4 release files

0.3.5

4 release files

0.3.4

4 release files

0.3.2

4 release files

0.3.0

4 release files

0.1.0

4 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page