A Telegram Bot API library for Go, implemented directly over MTProto using
gotd/td — not over HTTP to api.telegram.org.
It exposes the familiar Bot API surface
(types, methods, updates) but speaks MTProto on a persistent connection. That
sidesteps the Bot API server's rate limits, removes the getUpdates/webhook
round trip, and keeps the raw gotd/td client one method call away
(Bot.Raw()) for anything not yet covered.
Status: under active reconstruction. The repo is being rebuilt from a codegen-first OpenAPI/ogen project into a hand-written library. The
Botclient skeleton compiles and connects today; the typed Bot API surface (methods, types, handler framework) is being filled in. Seedocs/roadmap.mdfor what's done and what's next.
| HTTP Bot API client | botapi | |
|---|---|---|
| Transport | HTTPS to api.telegram.org |
MTProto via gotd/td |
| Updates | getUpdates long-poll / webhook |
persistent connection, no polling |
| Rate limits | Bot API server limits | MTProto limits only |
| Escape hatch | none | raw *tg.Client via Bot.Raw() |
In priority order (see docs/architecture.md):
- Zero-reflection performance — fully typed request/response building, no
reflectin the hot path; allocation-tested likegotd/td. - Type-safe unions & enums —
ChatID,InputFile,ChatMember,ReplyMarkup, parse modes, etc. as sealed interfaces and typed constants, not stringly-typed structs. - First-class context & structured errors — context-first API; typed errors (flood-wait, retry-after, network vs API vs not-implemented); proactive rate limiting.
- A great handler framework — composable middleware, router and predicates over a native MTProto update stream.
package main
import (
"context"
"github.com/gotd/botapi"
)
func main() {
// Bots still need an MTProto app identity (https://my.telegram.org).
// This is NOT the bot token.
bot, err := botapi.New("<bot-token>", botapi.Options{
AppID: 123456,
AppHash: "<app-hash>",
})
if err != nil {
panic(err)
}
bot.OnCommand("start", "Start the bot", func(c *botapi.Context) error {
_, err := c.Reply("Hello!")
return err
})
// Connects, authorizes as a bot, and serves updates until ctx is cancelled.
if err := bot.Run(context.Background()); err != nil {
panic(err)
}
}See the guide for the full surface (sending, media,
keyboards, handlers, predicates, middleware, commands, files, chat management,
errors, pooling) and examples/ for runnable bots
(echo, buttons, inline, media, rich, background, advanced).
Options.Storage is optional — leave it nil to keep session, peers and update
state in memory (nothing survives a restart). storage.Open("bot.bbolt")
persists all of it to a single bbolt file; close it on shutdown. Every example
under examples/ persists its session this way by default, so
they reconnect without re-authorizing.
botapi(root) — the public library: theBotclient, options, and the hand-written Bot API surface as it lands.pool— runs and multiplexes many bots by token over one process.storage— bbolt-backed session/peer/update-state storage.internal/botdoc— fetches and extracts the published Bot API docs; kept as a reference oracle and a conformance check against API-version drift.cmd/botdoc— CLI to fetch and inspect the published Bot API docs.
- Bot API reference — the spec.
gotd/td— the MTProto engine.- reference Bot API server.