maxapi-lite
Легковесный асинхронный клиент MAX Bot API, совместимый с aiohttp 3.8.x.
Пакет нужен, когда в проекте уже зафиксирован старый aiohttp — например, рядом живёт
aiogram 2.x (aiohttp<3.9), а официальный клиент maxapi требует aiohttp>=3.12.
Зависимости — только aiohttp>=3.8 и pydantic>=2.
Lightweight async client for the MAX messenger Bot API that works with aiohttp 3.8, so it can share an environment with aiogram 2.x.
Установка
pip install maxapi-lite
Быстрый старт
import asyncio
from maxapi_lite import Bot, ParseMode
async def main():
bot = Bot(token="YOUR_MAX_TOKEN", parse_mode=ParseMode.HTML) # или переменная окружения MAX_BOT_TOKEN
# Кнопка-ссылка
kb_attachment = bot.build_link_button_attachment(
text="Открыть MiniApp",
url="https://example.com/app?startapp=123",
)
# Отправка фото + кнопки
result = await bot.send_message_with_media(
chat_id=-1, # Демонстрационный ID — замените на ID своего чата
text="<b>Розыгрыш</b>",
media_type="photo",
file_path="banner.jpg", # или media_url="https://..."
attachments=[kb_attachment],
)
# Извлечение mid и закрепление
mid = bot.extract_message_id(result)
if mid:
await bot.pin_chat_message(chat_id=-1, message_id=mid)
await bot.close_session()
asyncio.run(main())
Long polling
marker = None
while True:
data = await bot.get_updates(timeout=30, marker=marker)
for update in data.get("updates", []):
...
marker = data.get("marker", marker)
Можно передать types=["message_created", "message_callback"]. Библиотека оставляет
HTTP-таймауту запас не менее 10 секунд относительно timeout поллинга; явно
отключённые ограничения HTTP не включаются обратно. Допустимый timeout — 0–90,
limit — 1–1000. MAX рекомендует использовать Webhook для production: Long Polling
ограничен скоростью и сроком хранения событий (документация).
Подключение и TLS
По умолчанию запросы идут на https://platform-api2.max.ru. Для другого сервера
передайте base_url. Настройки доступны как в Bot, так и в MaxApiClient:
import ssl
import aiohttp
from maxapi_lite import Bot
tls = ssl.create_default_context()
# При необходимости добавьте доверенный сертификат в окружении приложения:
# tls.load_verify_locations(cafile="/path/to/trusted-ca.pem")
bot = Bot(
ssl_context=tls, # токен берётся из MAX_BOT_TOKEN
timeout=aiohttp.ClientTimeout(total=60),
transfer_timeout=aiohttp.ClientTimeout(
total=None, connect=30, sock_connect=30, sock_read=120,
),
)
API по умолчанию использует total=300. У upload/download нет общего ограничения
времени, но по умолчанию установлены таймауты соединения 30 с и чтения 120 с.
Вместо ssl_context можно передать connector=aiohttp.TCPConnector(ssl=tls);
одновременно эти параметры передавать нельзя. Внешний connector закрывает
вызывающий код. Собственные сессии и connector библиотека закрывает через
await bot.close_session(); вызывайте его в finally.
Входящие файлы и видео
Извлекайте URL из входящего события и передавайте его в download_file:
from maxapi_lite import Bot
async def save_incoming_video(bot: Bot, update: dict, destination: str) -> int:
for attachment in bot.extract_attachments(update):
if attachment.get("type") == "video":
url = (attachment.get("payload") or {}).get("url")
if url:
return await bot.download_file(url, destination)
return 0
download_file(url, dest_path, *, chunk_size=1<<20, max_retries=3) возвращает число
сохранённых байтов. Скачивание идёт чанками через отдельную сессию без токена
бота, включая переходы по редиректам. max_retries=3 — до трёх повторов после
первой попытки. При обрыве выполняется докачка через Range/If-Range, если сервер
предоставил сильный ETag или Last-Modified; без валидатора скачивание начинается
заново. Ответ 200 вместо 206 также перезаписывает временный файл с начала.
Размер сверяется с Content-Length/Content-Range, когда они доступны.
Существующий файл назначения заменяется атомарно после успешного скачивания. При ошибке или отмене временный файл удаляется; между вызовами докачка не сохраняется. Родительский каталог назначения должен существовать.
Для скачивания по готовому payload.url токен видео не нужен.
await bot.get_video(video_token) отдельно получает метаданные через API;
urls в ответе может быть None.
По наблюдениям, приведённым в задании ClipWizard: входящее video перекодируется
MAX и URL живёт около 24 часов; file сохраняет исходные байты и URL живёт около
30 дней; изображение может возвращаться в webp. Это наблюдения, а не гарантии
SDK: скачивайте входящие файлы своевременно. Ошибка HTTP 403 возвращается без
автоматических повторов; приложение может запросить свежую ссылку через MAX API,
если такая возможность доступна для вложения.
Загрузка и отправка результата
await bot.send_message_with_media(
chat_id=-1, # замените на свой ID
media_type="video",
file_path="result.mp4",
text="Видео готово",
wait_attachments=True,
attachment_wait_timeout=60,
)
Файл передаётся потоком в multipart-поле data. Для video/audio библиотека
сохраняет токен из ответа /uploads, если сервер заливки не вернул собственный.
Токен вложения используется при отправке сообщения; передавать его вручную при
загрузке локального файла не требуется.
При wait_attachments=True отправка или редактирование повторяется только после
ошибки attachment.not.ready. Паузы растут 1, 2, 4, 8, 16 с, затем остаются 16 с;
запросы и паузы ограничены общим бюджетом attachment_wait_timeout (60 с по
умолчанию). Эти параметры работают у send_message, edit_message и обоих
методов *_with_media. По умолчанию ожидание выключено. Истечение бюджета после
определённого ответа not.ready даёт AttachmentNotReady; таймаут запроса с
неизвестным результатом остаётся asyncio.TimeoutError.
Размер локального файла проверяется до запроса /uploads:
| Тип | Максимум в байтах |
|---|---|
| image | 50 000 000 |
| video | 250 000 000 |
| audio | 256 000 000 |
| file | 4 000 000 000 |
Используются консервативные десятичные МБ/ГБ. При превышении возникает
FileTooLarge с полями size и limit. MAX также ограничивает изображения
7680×7680 px и аудио 60 минутами; поддерживает MP4/MOV/MKV/WEBM для video.
Проверка содержимого, разрешения и длительности выполняется сервером; локально
библиотека не декодирует медиа (лимиты MAX).
Resumable upload пока не реализован; после обрыва заливку нужно запускать заново.
Клавиатуры и callback
from maxapi_lite import CallbackButton, LinkButton
keyboard = bot.build_keyboard([
[CallbackButton(text="Обработать", payload="process")],
[LinkButton(text="Открыть сайт", url="https://example.com")],
])
await bot.send_message(chat_id=-1, text="Выберите действие", attachments=[keyboard])
await bot.send_callback(
callback_id="CALLBACK_ID_FROM_UPDATE",
notification="Готово",
message={"text": "Обработка запущена", "attachments": []},
)
Модели кнопок сериализуются с обязательным полем type. build_keyboard
принимает ряды моделей или словарей и возвращает одно вложение inline_keyboard.
send_callback может отправлять уведомление, обновлённое сообщение или оба.
Ошибки и повторы
MaxApiError.code — числовой HTTP status, MaxApiError.api_code — строковый код
ошибки MAX, если он есть. FileTooLarge, AttachmentNotReady, RateLimited
наследуют MaxApiError; InvalidToken сохраняет прежнее поведение.
При HTTP 429 возникает RateLimited; поле retry_after содержит задержку в
секундах из Retry-After либо None. 429 автоматически не повторяется. MAX
указывает общий предел 30 rps, а для /answers — не более двух ответов в секунду
в один диалог/чат/канал; очередь и регулирование частоты остаются в приложении
(uploads,
answers).
Сетевые ошибки отправки сообщений автоматически не повторяются: после обрыва сервер уже мог принять сообщение, и повтор способен создать дубликат.
Методы Bot
| Группа | Методы |
|---|---|
| Бот и обновления | get_me, get_updates, extract_attachments |
| Сообщения | send_message, edit_message, delete_message, get_message |
| Медиа | upload_file, download_file, get_video, create_media_attachment, send_message_with_media, edit_message_with_media |
| Закрепление | pin_chat_message, pin_from_response, unpin_chat_message |
| Чаты | get_chat_by_id, get_chat_member, get_chat_members_batch, get_list_admin_chat |
| Callback | send_callback |
| Утилиты | extract_message_id, build_keyboard, build_link_button_attachment |
Методы возвращают «сырые» dict из ответа API. Ошибки API поднимаются как MaxApiError
(с полем code), ошибка авторизации — как InvalidToken.
Поддерживаемые media_type
photo,animation,image→ загрузка какimagevideoaudiodocument,file
Примечания
chat_id/user_idпередаются query-параметрами, как требует MAX API.edit_message(..., attachments=[])явно очищает вложения;attachments=Noneоставляет их как есть.- Формат (
parse_mode) применяется к редактированию только если переданtext. - Для upload используется multipart-поле
data.
Разработка
pip install -e ".[test]"
pytest
Релиз: поднять __version__ в src/maxapi_lite/__init__.py, дополнить CHANGELOG.md,
создать GitHub Release с тегом vX.Y.Z — workflow publish.yml соберёт пакет и опубликует его на PyPI.
Лицензия
MIT
Metadata
Release files for maxapi-lite 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| maxapi_lite-0.3.0.tar.gz | 26.0 kB | With provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| maxapi_lite-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 47.0 kB
Release files / maxapi_lite-0.3.0.tar.gz
| Download URL | maxapi_lite-0.3.0.tar.gz |
|---|---|
| Size | 26.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
80eb2560d91ef7f0abfe03afc9eb2e78f47e9362f997d06eab38ac96d066e797
|
|
BLAKE2b-256 checksum How to use checksums |
22dc15ad198668942e7d618eb79617eccbcdb9ee6b32351965fda5b7558ae62b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logRelease files / maxapi_lite-0.3.0-py3-none-any.whl
| Download URL | maxapi_lite-0.3.0-py3-none-any.whl |
|---|---|
| Size | 21.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
db342793dfc54cc0e5217f77a332c2dbfca7318242c3b82a50fee2351f3a15b5
|
|
BLAKE2b-256 checksum How to use checksums |
0c11c3e3b51d62018ca463f78284f57dd5dba7c28a769ee00e5e713d0d4d288b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logSecurity for maxapi-lite 0.3.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for maxapi_lite-0.3.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 15, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.