Bot API VVelcom.online

Боты — это программы, которые общаются с людьми в VVelcom: отвечают на команды, присылают уведомления, принимают заказы, открывают свои мини-приложения прямо в мессенджере. Бот работает на вашем сервере и разговаривает с VVelcom по простому HTTP API.

Создавая бота, вы принимаете Условия для разработчиков ботов и несёте ответственность за бота, его токен, мини-приложение и данные пользователей.

✈️ Формат Telegram Bot API 🧩 Мини-приложения 🔐 Шифрование сообщений ⚡ Webhook и long polling

Уже есть бот в Telegram?

API сделан дружелюбным к Telegram: те же методы, те же поля, тот же адрес вида /bot<токен>/<метод>. Чтобы перенести бота, обычно достаточно получить токен у @VVbotMother и поменять адрес API в вашей библиотеке (grammY, aiogram, node-telegram-bot-api и другие). После переноса проверьте используемые методы по разделу «Чем отличается»: Bot API совместим не со всеми возможностями Telegram. Никакие данные при этом в Telegram не передаются — это только совместимый формат.

Как перенести бота →

Быстрый старт

Хотите начать с готового проекта? Возьмите пример на нужном языке, заполните .env и запустите его по инструкции.

Готовые примеры на GitHub ↗

  1. Найдите @VVbotMother Это бот, который создаёт других ботов. Откройте его в приложении VVelcom — в поиске наберите VVbotMother или перейдите по ссылке:

    Открыть @VVbotMother

  2. Создайте бота Нажмите «Начать» и отправьте /newbot — или нажмите «Открыть» и создайте бота в приложении VVbotMother. Придумайте имя (его видят пользователи) и username — адрес бота.
    Правило для username Латиница, цифры и _, от 6 до 32 символов, начинается с буквы и обязательно заканчивается на vvbot (регистр любой): weather_vvbot, ShopVVbot, my_helper_vvbot.
  3. Скопируйте токен В ответ придёт токен вида vv_AbC123… — нажмите на него, чтобы скопировать. Посмотреть токен снова — команда /token, выпустить новый — /revoke.
    Токен — это пароль бота С ним кто угодно может управлять ботом. Не публикуйте его в коде на GitHub и в чатах; храните в переменной окружения.
  4. Проверьте, что всё работает Откройте в браузере (подставьте свой токен) или выполните в терминале:
    curl https://apibots.vvelcom.online/botvv_ВАШ_ТОКЕН/getMe
    В ответ придёт {"ok":true,"result":{…}} с данными вашего бота.
  5. Напишите код бота Готовый пример на 20 строк — в следующем разделе. Запустите его, откройте своего бота в VVelcom, нажмите «Начать» — и он ответит.

Первый бот

Эхо-бот: отвечает на /start приветствием, а на любое другое сообщение — его же текстом. Он забирает новые сообщения методом getUpdates, поэтому ему не нужен ни публичный сервер, ни домен — можно запустить прямо на своём компьютере.

// bot.mjs — Node.js 18+, без зависимостей.  Запуск: BOT_TOKEN=vv_… node bot.mjs
const API = `https://apibots.vvelcom.online/bot${process.env.BOT_TOKEN}`;

async function call(method, params = {}) {
  const res = await fetch(`${API}/${method}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(params),
  });
  const data = await res.json();
  if (!data.ok) throw new Error(data.description);
  return data.result;
}

let offset = 0;
while (true) {
  // Ждём новые события до 30 секунд (long polling)
  const updates = await call('getUpdates', { offset, timeout: 30 });
  for (const update of updates) {
    offset = update.update_id + 1; // подтверждаем обработанное
    const msg = update.message;
    if (!msg?.text) continue;
    const text = msg.text === '/start'
      ? 'Привет! Я эхо-бот. Напишите мне что-нибудь.'
      : `Вы написали: ${msg.text}`;
    await call('sendMessage', { chat_id: msg.chat.id, text });
  }
}
# bot.py — Python 3.8+, нужен requests (pip install requests).  Запуск: BOT_TOKEN=vv_… python bot.py
import os, requests

API = f"https://apibots.vvelcom.online/bot{os.environ['BOT_TOKEN']}"

def call(method, **params):
    data = requests.post(f"{API}/{method}", json=params, timeout=60).json()
    if not data["ok"]:
        raise RuntimeError(data["description"])
    return data["result"]

offset = 0
while True:
    for update in call("getUpdates", offset=offset, timeout=30):
        offset = update["update_id"] + 1
        msg = update.get("message")
        if not msg or not msg.get("text"):
            continue
        text = ("Привет! Я эхо-бот. Напишите мне что-нибудь."
                if msg["text"] == "/start" else f"Вы написали: {msg['text']}")
        call("sendMessage", chat_id=msg["chat"]["id"], text=text)
// npm i grammy — та же библиотека, что для Telegram, меняется только apiRoot
import { Bot } from 'grammy';

const bot = new Bot(process.env.BOT_TOKEN, {
  client: { apiRoot: 'https://apibots.vvelcom.online' },
});

bot.command('start', (ctx) => ctx.reply('Привет! Я эхо-бот.'));
bot.on('message:text', (ctx) => ctx.reply(`Вы написали: ${ctx.message.text}`));

bot.start();
# pip install aiogram — меняется только адрес сервера
import asyncio, os
from aiogram import Bot, Dispatcher, F
from aiogram.client.session.aiohttp import AiohttpSession
from aiogram.client.telegram import TelegramAPIServer
from aiogram.filters import CommandStart

session = AiohttpSession(api=TelegramAPIServer.from_base("https://apibots.vvelcom.online"))
bot = Bot(os.environ["BOT_TOKEN"], session=session)
dp = Dispatcher()

@dp.message(CommandStart())
async def start(message):
    await message.answer("Привет! Я эхо-бот.")

@dp.message(F.text)
async def echo(message):
    await message.answer(f"Вы написали: {message.text}")

asyncio.run(dp.start_polling(bot))

Дальше можно добавить команды в кнопку «Меню» (setMyCommands), кнопки под сообщениями (inline-клавиатура) и мини-приложение (веб-страница внутри мессенджера).

Как бот получает сообщения

Всё, что происходит с ботом — новое сообщение, нажатие кнопки, добавление в группу, — приходит ему событием (Update). У каждого события свой номер update_id, события идут строго по порядку. Забирать их можно одним из двух способов:

getUpdates (long polling)Webhook
Как работаетБот сам спрашивает «есть что-то новое?» и ждёт ответа до timeout секундМы сами присылаем каждое событие POST-запросом на ваш URL
Что нужноНичего — работает с любого компьютераПубличный HTTPS-адрес
Когда выбратьРазработка, небольшие ботыБоевой режим, много пользователей

Одновременно работает только один способ: пока задан webhook, getUpdates вернёт ошибку 409. Неполученные события хранятся 24 часа.

Webhook за три шага

# 1. Сообщаем адрес (и секрет, по которому вы будете узнавать наши запросы)
curl -X POST https://apibots.vvelcom.online/botvv_ВАШ_ТОКЕН/setWebhook \
  -H 'Content-Type: application/json' \
  -d '{"url": "https://bot.example.com/webhook", "secret_token": "my-secret-123"}'
// 2. Принимаем события — Node.js + Express
import express from 'express';
const app = express();
app.use(express.json());

app.post('/webhook', async (req, res) => {
  // Проверяем, что запрос пришёл от VVelcom
  if (req.get('X-Telegram-Bot-Api-Secret-Token') !== 'my-secret-123') return res.sendStatus(403);
  res.sendStatus(200); // 3. Отвечаем 2xx быстро — иначе событие придёт повторно

  const msg = req.body.message;
  if (msg?.text) await call('sendMessage', { chat_id: msg.chat.id, text: 'Получил!' });
});

app.listen(8443);
  • Адрес — только https, порты 443 или 8443, только публичный хост (не localhost и не локальная сеть). Порт 8443 — просто запасной HTTPS-порт для вашего сервера, к getUpdates он отношения не имеет.
  • Секрет (secret_token) приходит в заголовках X-Messenger-Webhook-Secret (VVelcom) и X-Telegram-Bot-Api-Secret-Token (для Telegram-библиотек) — значение одно и то же.
  • Ответ 2xx нужен в течение 10 секунд. При ошибке, таймауте, 5xx или 429 событие придёт снова: через 1 мин, 5 мин, 15 мин, 1 ч, 6 ч и 24 ч. Ответ 4xx (кроме 429) не повторяется.
  • После 20 ошибок подряд доставка встаёт на паузу, а @VVbotMother присылает вам сообщение. Исправьте сервер и вызовите setWebhook ещё раз.
  • Одно и то же событие может прийти дважды при сбое сети — обрабатывайте события по update_id один раз.

Запросы и ответы

Адрес

https://apibots.vvelcom.online/bot<токен>/<метод>

Токен начинается с vv_, поэтому в адресе получается …/botvv_AbC…/getMe — это тот формат, который собирают библиотеки для Telegram. Можно передавать токен и заголовком: https://apibots.vvelcom.online/bot-api/<метод> + Authorization: Bearer vv_….

Параметры

  • JSON в теле (Content-Type: application/json), форма (x-www-form-urlencoded, multipart/form-data) или query-строка — как удобнее. Файл можно приложить только в sendPhoto / sendVideo.
  • Подходит любой HTTP-метод (GET, POST…), имя метода — без учёта регистра.
  • Вложенные объекты в форме (например, reply_markup) передаются JSON-строкой.

Ответ

// успех
{ "ok": true, "result": { … } }

// ошибка — HTTP-статус совпадает с error_code
{ "ok": false, "error_code": 400, "description": "Bad Request: text is required" }
КодЧто значит
400Неверные параметры — подробности в description
401Неверный или отозванный токен
403Писать в этот чат нельзя (пользователь не начинал диалог, бота удалили из группы)
409getUpdates при включённом webhook
429Слишком много запросов — подождите

Лимиты

  • 30 запросов в секунду на бота;
  • 60 сообщений в минуту в один чат;
  • 20 фото и видео в минуту на бота;
  • текст длиннее 4096 символов уходит несколькими сообщениями — каждое считается отдельно в лимите на чат.

Где бот может писать

  • Личный чат — только после того, как пользователь сам начал диалог: нажал «Начать» или написал боту. Первым написать незнакомому человеку бот не может.
  • Группа — если бота добавили в группу. В поток новых событий бот автоматически получает только обращённые к нему сообщения: упоминание @username_бота, команду /cmd или /cmd@username_бота и ответ (reply) на своё сообщение. Добавление бота в группу разрешает ему работать с доступной историей этой группы, включая поиск через searchChatMessages. Это явный запрос API, а не автоматическая передача всей переписки. После удаления бота из группы доступ прекращается сразу.
  • Канал — если бота добавили в канал. Там бот администратор: публикует посты от имени канала (sendMessage, sendPhoto, sendVideo) и получает каждый новый пост событием channel_post. В chat_id канал можно указать ником: "chat_id": "@my_channel" — как в Telegram. Это работает во всех методах и только для канала, в котором бот состоит; иначе — 403 BOT_CHAT_ACCESS_DENIED.
  • Комментарии к посту — sendMessage, sendPhoto или sendVideo с chat_id канала и comment_to_message_id = id поста. Сообщения в обсуждении, адресованные боту, приходят как message с полем comment_to_message — текстом самого поста (см. события).

Бот не видит телефон, email и список чатов пользователя. Без отдельного разрешения пользователя он не может читать чаты, в которых сам не состоит. О человеке бот видит имя, фамилию, username и фото профиля (photo_url, метод getUserProfilePhotos), если человек показывает фото всем. Его id — случайный и свой для каждого бота, настоящий id в мессенджере бот не видит.

Доступ к боту

Настраивается в мини-приложении @VVbotMother: карточка бота → «Доступ». Проверяет всё платформа — вашему коду ничего делать не нужно.

  • Кто может пользоваться — «Все» или «Только я и выбранные люди» (закрытое тестирование). Людей добавляют по @нику, до 100 человек. Тем, кого нет в списке, в личном чате приходит ответ «бот в закрытом тестировании», а бот не получает ни message, ни bot_started; их упоминания в группах, нажатия кнопок и запуск мини-приложения до бота тоже не доходят.
  • Можно добавлять в группы и каналы — если выключить, бот сразу выходит из группы или канала, куда его добавили, и из всех, где он уже есть. Выход приходит событием my_chat_member со статусом left.
  • Видит всю переписку группы — бот получает событием message каждое сообщение групп, где он состоит, а не только обращения к нему. Аналог выключенного Group Privacy в Telegram. Участники видят под ботом в информации о группе пометку «Видит все сообщения группы».
  • Общение с другими ботами — бот получает сообщения других ботов (from.is_bot: true) в группах и напрямую: написать другому боту можно по нику, sendMessage { chat_id: "@other_vvbot", text }, — личный чат откроется сам, если общение с ботами включено у обоих. Защита от зацикливания: в чате подряд проходит не больше 10 сообщений ботов (счёт обнуляется, когда пишет человек, или через 10 минут тишины) и не больше 20 в минуту на бота-получателя.
  • Политика конфиденциальности — ссылка на страницу о том, какие данные собирает бот. Её видно в карточке бота и в окне перед первым открытием мини-приложения.

Ветки

Включаются владельцем в @VVbotMother: «Настройки бота» → «Ветки» → «Ветки в личном чате». В личном чате с ботом появляется переключатель веток — отдельных разговоров, например по одному на задачу («Общая / ветки / + Ветка»). Сообщения из ветки приходят с message_thread_id и is_topic_message: true; ответить в ветку — передать message_thread_id в методы отправки. Ветками бот управляет методами createForumTopic, editForumTopic, deleteForumTopic и getForumTopics — как темами в Telegram.

Ветки бывают только в личном чате с ботом; в группах message_thread_id не поддерживается. Неизвестная ветка — 400 Bad Request: message thread not found. Название ветки — до 64 символов, веток на чат — до 100; deleteForumTopic не удаляет сообщения, в приложении они остаются в «Общей». getMe возвращает has_topics_enabled и allows_users_to_create_topics. Переключатель «Запретить людям создавать ветки» убирает у людей кнопку «+ Ветка»: ветки создаёт только бот через createForumTopic (как «Disallow users to create new threads» в BotFather).

Ответ по ходу

Пока бот готовит ответ — ждёт нейросеть, распознаёт голосовое, считает, — человек видит, как ответ печатается, а не одно сообщение в конце. Это sendMessageDraft, как в Telegram. Работает в личных чатах и группах (не в каналах), в любом боте, отдельно включать не нужно; ветки для этого тоже не нужны (message_thread_id — только если отвечаете в ветку).

POST sendMessageDraft { "chat_id": "…", "draft_id": 42, "text": "Составляю список:\n• Молоко" }

draft_id — любое ненулевое число (или короткая строка A-Za-z0-9_-), одно на ответ. Каждый вызов с тем же draft_id заменяет текст целиком — передавайте весь текст на данный момент. Черновик — пузырь от бота внизу чата с мигающим курсором; он исчезает, когда бот присылает готовое сообщение (sendMessage и т. п.), при пустом text или через 30 секунд без обновлений. Ничего не сохраняется: в историю и в push черновик не попадает. Не чаще 30 обновлений за 3 секунды на чат (лишние отбрасываются), разумный шаг — раз в 0,5–1 с. Текст — до 4096 символов, разметка (parse_mode, entities) не применяется: оформление — в готовом сообщении.

Каким ИИ отвечать, решаете вы на своём сервере: платформа ключей нейросетей не хранит и сама за бота не отвечает. Типичная схема с потоковым API модели (stream: true): копите текст из кусочков, раз в ~0,7 с отправляйте его в sendMessageDraft, в конце — sendMessage с готовым ответом.

Режимы бота

Три режима, как в Telegram. Владелец включает их в @VVbotMother: «Настройки бота» → «Режимы». getMe отвечает can_connect_to_business (секретарь) и supports_inline_queries (запросы через @).

Режим секретаря. Человек выбирает бота ассистентом: «Профиль → Секретари», меню «⋮» списка чатов или чата. Выбрать можно только бота, которого человек запустил сам. Работает в личных чатах и обычных группах. Бот получает business_connection (подключили или отключили) и business_message (сообщение другого человека в чате; вид как у message плюс business_connection_id). Отвечать надо sendMessage с chat_id и business_connection_id — сообщение уйдёт от имени человека, а он увидит под ним «Ответил бот @имя». Если бот больше не ассистент — 403. Текущее состояние — getBusinessConnection.

Запросы через @ (inline). Человек пишет «@бот запрос» в любом чате. Бот получает inline_query и за 10 секунд отвечает answerInlineQuery (до 50 результатов, cache_time до 3600 с). Выбранный результат человек отправляет от себя с пометкой «via @бот», бот получает chosen_inline_result. Подсказку в поле ввода задаёт владелец.

Гостевой режим. Бота зовут упоминанием @бот в чат, где его нет (личный или группа). Бот видит только это сообщение — оно приходит как message с guest_mode: true. Ответить sendMessage можно в течение 15 минут, до 5 сообщений, без кнопок; ответ уходит от имени позвавшего с пометкой «via @бот».

Настройки бота в группах

Видит всю переписку группы. Бот получает все сообщения групп, где он состоит, а не только упоминания, команды и ответы на его сообщения. Нужно для модерации и сводок; участники группы видят рядом с ботом пометку «видит все сообщения».

Общение с другими ботами. Бот получает сообщения других ботов в группах и напрямую (если включено у обоих). Чтобы боты не отвечали друг другу бесконечно, подряд проходит не больше 10 сообщений ботов — дальше пауза, пока не напишет человек или не пройдёт 10 минут; и не больше 20 в минуту.

Можно добавлять в группы и каналы. Если выключить, бот сразу выйдет из всех групп и каналов, куда его добавят.

Методы

Все методы вызываются одинаково: POST https://apibots.vvelcom.online/bot<токен>/<метод> с JSON-телом.

Сообщения

getMe

Проверяет токен и возвращает информацию о боте. Параметров нет.

sendMessage

Отправляет текстовое сообщение.

ПараметрТипОписание
chat_idstringid чата — берётся из события: message.chat.id. Для канала можно передать @ник
textstringТекст любой длины; длиннее 4096 символов отправляется несколькими сообщениями (кнопки — на последнем)
reply_markupobjectНеобязательно. Кнопки: inline_keyboard, keyboard или remove_keyboard — см. Кнопки
reply_to_message_idstringНеобязательно. Ответить на сообщение (также принимается reply_parameters.message_id)
comment_to_message_idstringТолько для канала: написать комментарий под этим постом
{
  "chat_id": "7eb76e3b-28c4-470d-b799-7c540e4972fc",
  "text": "Привет! Чем могу помочь?",
  "reply_markup": {
    "inline_keyboard": [[{ "text": "Показать меню", "callback_data": "menu" }]]
  }
}

Возвращает отправленное сообщение (Message).

sendPhoto / sendVideo

Отправляют фото или видео — обычное сообщение с вложением. Платформа сама сжимает файл, как приложение сжимает отправляемое людьми: фото — до 1280 px по длинной стороне, JPEG (метаданные EXIF удаляются); видео — до 1280 px, H.264 + AAC в MP4. Для обоих делается размытое превью, файл шифруется и загружается в хранилище.

ПараметрТипОписание
chat_idstringid чата или @ник канала, в котором бот состоит
photo / videostring или файлhttps-ссылка на файл (платформа скачает его сама) или файл в multipart/form-data в поле с этим именем. Фото — до 20 МБ (JPEG, PNG, WebP, GIF, AVIF, TIFF), видео — до 200 МБ и 10 минут
captionstringНеобязательно. Подпись; первые 4096 символов идут под файлом, остаток — следующими сообщениями
reply_to_message_idstringНеобязательно. Ответить на сообщение
comment_to_message_idstringТолько для канала: фото или видео комментарием под постом
{
  "chat_id": "@my_channel",
  "photo": "https://example.com/cat.jpg",
  "caption": "Кот"
}

Возвращает отправленное сообщение с caption и photo либо video. Ссылка — только https, порты 443 и 8443, без редиректов и частных адресов. Пока без reply_markup и альбомов; текст такого сообщения не редактируется (editMessageText вернёт 400). Лимит — 20 фото и видео в минуту на бота.

editMessageText

{ chat_id, message_id, text, reply_markup? } — меняет текст и inline-кнопки своего сообщения. Если reply_markup не передан, кнопки убираются. Удобно, чтобы менять экран «меню» по нажатию кнопки, не засоряя чат новыми сообщениями.

deleteMessage · sendChatAction

deleteMessage { chat_id, message_id } удаляет сообщение бота. sendChatAction принимается для совместимости и ничего не делает.

answerCallbackQuery

{ callback_query_id, text?, show_alert? } — ответ на нажатие inline-кнопки. text (до 200 символов) пользователь увидит подсказкой, а с show_alert: true — окном. Отвечайте в течение ~5 секунд, пока у кнопки крутится индикатор.

События и webhook

getUpdates

{ offset?, limit? (1–100), timeout? (до 50 с), allowed_updates? } — забрать новые события. offset = последний update_id + 1 подтверждает всё, что было раньше: эти события больше не вернутся. С timeout запрос ждёт, пока не появится новое событие.

setWebhook

{ url, secret_token?, drop_pending_updates?, allowed_updates? } — включить доставку событий на ваш адрес. secret_token — 1–256 символов A-Z a-z 0-9 _ -, приходит в заголовке каждого запроса. Повторный вызов снимает паузу доставки. Подробнее — в разделе Как бот получает сообщения.

deleteWebhook

{ drop_pending_updates? } — выключить webhook (например, чтобы перейти на getUpdates).

getWebhookInfo

Состояние webhook: адрес, сколько событий ждёт доставки, последняя ошибка.

{ "ok": true, "result": {
  "url": "https://bot.example.com/webhook", "has_secret_token": true,
  "pending_update_count": 0, "last_error_message": null
} }

Команды и меню

setMyCommands · getMyCommands · deleteMyCommands

Список команд, который пользователи видят в кнопке «Меню» и в подсказках, когда набирают /. До 100 команд; команда — a-z 0-9 _ до 32 символов, описание — до 256.

Через setMyCommands команды видны везде. Чтобы показать команду только в части чатов, настройте её в @VVbotMother («Мои боты» → «Команды») в блоке «Кто видит»: «Личные чаты» (чат с ботом 1 на 1), «Групповые чаты», «Администраторы групп» (команда только для владельца и админов группы) и «Пространства» (чаты внутри обычных пространств; в глобальных чатах настройка не действует). Это только отображение в списке «/» и в «Меню»: команда, введённая вручную, дойдёт до бота в любом случае. Повторный setMyCommands заменяет список и сбрасывает эти настройки.

{ "commands": [
  { "command": "start", "description": "Начать" },
  { "command": "help",  "description": "Помощь" }
] }

setChatMenuButton · getChatMenuButton

Что делает кнопка слева от поля ввода в чате с ботом. { chat_id?, menu_button }, где menu_button:

  • { "type": "commands" } — «Меню» со списком команд;
  • { "type": "web_app", "text": "Открыть", "web_app": { "url": "https://…" } } — кнопка открывает мини-приложение;
  • { "type": "default" } — сбросить.

Без chat_id — для всех чатов, с chat_id — только для этого.

answerWebAppQuery

{ web_app_query_id, result: { type: "article", id, title, input_message_content: { message_text } } } — отправить сообщение в чат, из которого открыли мини-приложение, и закрыть его окно. web_app_query_id — это query_id из initData. Сообщение приходит от имени бота.

Чаты и пространства

Добавление бота в пространство не открывает ему все закрытые чаты: бот видит только чаты, в которых состоит, и публичные чаты (открытые группы и каналы) пространства, в которое его добавили. Доступ проверяется при каждом запросе, а не по ранее полученному списку чатов или сохранённому chat_id: после удаления бота из группы или пространства следующий запрос уже получит отказ. Закрытые группы без бота и чаты других пространств недоступны. Искать людей по всему мессенджеру бот не может, а историю группы он видит по её правилам для новых участников.

Отказ приходит как 403 с полем code: BOT_CHAT_ACCESS_DENIED (нет доступа к чату) или BOT_SPACE_ACCESS_DENIED (нет доступа к пространству). Для чата, которого нет, и чата, который боту видеть нельзя, ответ одинаковый.

МетодЧто возвращает
getChat { chat_id }Чат: id, type, title, description, space_id, member_count. Для участника и для публичного чата
getChatMemberCount { chat_id }Число участников (только чат, где бот состоит)
getChatMember { chat_id, user_id }Участник и его роль: creator | administrator | member | left; user_id — id человека для вашего бота (только чат, где бот состоит)
getChatAdministrators { chat_id }Администраторы (только чат, где бот состоит)
getChatMembers { chat_id, query?, offset?, limit? }Участники (люди — с именем, фамилией и username под своим id для вашего бота; поиск по имени работает среди ботов; только чат, где бот состоит)
searchChatMessages { chat_id, query, limit?, offset? }Явный поиск по доступной боту истории чата: где бот состоит, либо в публичном (открытом) чате пространства, в которое его добавили. Иначе 403 BOT_CHAT_ACCESS_DENIED. До 20 поисков в минуту. Новые сообщения без обращения к боту при этом не становятся событиями.
readUserChat { user_id, chat_id, query?, limit?, offset?, from_user_id? }Прочитать чат, где бота нет, с разрешения человека. Первый вызов отправляет человеку вопрос (в его чате с ботом) и отвечает 403 с parameters.request_id; после «Разрешить» придёт событие chat_access, и повторный вызов вернёт { messages, next_offset }. Доступ — на 24 часа, только к этому чату и только к тому, что видит сам человек. Не больше 3 вопросов в час одному человеку.
sendSpaceAnnouncement { space_id, text }Системное уведомление для всего пространства. Доступно боту, добавленному в пространство; права администратора не нужны.
getSpace { space_id }Пространство: название, описание, число участников и групп
getSpaceMembers { space_id, query? }Участники пространства (только пространство, в котором бот состоит)
getSpaceChats { space_id, query? }Группы и каналы пространства, которые видит бот: где он состоит и открытые. Закрытые группы без бота не показываются

События (Update)

Каждое событие — объект с update_id и одним из полей ниже.

message — новое сообщение

{ "update_id": 1041, "message": {
  "message_id": "f5df…",
  "chat": { "id": "7eb7…", "type": "private" },
  "from": { "id": "c91e…", "is_bot": false, "first_name": "Анна", "last_name": "Иванова", "username": "anna", "language_code": "ru" },
  "text": "/help",
  "entities": [{ "type": "bot_command", "offset": 0, "length": 5 }],
  "date": 1758794460
} }

Команды, обычный текст и нажатия кнопок reply-клавиатуры — всё приходит как message. В группе у chat тип group и есть title.

Контекст сообщения: на что ответили и под каким постом

Чтобы бот понимал «что это?» или «у кого они его заказали?», вместе с сообщением приходит то, к чему оно относится:

ПолеКогда естьЧто внутри
reply_to_messageпользователь ответил (reply) на сообщениетекст этого сообщения: { id, chat, text?, entities?, attachment_count?, from_bot, created_at }
comment_to_messageсообщение написано в обсуждении постатекст поста в том же виде, chat.type: "channel"
  • Событие приходит боту только если обращение адресовано ему (если не включено «Видит всю переписку группы»): упоминание @username_бота, команда или ответ на сообщение бота. Ответ на сообщение другого человека без упоминания бота событием не становится.
  • Пользователь может ответить на любое сообщение, в том числе чужой комментарий, и упомянуть бота («@бот, что скажешь?»): бот получит и этот текст, и в reply_to_message — текст сообщения, на которое ответили.
  • from_bot равен true, если ответили на сообщение самого бота, иначе false.
  • Автор не передаётся. В reply_to_message и comment_to_message нет from, имени, ника и id автора: только текст. Исключение — ответ на сообщение самого бота (там from — сам бот).
  • Ответить можно только на сообщение из того же чата: ссылка на сообщение из другого чата игнорируется.
  • comment_to_message приходит, только если бот состоит в самом канале; если пост удалён или бот не участник канала, поля нет.
  • Вложения не передаются: бот видит подпись и attachment_count. Если сообщение удалено или не читается, поле просто отсутствует, событие не теряется.
{ "update_id": 1042, "message": {
  "message_id": "c3d1…",
  "chat": { "id": "9b02…", "type": "group", "comments_for": { "chat_id": "44ab…", "message_id": "26a1…" } },
  "text": "@mill_vvbot подскажи, у кого они его заказали?",
  "reply_to_message": { "message_id": "7f10…", "text": "Первый Gripen E бразильской сборки совершил полёт", "from_bot": false },
  "comment_to_message": { "message_id": "26a1…", "text": "Первый Gripen E бразильской сборки…", "from_bot": false }
} }

callback_query — нажата inline-кнопка

{ "update_id": 1042, "callback_query": {
  "id": "0c6a…",
  "from": { "id": "c91e…", "is_bot": false, "first_name": "Анна", "last_name": "Иванова", "username": "anna", "language_code": "ru" },
  "message": { "message_id": "4f71…", "chat": { "id": "7eb7…", "type": "private" } },
  "data": "menu"
} }

Ответьте на него answerCallbackQuery, иначе у кнопки будет крутиться индикатор.

Другие события

  • chat_access — человек ответил на запрос readUserChat: granted или denied.
  • my_chat_member — бота добавили в группу или канал либо удалили оттуда.
  • channel_post — новый пост в канале, где бот администратор.
  • bot_started — пользователь впервые нажал «Начать». Сразу после него придёт message с /start, так что обычно достаточно обрабатывать только его.

Кнопки

Inline-кнопки под сообщением

Бывают трёх видов: callback_data (нажатие присылает боту callback_query), url (открывает сайт) и web_app (открывает мини-приложение).

// Отправляем меню с кнопками
await call('sendMessage', {
  chat_id, text: 'Что будем делать?',
  reply_markup: { inline_keyboard: [
    [{ text: '📦 Мои заказы', callback_data: 'orders' }, { text: '❓ Помощь', callback_data: 'help' }],
    [{ text: '🛒 Открыть магазин', web_app: { url: 'https://shop.example.com' } }],
    [{ text: '🌐 Наш сайт', url: 'https://example.com' }],
  ] },
});

// Обрабатываем нажатие
const cq = update.callback_query;
if (cq?.data === 'orders') {
  await call('answerCallbackQuery', { callback_query_id: cq.id });
  await call('editMessageText', { chat_id: cq.message.chat.id, message_id: cq.message.message_id, text: 'У вас 2 заказа' });
}
  • callback_data — до 64 байт. Кладите туда короткий код действия, а не секреты и личные данные.
  • До 20 рядов, до 8 кнопок в ряду, текст кнопки — до 64 символов.

Reply-клавиатура вместо обычной

Кнопки появляются на месте клавиатуры; нажатие отправляет боту текст кнопки как обычное сообщение. Работает в личных чатах.

reply_markup: {
  keyboard: [['Мой профиль', 'Помощь'], [{ text: 'Заполнить анкету', web_app: { url: 'https://…' } }]],
  resize_keyboard: true,
  input_field_placeholder: 'Выберите действие',
}
// убрать клавиатуру: reply_markup: { remove_keyboard: true }

Мини-приложения

Мини-приложение — это ваша веб-страница, которая открывается прямо в VVelcom, без перехода в браузер: магазин, запись к врачу, анкета, игра. Страница знает, кто её открыл, умеет показывать кнопки внизу окна, вибрацию, всплывающие окна и подстраивается под тему приложения. Живой пример — приложение @VVbotMother (кнопка «Открыть» в чате с ней).

Как открыть

  • Главное приложение — кнопка «Открыть» в профиле бота и в списке чатов, а также ссылка https://uvvel.com/@username_бота?startapp=параметр. Задаётся в @VVbotMother командой /setmainapp.
  • Кнопка меню слева от поля ввода — setChatMenuButton или /setmenubutton.
  • Inline-кнопка web_app под сообщением.
  • Кнопка reply-клавиатуры web_app — из такого окна можно вернуть данные боту через sendData.

Параметр запуска для раундов и уровней. Приложение получает start_param в подписанном initData. Его можно передать ссылкой ?startapp=… или прямо в кнопке: { "text": "Играть: средний, 5 минут", "web_app": { "url": "https://…", "start_param": "sudoku_medium_300" } }. Параметр берётся из копии кнопки на платформе, игрок не может его подменить. До 512 символов: латиница, цифры, _ и -.

Минимальная страница

<!doctype html>
<html>
<head>
  <meta name="viewport" content="width=device-width, initial-scale=1" />
  <script src="https://apibots.vvelcom.online/bot-platform/js/vvelcom-web-app.js"></script>
</head>
<body style="background: var(--tg-theme-bg-color); color: var(--tg-theme-text-color)">
  <h1 id="hello"></h1>
  <script>
    const app = window.VVelcom.WebApp;   // он же window.Telegram.WebApp
    app.ready();
    document.getElementById('hello').textContent =
      'Привет! Ваш id для этого бота: ' + app.initDataUnsafe.user?.id;

    app.MainButton.setText('Оформить заказ').show().onClick(() => {
      app.HapticFeedback.notificationOccurred('success');
      app.showAlert('Заказ оформлен!');
    });
  </script>
</body>
</html>

Официальный telegram-web-app.js тоже работает — протокол тот же.

Что умеет страница

ВозможностьКак
Кто открыл и откудаinitData, initDataUnsafe.user, start_param
Кнопки внизу окнаMainButton, SecondaryButton
«Назад» вместо «Закрыть»BackButton
Всплывающие окнаshowPopup, showAlert, showConfirm
ВибрацияHapticFeedback
Цвета и темаthemeParams, CSS-переменные --tg-theme-*, setHeaderColor
Размер окнаexpand(), requestFullscreen(), viewportHeight
ХранилищеCloudStorage — до 1024 ключей на пользователя
Вернуть данные ботуsendData() или answerWebAppQuery с вашего сервера
Закрыть окноclose()

Проверка пользователя на сервере

initDataUnsafe удобно показывать, но доверять ему нельзя. Отправляйте на свой сервер initData и проверяйте подпись — алгоритм тот же, что у Telegram, ключ выводится из токена вашего бота:

import crypto from 'node:crypto';

function checkInitData(initData, botToken, maxAgeSeconds = 86400) {
  const params = new URLSearchParams(initData);
  const hash = params.get('hash');
  params.delete('hash');
  const dataCheckString = [...params].sort(([a], [b]) => (a < b ? -1 : 1))
    .map(([k, v]) => `${k}=${v}`).join('\n');
  const secret = crypto.createHmac('sha256', 'WebAppData').update(botToken).digest();
  const expected = crypto.createHmac('sha256', secret).update(dataCheckString).digest('hex');
  if (expected !== hash) return null;
  if (Date.now() / 1000 - Number(params.get('auth_date')) > maxAgeSeconds) return null;
  return JSON.parse(params.get('user')); // { id, first_name, last_name, username, language_code, allows_write_to_pm }
}

Готовые библиотеки проверки initData для Telegram тоже подходят.

Примеры использования

В репозитории подготовлен каталог bot-examples: каждый пример — отдельный небольшой проект с README, шаблоном .env.example без секретов и командами запуска.

Эхо-бот

Минимальный бот на Python и JavaScript: получение токена, getUpdates и первый ответ через sendMessage.

ИИ-бот

Подключите подходящую AI-модель или облачную платформу, добавьте свои данные, базу знаний и инструменты — от простого помощника до полноценного агента.

Telegram → VVelcom

Кросспостинг текстовых публикаций из Telegram-канала в канал VVelcom с проверкой исходного и целевого каналов.

Начните с эхо-бота Если он отвечает локально, токен и получение событий настроены правильно. После этого переходите к ИИ или интеграциям.

Переезд с Telegram

  1. Создайте бота в @VVbotMotherUsername должен заканчиваться на vvbot. Команды, описание и мини-приложение настраиваются так же, как у BotFather.
  2. Поменяйте адрес APIВ библиотеке укажите сервер https://apibots.vvelcom.online и новый токен.
  3. Проверьте сценарииЗапустите бота и проверьте команды, кнопки и обработку событий. Неподдерживаемые методы Telegram нужно заменить возможностями из этой документации.
// grammY
new Bot(TOKEN, { client: { apiRoot: 'https://apibots.vvelcom.online' } });
// node-telegram-bot-api
new TelegramBot(TOKEN, { polling: true, baseApiUrl: 'https://apibots.vvelcom.online' });
// Telegraf
new Telegraf(TOKEN, { telegram: { apiRoot: 'https://apibots.vvelcom.online' } });
# aiogram 3
session = AiohttpSession(api=TelegramAPIServer.from_base("https://apibots.vvelcom.online"))
bot = Bot(TOKEN, session=session)
# python-telegram-bot
app = Application.builder().token(TOKEN).base_url("https://apibots.vvelcom.online/bot").build()

Что работает так же

  • методы из этой страницы и их параметры;
  • объекты Update, Message, User, Chat, CallbackQuery;
  • getUpdates и webhook с заголовком X-Telegram-Bot-Api-Secret-Token;
  • кнопки callback_data, url, web_app, reply-клавиатура;
  • мини-приложения: telegram-web-app.js, initData и её проверка.

Чем отличается

  • Все id (chat.id, from.id, message_id) — строки, а не числа. Большинство библиотек это не замечают; если вы храните id в базе как число — поменяйте тип на строку. update_id — число, как в Telegram.
  • Из медиа бот отправляет только фото и видео (sendPhoto, sendVideo: без кнопок и альбомов); получать файлы и отправлять документы, аудио и голосовые пока нельзя. Нет inline-режима и платежей. parse_mode принимается, но текст показывается без разметки.
  • answerWebAppQuery отправляет сообщение от имени бота.

Команды @VVbotMother

Всё это можно делать и в приложении @VVbotMother — кнопка «Открыть» в чате с ней. Команда без имени бота спросит, какого бота настроить; можно указать сразу: /setname @weather_vvbot.

КомандаЧто делает
/newbotСоздать бота и получить токен
/mybotsВаши боты и их настройки
/setnameИмя бота
/setdescription«Что умеет этот бот?» — текст в пустом чате перед «Начать»
/setabouttext«О боте» — короткий текст в профиле
/setuserpicФото бота
/setcommandsКоманды для кнопки «Меню»
/token · /revokeПоказать токен · выпустить новый (старый сразу перестаёт работать)
/myapps · /newapp · /listapps · /deleteappМини-приложения ботов
/setmenubutton · /setmainappКнопка меню и главное мини-приложение
/deletebotУдалить бота
/cancelОтменить текущее действие

Создать бота в @VVbotMother