Skip to main content
SwiftBot - Ultra-Fast Telegram Bot Framework

PyPI Python License

SwiftBot

SwiftBot is a fast, async-first Telegram bot framework built for simplicity and correctness. One decorator registers a handler, a rich Context object does the talking, and the framework quietly handles everything else — HTTP/2 connection pooling, Retry-After compliance, persistent state storage, and a fully typed error hierarchy. Everything is typed, everything is optional, and you never need an external database to get started.

pip install swiftbot

Why SwiftBot

Writing a Telegram bot should not mean wiring polling loops, rate-limit math, and error handling by hand. SwiftBot gives you a clean decorator API on top of a production-grade runtime: HTTP/2 multiplexing over a keep-alive connection pool, a worker pool with backpressure and a dead-letter queue, a trie-based command router, and full Bot API 2026 coverage — including managed bots, guest mode, business messages, and ephemeral messages.

Quick Start

import asyncio
from swiftbot import SwiftBot, Filters as F
from swiftbot.types import Message

bot = SwiftBot(token="YOUR_BOT_TOKEN")

@bot.on(Message(text="hello"))
async def hello(ctx):
    await ctx.reply("Hi there!")

@bot.on(Message(filters=F.command("start")))
async def start(ctx):
    await ctx.reply("Welcome! Send me hello.")

asyncio.run(bot.run())

That is the whole bot. No router setup, no dispatch table, no middleware boilerplate.

Core Concepts

Handlers and Filters

Handlers are registered with @bot.on(Message(...)) and the first matching handler wins. Filters are composable — combine commands, regex patterns, and predicates:

@bot.on(Message(filters=F.command("ban") & F.chat(-100123456789)))
async def ban(ctx):
    ...

@bot.on(Message(pattern=r"^/weather (\w+)"))
async def weather(ctx):
    city = ctx.match.group(1)
    await ctx.reply(f"Weather in {city}: sunny")

Context

Every handler receives a Context with typed access to the update, plus shortcuts that cover most use cases: ctx.reply(), ctx.edit(), ctx.delete(), ctx.answer_callback(), and ctx.forward_to().

Buttons and Callbacks

from swiftbot import InlineKeyboard, Button, CallbackData

# Declare the payload shape once
page = CallbackData("page", int)

# Attach packed payloads to buttons
kb = InlineKeyboard([]).add_row(
    Button.inline("1", page.pack(1)),
    Button.inline("2", page.pack(2)),
)
await ctx.reply("Pick a page:", reply_markup=kb.to_dict())

# Filter on valid payloads and decode the typed data
@bot.on(CallbackQuery(pattern=rf"^{page.prefix}:[^:]+:[^:]+$"))
async def on_page(ctx):
    page_num = page.unpack(ctx.callback_query.data)[0]
    await ctx.answer_callback(f"Page {page_num}")

State and Dialogues

State survives restarts with pluggable storage backends — in-memory, JSON file, or Redis — and the dialogue system models multi-step conversations as declared transition graphs with per-state timeouts:

survey = bot.dialogue("survey")

@survey.state("ask_name", next=["ask_age"])
async def ask_name(ctx, prev=None):
    await ctx.reply("What's your name?")
    return Dialogue.next("ask_age", carry=ctx.text)

@survey.state("ask_age", timeout=120.0)
async def ask_age(ctx, prev=None):
    await ctx.reply(f"Hi {prev}, how old are you?")
    return Dialogue.end

Middleware, Pipelines and Scopes

Middleware runs around every handler, and the Composer bundles middleware chains with error boundaries. Pipeline adds dependency injection so handlers stay pure and testable, while scope() attaches middleware to only the updates matching a predicate.

from swiftbot.middleware import Logger, RateLimiter
from swiftbot.pipeline import Pipeline

bot.use(Logger())
bot.use(RateLimiter(rate=20, per=60))

pipe = Pipeline().deps(db=my_db)
async def stats(ctx, db):
    await ctx.reply(f"{await db.count()} users")
pipe.handle(F.command("stats"), stats)
bot.pipeline(pipe)

bot.scope(F.private).use(RateLimiter(rate=1, per=1.0))

Safety Nets

Fallback handlers catch anything that no other handler matched, and outbound throttling keeps your bot under Telegram's limits automatically:

@bot.fallback
async def catch_all(ctx):
    await ctx.reply("Try /help.")

bot.api.config.use(throttle(max_per_second=20.0, per_chat=4.0))

Testing Without Telegram

The built-in harness runs your real handlers with zero network calls — every outgoing API request is captured and every response is scriptable:

from swiftbot.testing import TestClient

async with TestClient(bot) as client:
    await client.send_update({
        "update_id": 1,
        "message": {
            "message_id": 1, "date": 1,
            "chat": {"id": 1, "type": "private"},
            "from": {"id": 2, "is_bot": False, "first_name": "A"},
            "text": "hello",
        },
    })

assert client.outgoing[0]["method"] == "sendMessage"

More

Topic What you get
Commands Declarative command specs with auto-generated /help
Transformers Outbound API layer with auto-typing and recording
Deep Linking Typed ?start= payloads for referrals and auth
Webhooks aiohttp server with secret-token verification and metrics
Storage In-memory, JSON-file, and Redis FSM backends
Exceptions Typed ChatNotFound, TooManyRequests, Forbidden, ...

The complete documentation lives in the docs/ folder.

Contributing

Contributions are welcome — open an issue or submit a pull request.

License

MIT — Copyright (c) 2026 Arjun-M/SwiftBot

Metadata

Release files for swiftbot 1.6.1

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

Source distribution (sdist)

Source distribution for swiftbot 1.6.1
File Size Uploaded
swiftbot-1.6.1.tar.gz 94.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for swiftbot 1.6.1
File Interpreter ABI Platform
swiftbot-1.6.1-py3-none-any.whl Python 3 none any Details

Total release size: 203.7 kB

Release files / swiftbot-1.6.1.tar.gz

Download URL swiftbot-1.6.1.tar.gz
Size 94.0 kB
Tags Source
SHA-256 checksum
How to use checksums
f3b064145cafb4f80fc6b0377128da0c30bc4d20b82733a2c57e1985771b921b
BLAKE2b-256 checksum
How to use checksums
c19363495e18a9a4d43184042bd3393b2621a2c6a45af1f271c46fecff4f65e8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release files / swiftbot-1.6.1-py3-none-any.whl

Download URL swiftbot-1.6.1-py3-none-any.whl
Size 109.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
e3fc1d66b84f52f42e03123e09fe06d7ee4b0a9d04e8c3ea8a9c4f8ff15bf55d
BLAKE2b-256 checksum
How to use checksums
efe79fd405f06f60222d82fc2df3f9576d5626ad82aac8d92052ab6ef58148fa
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/7.0.0 CPython/3.12.3

Release history Release notifications | RSS feed

1.6.4

2 release files

1.6.3

2 release files

1.6.2

2 release files

This release

1.6.1 This release

2 release files

1.6.0

2 release files

1.0.2

2 release files

1.0.1

2 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