python-vk-bot
An asynchronous framework for VK community bots, inspired by python-telegram-bot. Supports VK API 5.199.
Installation
uv add python-vk-bot
For Python 3.9–3.13, use the compat/py39 branch:
uv add git+https://github.com/fomenko-ai/python-vk-bot.git --branch compat/py39
See Python compatibility for branch differences, optional dependencies and installation with pip.
Install from this checkout
uv sync --locked
For the optional Callback HTTP receiver:
uv sync --locked --extra callback
Examples
See the examples guide for setup, required events and run commands.
| Example | Description |
|---|---|
| Echo bot | Reply to text messages using Bots Long Poll |
| Keyboards | Ordinary text buttons and inline callback buttons with message editing |
| Interactive map | Generate, upload and replace a PNG using navigation buttons |
| Callback receiver | Receive events through an ASGI application |
Long Poll bot
Enable Bots Long Poll and the message_new event in the community settings. Configure
its event version to match the supported API schema. Supply a community token with the
required permissions through the environment; messaging is subject to VK's conversation
and permission rules.
import asyncio
from python_vk_bot import Application, Bot, BotSettings, Context, MessageHandler, Update, filters
async def echo(update: Update, context: Context) -> None:
message = update.message
if message is not None:
await context.bot.send_message(message.peer_id, message.text)
async def main() -> None:
settings = BotSettings()
bot = Bot(settings.token, api_version=settings.api_version, timeout=settings.timeout)
app = Application(bot, settings.group_id)
app.add_handler(MessageHandler(echo, predicate=filters.TEXT))
await app.run_polling(wait=settings.polling_wait)
asyncio.run(main())
With VK_TOKEN and VK_GROUP_ID already set, run the included example:
uv run python examples/echo.py
run_polling() is awaitable. Cancellation closes owned resources. Handlers run
sequentially, with the first match in each numeric group. Context exposes bot,
user_data, peer_data and bot_data. Use MessageEventHandler for button events,
filters.LOCATION for messages containing geo, and CommandHandler for /command tokens.
Settings
Import BotSettings from python_vk_bot or python_vk_bot.settings. It uses
pydantic-settings to load and validate configuration when you create an instance.
Importing the module does not read configuration or require credentials.
| Field | Environment variable | Default |
|---|---|---|
token |
VK_TOKEN |
Required, nonempty SecretStr |
group_id |
VK_GROUP_ID |
Required, positive integer |
api_version |
VK_API_VERSION |
"5.199" |
timeout |
VK_TIMEOUT |
40.0 seconds, positive and finite |
polling_wait |
VK_POLLING_WAIT |
25 seconds, between 1 and 90 |
Use environment variables directly:
from python_vk_bot import BotSettings
settings = BotSettings() # Read VK_* variables; no automatic .env loading.
Alternatively, opt into a dotenv file and override a value for this instance:
from pathlib import Path
from python_vk_bot import BotSettings
settings = BotSettings(_env_file=Path(".env"), timeout=15.0)
Explicit constructor values take precedence over environment variables, which take
precedence over dotenv values and field defaults. Unrelated dotenv entries are ignored,
so a project may share its .env with other components. Unknown constructor fields are
also ignored; use extra="forbid" in a subclass if you prefer strict configuration.
Settings only contain configuration: pass their values to Bot, Application and
run_polling explicitly as shown above. Keep real tokens and .env out of Git.
Extend the class with your project's fields:
from pathlib import Path
from pydantic import Field
from python_vk_bot import BotSettings
class ProjectSettings(BotSettings):
admin_ids: list[int] = Field(default_factory=list)
debug: bool = False
settings = ProjectSettings(_env_file=Path(".env"))
These fields read VK_ADMIN_IDS (a JSON array such as [123, 456]) and VK_DEBUG
(for example, true). Override model_config with SettingsConfigDict(env_prefix="MYBOT_")
to use another prefix. A field with Field(validation_alias="DATABASE_URL") instead reads
that exact variable name, without the prefix. Token values remain SecretStr and can be
passed directly to Bot.
Bot without polling
async with Bot(token) as bot:
user = await bot.get_user_info(user_id)
An injected httpx.AsyncClient remains caller-owned. Methods cover uploading, sending,
editing, deleting, forwarding, fetching a message/user, answering message events, and obtaining Long Poll
connection data. Bot.request(method, parameters) exposes raw JSON results for additional
VK methods; nested request parameters must be JSON encoded explicitly.
Messages use peer_id; Message exposes both id and conversation_message_id.
send_message returns an integer message ID and accepts an optional nonzero int32
random_id. Sends are never retried automatically. edit_message accepts exactly one
message identifier and maps conversation_message_id to VK's cmid parameter.
Callback API
The Callback example extends the same base settings with its required secrets. For example, to construct a receiver from the environment:
from pydantic import Field, SecretStr
from python_vk_bot import Application, Bot, BotSettings, Callback
class CallbackSettings(BotSettings):
callback_secret: SecretStr = Field(min_length=1, repr=False)
callback_confirmation: SecretStr = Field(min_length=1, repr=False)
settings = CallbackSettings()
bot = Bot(settings.token, api_version=settings.api_version, timeout=settings.timeout)
application = Application(bot, settings.group_id)
# Register your handlers before starting the ASGI application.
callback = Callback(
application,
secret=settings.callback_secret,
confirmation_code=settings.callback_confirmation,
)
asgi_app = callback.create_app()
Set VK_TOKEN, VK_GROUP_ID, VK_CALLBACK_SECRET, and VK_CALLBACK_CONFIRMATION, then:
uv run --extra callback uvicorn examples.callback:create_app --factory
Expose /callback through your HTTPS deployment and configure the same secret in VK.
ASGI lifespan manages startup/shutdown. Callback.handle() is also available for other
HTTP frameworks, provided the caller manages Application's async lifecycle.
Confirmation returns the configured confirmation code. Ordinary events return ok only
after successful processing. A bounded in-memory cache skips successful duplicates.
Partial handler failures, restarts and multiple workers can repeat side effects; this
is not a durable queue or an exactly-once processing guarantee. See the architecture
for delivery limitations and resource limits.
Media and location
With an initialized bot:
from pathlib import Path
photo = await bot.upload_photo(peer_id, Path("map.png"))
message_id = await bot.send_message(peer_id, "Map", attachment=photo, keyboard=keyboard)
document = await bot.upload_document(peer_id, Path("report.pdf"))
await bot.send_message(peer_id, "Report", attachment=document)
await bot.edit_message_media(
peer_id,
new_png_bytes,
message_id=message_id,
caption="Updated map",
keyboard=keyboard,
filename="map.png",
)
Uploads accept bytes, Path and binary file objects. Files are read off the event loop
and buffered in memory; use inputs that fit comfortably in memory. Existing attachment
identifiers can be passed directly to send/edit methods, and a saved photo passed to
edit_message_media skips uploading. Supply the desired caption and keyboard explicitly;
there is no automatic fallback send when editing fails.
Incoming message.attachments remain raw dictionaries. Use message.typed_attachments
for PhotoAttachment, DocumentAttachment, VideoAttachment, AudioMessageAttachment
or a generic Attachment preserving unknown fields. With message.geo is not None,
read message.geo.coordinates.latitude and .longitude; filters.LOCATION selects
these messages. Incomplete coordinate objects fail validation.
See the media API guide for incoming attachment examples,
deletion, errors and VK restrictions, and interactive_map.py
for a PNG grid with navigation buttons. Enable message_new and message_event, then run:
uv run python examples/interactive_map.py
The media API has network-free regression tests. Actual replacement of a photo in an existing VK message has not yet been verified with a live token; an explicitly enabled integration test is provided.
Agent Skills
The bundled telegram-to-vk Agent Skill helps AI coding agents migrate
python-telegram-bot applications to VK using python-vk-bot.
After installing a package version containing the skill, run from your bot project's root:
uvx library-skills
Select telegram-to-vk and the .agents/skills target for a compatible AI coding agent.
The skill adds no runtime dependencies and does not change the framework's behavior.
See Agent Skills for package installation, installing from a local
checkout, and usage examples.
Documentation
Metadata
Release files for python-vk-bot 0.2.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 | Actions |
|---|---|---|---|---|
| python_vk_bot-0.2.0.tar.gz | 30.0 kB | Without provenance | Details for python_vk_bot-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| python_vk_bot-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for python_vk_bot-0.2.0-py3-none-any.whl |
Total release size: 63.2 kB
Release files / python_vk_bot-0.2.0.tar.gz
| Download URL | python_vk_bot-0.2.0.tar.gz |
|---|---|
| Size | 30.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
15150b36ffa99c0c8eb12838763c411d4068af818b9dc7165d59c2a947466370
|
|
BLAKE2b-256 checksum How to use checksums |
56650696703c0d1eb4fbe29180b297871bca1e55d1bcab2327fcd000ccee999c
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.10","id":"oracular","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / python_vk_bot-0.2.0-py3-none-any.whl
| Download URL | python_vk_bot-0.2.0-py3-none-any.whl |
|---|---|
| Size | 33.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7edf10f577f34a72d32867f24b85405d3342ebdfd93dc9689b4806b75ba9a75d
|
|
BLAKE2b-256 checksum How to use checksums |
070f2ce5a22aa445b2a5c1f3e42186922e52f3b3ac8f9baa1b23246d3b1ac3d4
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.17 {"installer":{"name":"uv","version":"0.11.17","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.10","id":"oracular","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for python-vk-bot 0.2.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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A 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.