Skip to main content

Async framework for Max messenger bots (aiogram-style)

Project description

AioScam

Async Python framework for building Max messenger bots, inspired by aiogram architecture.

Version

v0.2.1 — Latest (2026-06-21)

What's new in v0.2.1

  • HomePage — generic landing page for the server root, so a plain visitor/scanner sees a normal-looking page with no hint that /api/* exists; mount the real Mini App frontend under its own path instead
  • WebAppMiddleware 404/401 split — a request with no initData at all now gets a plain 404 (looks like the route doesn't exist); only a present-but-wrong signature gets 401
  • api_prefix — move the API off the well-known /api path; examples/webapp_bot.py wires it through WEBAPP_API_PREFIX end to end, including server-side template rewriting for all 4 frontend pages
  • WebAppFailGuard — in-memory sliding-window per-IP ban for repeat failed-auth probing
  • 633/633 tests passing

What's new in v0.2.0

  • aioscam.webapp — server-side module for Max WebApps (mini apps): validate_init_data() / validate_contact() (HMAC-SHA256), EventStreamManager (SSE push, Bot → WebApp), WebAppMiddleware (validates initData on /api/* requests, static files stay public)
  • BotCapabilitiesBotCapabilities.probe(bot) reports what the bot can actually do at startup, since GET /me carries no permissions field; caps.log_report(logger) prints a banner
  • Hint-based exceptions everywhere — every framework exception now carries a .hint with a concrete cause/fix, appended automatically to str(exc) (ApiError, NetworkError, RetryAfter, UnauthorizedError, BotTokenError, DispatcherError, and the new WebApp* exceptions)
  • examples/webapp_bot.py + examples/webapp/*.html — working bot with a REST+SSE API and 4 frontend pages (native Bridge SDK reference, Vue 3 demo, Chart.js, sortable table)
  • 604/604 tests passing

What's new in v0.1.8.1

  • AIOSCAM_ENV / AIOSCAM_API_URL — исправлен регистр env-переменных (Aioscam_ENVAIOSCAM_ENV), на Linux mixed-case переменные не работали
  • PolyForm Noncommercial License 1.0.0 — смена лицензии с MIT

Features

  • 🚀 Fully asyncasyncio + aiohttp
  • 🎯 aiogram-style API — familiar decorators and patterns
  • 🔄 Router system — modular, nestable
  • 🎭 Magic FiltersF.text, F.callback.payload, F.message.body.text
  • 🔧 Middleware — request/response pipeline
  • 📦 FSMState, StatesGroup, MemoryStorage
  • 🛡️ StateGuard — blocks unauthorized commands during active FSM
  • 🖼️ Media — upload/download images, video, audio, documents
  • 📱 Contact & Location — inline buttons for phone and geolocation
  • 📝 Formatting — Markdown and HTML
  • 🔗 Deep linkscreate_deep_link, parse_deep_link, StartCommand filter
  • 🌍 I18n — JSON-based translations, auto locale from user_locale
  • 📋 Bot Commandsset_my_commands(), set_bot_info()
  • 🗑️ Message Management — delete, pin, edit
  • 🌐 Webhook — aiohttp, FastAPI, Litestar
  • 📡 Polling — long-polling with exponential backoff
  • 🛡️ Rate Limiter — token bucket, 429 retry, exponential backoff
  • 🔒 Security — webhook secret token, circular router detection
  • 🪟 WebApp (Mini Apps)initData/contact validation, SSE push (Bot → WebApp), /api/* middleware
  • 📊 BotCapabilities — capability/permission report logged at startup
  • 💡 Hint-based exceptions — every error tells you what to actually do about it
  • 📦 Python 3.9–3.12

Installation

git clone https://github.com/alex-di-96/aioscam.git
cd aioscam
pip install -e .
pip install aioscam[fastapi]   # FastAPI webhook
pip install aioscam[litestar]  # Litestar webhook
pip install aioscam[dev]       # pytest, ruff, mypy

aioscam.webapp (WebApp/Mini App support — validate_init_data, EventStreamManager, WebAppMiddleware) needs no extra install — it only uses aiohttp and pydantic, both already required by the base package. A plain pip install aioscam is enough.

Quick Start

import asyncio
from aioscam import Bot, Dispatcher, Router
from aioscam.filters import Command, F

dp = Dispatcher()
router = Router()

@router.message_created(Command("start"))
async def cmd_start(event):
    await event.answer("Hello! Send me anything.")

@router.message_created()
async def echo(event):
    await event.answer(event.text)

dp.include_router(router)

async def main():
    bot = Bot()  # token from MAX_BOT_TOKEN env
    await dp.start_polling(bot)

asyncio.run(main())

Media

from aioscam import InputMedia, InputMediaBuffer, UploadType

# Send from file path (type auto-detected from extension)
await bot.send_photo(chat_id=cid, user_id=uid, photo="photo.jpg")
await bot.send_video(chat_id=cid, user_id=uid, video="video.mp4", caption="Watch!")
await bot.send_document(chat_id=cid, user_id=uid, document="report.pdf")
await bot.send_audio(chat_id=cid, user_id=uid, audio="song.mp3")

# Auto-detect type
await bot.send_media(chat_id=cid, user_id=uid, media="anyfile.ext")

# From bytes buffer (no file on disk)
data = open("photo.jpg", "rb").read()
await bot.send_photo(chat_id=cid, user_id=uid, photo=data)

# Download incoming media into memory
image_bytes = await bot.download_file_bytes(url, token)

# Download to disk with unique temp name
path = Bot.make_temp_path(".jpg")  # /tmp/aioscam_20260528_143022_847291.jpg
await bot.download_file(path, url, token)

FSM

from aioscam.fsm import State, StatesGroup

class Registration(StatesGroup):
    waiting_name = State()
    waiting_age = State()
    waiting_email = State()
    waiting_phone = State()

@router.message_created(Command("register"))
async def start(event, state):
    await state.set_state(Registration.waiting_name)
    await event.answer("Step 1/4: Enter your name:")

@router.message_created(StateFilter(Registration.waiting_name))
async def name(event, state):
    await state.update_data(name=event.text)
    await state.set_state(Registration.waiting_age)
    await event.answer("Step 2/4: Enter your age:")

WebApp (Max Mini Apps)

Server-side helpers for two-way communication between your bot and a Max WebApp (mini app) running in the client's WebView:

from aioscam.webapp import validate_init_data, EventStreamManager
from aioscam.webapp.aiohttp import WebAppMiddleware
from aioscam.utils.capabilities import BotCapabilities

# Validate the signed initData a WebApp page sends you
data = validate_init_data(raw_init_data, bot_token)  # -> WebAppInitData (HMAC-SHA256 checked)

# Push events from the bot to a connected WebApp over SSE
events = EventStreamManager()
await events.publish(user_id, {"type": "bot_message", "text": "hi from the bot"})

# Protect your /api/* routes (static files stay public)
app.middlewares.append(WebAppMiddleware(bot_token=bot.token))

# Log what this bot can actually do at startup
caps = await BotCapabilities.probe(bot, webapp_url="https://example.com/webapp")
caps.log_report(logger)

Serve the server's HTTP root with a generic landing page instead of a hand-written index.html — works with no JS (plain "Open in Max" link) and gives a scanner/plain visitor no hint that /api/* exists. Mount your actual Mini App frontend under its own path (e.g. /app) and register that path in the Max bot dashboard, not the bare root:

from aioscam.webapp.aiohttp import HomePage

app.router.add_get("/", HomePage(bot).handler)

WebAppMiddleware already returns 404 (not 401) when a request carries no initData at all, so blind probing of /api/* paths looks identical to a route that doesn't exist — only requests with a (wrong) signature get a 401. For stronger masking, move the API off the well-known /api prefix and add a WebAppFailGuard to flat-404 repeat offenders instead of letting them keep guessing:

from aioscam.webapp.aiohttp import WebAppFailGuard, WebAppMiddleware

guard = WebAppFailGuard(max_failures=20, window=60, ban_seconds=300)
app.middlewares.append(
    WebAppMiddleware(bot_token=bot.token, api_prefix="/a8f3e1", fail_guard=guard)
)

Full working example with a REST+SSE backend and 4 frontend pages (native Bridge SDK reference, Vue 3, Chart.js, sortable table): examples/webapp_bot.py + examples/webapp/*.html — run it with WEBAPP_API_PREFIX=/your-secret to see api_prefix move the whole API and have the frontend pick it up automatically (the server rewrites const API_PREFIX = "/api"; in each served page).

Rate Limiter

from aioscam import Bot
from aioscam.limiter import RateLimitConfig

bot = Bot(rate_limit=RateLimitConfig.strict())   # 5 req/s, burst 10
bot = Bot(rate_limit=RateLimitConfig.relaxed())  # 30 req/s, burst 50

API Coverage

Category Methods
Bot Info get_me, get_me_from_chat, change_info, set_bot_info, set_my_commands
Messages send_message, edit_message, delete_message, get_message, get_messages, pin_message, delete_pin_message, get_pin_message
Media send_photo, send_video, send_audio, send_document, send_media, download_file, download_file_bytes, get_upload_url, get_video
Callbacks send_callback, send_action
Chats get_chats, get_chat_by_id, get_chat_by_link, edit_chat, delete_chat, add_chat_members, remove_member_chat, add_list_admin_chat, remove_admin, get_chat_members, get_chat_member, get_list_admin_chat, delete_me_from_chat
Updates get_updates, get_last_marker
Webhooks subscribe_webhook, unsubscribe_webhook, get_subscriptions

14 event types: message_created, message_callback, message_edited, message_removed, bot_started, bot_stopped, bot_added, bot_removed, chat_title_changed, dialog_cleared, dialog_muted, dialog_unmuted, user_added, user_removed

8 button types: CallbackButton, LinkButton, ChatButton, MessageButton, ClipboardButton, OpenAppButton, RequestContactButton, RequestGeoLocationButton

Project Structure

aioscam/
├── bot/          # Bot client — all API methods
├── client/       # HTTP client (aiohttp, rate-limited, file upload/download)
├── dispatcher/   # Dispatcher, Router, EventContext, StateGuard
├── enums/        # 15 enum files
├── exceptions/   # 12 exception classes
├── filters/      # Command, Text, StartCommand, StateFilter, ContentType, F
├── fsm/          # State, StatesGroup, MemoryStorage
├── handler/      # MessageHandler, CallbackHandler, EventHandler
├── i18n/         # I18n — JSON translations, locale detection
├── limiter/      # RateLimiter, RateLimitConfig
├── methods/      # BaseMethod, GetMe, SendMessage, GetUpdates
├── middleware/   # BaseMiddleware, MiddlewareManager
├── types/        # Pydantic models — User, Chat, Message, Attachment, etc.
├── utils/        # KeyboardBuilder, formatting, deep_linking, media, BotCapabilities
└── webapp/       # validate_init_data, validate_contact, EventStreamManager, WebAppMiddleware

Configuration

MAX_BOT_TOKEN=your_token
AIOSCAM_ENV=prod   # debug | test | prod

Testing

python -m pytest tests/ -v

633/633 tests passing (100%)

Example Bots

File Description
echo_bot.py Simple echo bot
fsm_bot.py FSM registration flow
keyboard_bot.py Inline keyboard demo
callback_bot.py send_callback demo
middleware_bot.py Logging + timing middleware
router_bot.py Multi-router architecture
webhook_bot.py Webhook mode (aiohttp)
deep_link_bot.py Deep links + referral
deep_link_test_bot.py Deep link raw update debugger
i18n_bot.py Multilingual bot (ru/en)
media_bot.py Media upload/download demo
rate_limited_bot.py Rate limiter demo
methods_bot.py Methods API demo
demo_bot.py Full-featured demo (FSM, media, i18n, deep links, SQLAlchemy)
run_bot.py Minimal launcher
webapp_bot.py WebApp REST+SSE backend — examples/webapp/*.html frontends

License

PolyForm Noncommercial License 1.0.0aLex Di

Free for personal, educational, and other noncommercial use. Commercial use requires a separate license — contact the author.

☕ Support the Project

If you find AioScam useful and want to support its development, consider:

  • 🍪 Buy me a cookieBoosty
  • Star the repo — it helps with visibility
  • 🐛 Report bugs — open issues for any problems you find
  • 🤝 Contribute — PRs welcome!

Every cookie fuels more features, faster bug fixes, and better documentation! 🚀

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

aioscam-0.2.1.tar.gz (126.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

aioscam-0.2.1-py3-none-any.whl (99.1 kB view details)

Uploaded Python 3

File details

Details for the file aioscam-0.2.1.tar.gz.

File metadata

  • Download URL: aioscam-0.2.1.tar.gz
  • Upload date:
  • Size: 126.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for aioscam-0.2.1.tar.gz
Algorithm Hash digest
SHA256 70526b45d00b55d1a1f600e7ccaadf5a922a4c5ae380502b6a85023638aebfb6
MD5 75dc41875bfb3959dd82fc6eef905126
BLAKE2b-256 15f82314ffa1d1fa69289cfcdf208ec928a9802300a4194793078f4c61498e31

See more details on using hashes here.

File details

Details for the file aioscam-0.2.1-py3-none-any.whl.

File metadata

  • Download URL: aioscam-0.2.1-py3-none-any.whl
  • Upload date:
  • Size: 99.1 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for aioscam-0.2.1-py3-none-any.whl
Algorithm Hash digest
SHA256 c620b9fe5a0683ea6bdfdd4cfde903200c2f6ece3529858167ef0b608e8b971a
MD5 c2a8cd1e593cd099237158639d7b7e6b
BLAKE2b-256 95cf8e424016e5164b7f2dec7008d328896782eebd6a75e45b66ea8bad725ceb

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page