Precision-Engineered Telegram Stack for Zig 0.17.
zig-telegram unifies three protocol planes in one zero-dependency Zig package:
100% deterministic codegen for Bot API 10.3 (all 185 methods & 400 types/unions),
a pure-Zig MTProto 2.0 binary/cryptographic core (TL codec, AES-256-IGE, SHA-256 msg_key, Obfuscated2 framing),
and an optional runtime-loaded TDLib tdjson bridge.
const std = @import("std");
const telegram = @import("telegram");
pub fn main(init: std.process.Init) !void {
var http: telegram.transport.HttpTransport = .init(init.gpa, init.io);
defer http.deinit();
const token = try telegram.SecretToken.initValidated("123456:ABC-DEF");
var client = telegram.bot.BotClient.init(
init.gpa, init.io, token, http.transport(), .{},
);
var detail: ?telegram.ErrorDetail = null;
defer if (detail) |*d| d.deinit(init.gpa);
var msg = try client.sendMessage(.{
.chat_id = .fromInt(42),
.text = "Hello from zig-telegram (Bot API 10.3)!",
.parse_mode = .MarkdownV2,
}, &detail);
defer msg.deinit();
}
One Module. Three Protocol Planes. Zero Hidden State.
Every network call, allocator, and error diagnostic is explicit. Choose high-level Bot API 10.3 ergonomics, low-level MTProto 2.0 binary framing, or dynamic TDLib JSON bindings.
Recursive attach:// Multipart
Existing Zig libraries only inspect top-level method fields for InputFile, silently breaking
sendMediaGroup, sendPaidMedia, and editMessageMedia.
- Walks structs, optionals, slices, and unions
- Emits
"attach://part_<n>"in JSON automatically - Streams binary parts with CSPRNG 128-bit boundaries
- RFC 7578 filename quote/CRLF escaping
SecretToken & Caller-Owned Errors
Bot tokens never leak in logs or stack traces, and concurrent threads never race on a shared mutable
last_error struct field.
SecretToken.formatprintsbot<id>:[REDACTED]- Constant-time SHA-256 webhook header verification
- Explicit
err_out: ?*?ErrorDetailwithretry_after - Automatic
--localBot API server path remapping
Pure-Zig Cryptography & Framing
Full MTProto 2.0 binary packet codec built exclusively on Zig's standard library primitives.
- AES-256-IGE mode on top of
std.crypto.core.aes.Aes256 - MTProto 2.0 SHA-256
msg_key& AES key/IV derivation - Abridged, Intermediate, Padded & Obfuscated2 framing
- 64-bit time-synchronized monotonic
msg_idgenerator
Why zig-telegram Replaces First-Gen Zig Wrappers
Audited against zigtgshka, ziogram, and telebot.zig across
specification coverage, multipart correctness, TLS connection reuse, and memory safety.
| Capability | zig-telegram (0.17.0) | zigtgshka | ziogram | telebot.zig |
|---|---|---|---|---|
| Telegram Bot API Spec | 10.3 (185 methods / 400 types) | 9.2 (161 methods) | 7.10 partial | ~30 manual methods |
Nested attach:// Multipart (sendMediaGroup) |
Recursive comptime + runtime | Top-level fields only | None | libcurl C FFI |
Discriminated Unions (23 unions + RichText) |
Single-pass zero-DOM scanner | 2-pass DOM allocation | Incomplete | Manual structs |
| HTTP Transport & TLS 1.3 Keep-Alive | Persistent pooled std.http.Client | New client per request | New client per request | Requires C libcurl |
Error Diagnostics (retry_after, migrate_to_chat_id) |
Caller-owned ?*?ErrorDetail | Discarded on error | Thread-unsafe struct field | Status code only |
| Webhook Constant-Time Secret Verification | SHA-256 + timing_safe.eql | Not included | Not included | Not included |
| Pure-Zig MTProto 2.0 Core (TL + AES-256-IGE) | Included (telegram.mtproto) | No | No | No |
Copy-Ready Zig 0.17 Snippets
Add zig-telegram with zig fetch --save git+https://github.com/guanchzhou/zig-telegram
and import @import("telegram").
const std = @import("std");
const telegram = @import("telegram");
const AppCtx = struct {
client: *telegram.bot.BotClient,
pub fn onStart(self: *@This(), msg: telegram.bot.types.Message, args: []const u8) !void {
_ = args;
var r = try self.client.sendMessage(.{
.chat_id = .fromInt(msg.chat.id),
.text = "Welcome to zig-telegram!",
}, null);
r.deinit();
}
};
const AppRouter = telegram.bot.Router(*AppCtx, .{
.commands = &.{.{ .name = "start", .handler = AppCtx.onStart }},
});
const media_items = [_]telegram.bot.types.InputMedia{
.{ .photo = .{
.media = .fromBytes("diagram.png", png_bytes),
.caption = "Uploaded via attach://part_0",
} },
.{ .document = .{
.media = .fromPath("./spec/bot_api_10_3.json"),
.thumbnail = .fromBytes("thumb.jpg", jpg_bytes),
} },
};
var sent = try client.sendMediaGroup(.{
.chat_id = .fromChannel("@zig_announcements"),
.media = &media_items,
}, null);
defer sent.deinit();
var processor: telegram.bot.WebhookProcessor = .{
.expected_secret_token = "whsec_super_secret_token_2026",
};
var update = try processor.verifyAndParseUpdate(
allocator,
headers,
request_body,
);
defer update.deinit();
var session = telegram.mtproto.session.Session.init(
auth_key,
0x0102030405060708,
0x1122334455667788,
);
const encrypted = try session.encryptPacket(
allocator,
tl_payload,
unix_time_sec,
true,
.client_to_server,
random_pad,
);
defer allocator.free(encrypted.packet);
$ zig build run -- spec
Telegram Bot API 10.3 (August 24, 2026) — 185 methods
$ zig build run -- mtproto
MTProto 2.0 Self-Test: OK (auth_key_id=0x..., msg_id=0x..., packet=64 bytes, factorizePq(0x17ED48941A08F981)=0x494C553B * 0x53911073)
$ TELEGRAM_BOT_TOKEN="123456:ABC-DEF" zig build run -- send --chat 42 --text "Deployed!"
Explore All 185 Generated BotClient Methods
Filter every method generated from spec/bot_api_10_3.json. Each method is available on
telegram.bot.BotClient with strongly-typed parameters in telegram.bot.methods.
Measured Performance on Apple Silicon (Zig 0.17.0 ReleaseFast)
Reproduce locally with zig build bench and enforce the regression gate in CI via zig build perf-check.
Discriminated Union JSON Decode (ChatMember)
Zero-allocation top-level tag scanner vs 2-pass std.json.Value DOM tree allocation.
Protocol & Cryptographic Throughput
Pure-Zig MTProto 2.0 AES-256-IGE packet encryption and constant-time SHA-256 webhook verification.