SMeetBot API

SMeet Bot API

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

Мини-приложение является веб-страницей автора бота, которая открывается внутри SMeet в окне поверх чата с ботом. Бот открывает её кнопкой, а форма, которую человек отправил из неё, приходит боту событием в той же очереди, что и сообщения.

Что такое мини-приложение#

У бота может быть одно мини-приложение. Владелец создаёт его в «Моих ботах» (экран открывает SMeet BotFather), указывает адрес рабочей и тестовой версии на своём HTTPS-сервере и отправляет на проверку; в рабочей среде работает только проверенная конфигурация. Перед каждым запуском SMeet показывает человеку, кто сделал мини-приложение и что оно получит, а перед каждой формой, которую оно отправляет боту, просит человека подтвердить отправку.

Страница и её сервер принадлежат автору. Программе бота не нужно их обслуживать: она получает то, что отправил человек, и отвечает в чате, как на любое сообщение.

Страница, вход человека, сервер автора и публикация описаны в документации SMeet Mini Apps: SDK, Вход, Ваш сервер и Публикация. Здесь описано то, что видит бот.

getMe сообщает, работают ли на этом сервере мини-приложения, и описывает мини-приложение бота:

JSON
{
  "capabilities": ["chat_context", "access_revisions", "message_revisions", "initiator_conditions",
                   "strict_conditions", "mini_apps"],
  "mini_app": {"id": "1000", "status": "active", "published": true}
}
  • mini_apps в capabilities означает, что кнопка mini_app и событие mini_app_submission сейчас работают на этом сервере. Если значения нет (старый сервер или мини-приложения выключены на платформе), отправляйте тот же текст без кнопки.
  • mini_app есть, пока у бота есть мини-приложение. status равен active, paused_by_owner или blocked_by_admin; published говорит, работает ли проверенная конфигурация. id совпадает с app_id отправок этого бота.

Кнопка mini_app#

Кнопка с mini_app открывает мини-приложение бота, а не отправляет боту нажатие:

JSON
{
  "chat_id": "70051",
  "text": "Заполните форму заявки. Она открывается в SMeet: нажмите кнопку ниже.",
  "reply_markup": {
    "inline_keyboard": [
      [{"text": "Открыть форму", "mini_app": {"start_param": "vpn-access"}}],
      [{"text": "Помощь", "callback_data": "help"}]
    ]
  }
}
  • У кнопки ровно одно из полей callback_data, url и mini_app. mini_app является объектом; start_param необязателен, до 64 символов из A-Z a-z 0-9 _ -, и передаётся мини-приложению при открытии. Пустое значение означает, что параметра нет.
  • Только в личном чате бота, у которого есть мини-приложение, и не удалённое. В группе, теме или канале, а также у бота без мини-приложения sendMessage, editMessageText, sendPhoto и sendDocument отвечают 400 INVALID_REQUEST с "field": "reply_markup" и "reason": "mini_app_not_configured". Неверный start_param получает INVALID_REQUEST с "field": "reply_markup" и без reason.
  • Кнопка открывает только опубликованную конфигурацию. Пока её нет, а также пока мини-приложение приостановлено или заблокировано, человек видит, что оно недоступно; кнопка остаётся в чате.
  • О нажатии бот не узнаёт. Результат вызова показывает кнопку в том виде, в каком вы её написали, только пустой start_param возвращается как отсутствующий.
  • Приложения без поддержки мини-приложений (SMeet для Android, приложение для компьютера и старые версии веб-приложения и SMeet для iOS) показывают кнопку неактивной и ничего не объясняют. Напишите в тексте, где открывается форма, как в примере.

То же окно открывается по ссылке на профиль бота с startapp: https://messenger.scrile.com/u/<bot_username>?startapp=<param>, где param подчиняется правилу start_param и может быть пустым. Человеку, который открыл ссылку, не запустив бота, предлагается запустить бота и открыть мини-приложение одним действием.

Событие mini_app_submission#

Когда человек подтверждает форму, бот получает:

JSON
{
  "update_id": "4380",
  "event_id": "2c7a1e94-3b6f-4d1a-8e2b-6f0c9d3a5b17",
  "type": "mini_app_submission",
  "date": "2026-10-10T12:00:00Z",
  "mini_app_submission": {
    "id": "6f1c9a2e-8a8f-4d6b-9a4e-6d2f0a3b7c11",
    "app_id": "1000",
    "environment": "production",
    "client_request_id": "f3b0c9e2-form-1",
    "from": {"id": "103", "display_name": "Дмитрий", "username": "dmitry", "is_bot": false},
    "chat": {"id": "5501", "type": "private", "access_revision": "1088"},
    "data": {"subject": "VPN", "priority": "high"},
    "date": "2026-10-10T12:00:00Z"
  }
}
  • app_id, environment, from и chat определяет SMeet: страница не может их выбрать. from.id означает того же человека, что from.id его сообщений, а chat.id является вашим личным чатом с ним.
  • data содержит форму ровно в том виде, в каком её отправила страница: JSON-объект до 16 КиБ. Проверяйте его так же, как любой ввод людей.
  • Одна отправка даёт одно событие. Страница называет каждую форму своим requestId, который приходит как client_request_id; когда страница отправляет ту же форму снова (после сетевой ошибки, перезагрузки, из второго окна), SMeet возвращает ту же отправку и второго события не пишет. Свою работу защищайте от повторов по event_id, как для любого события (Защита от повторов).
  • id обозначает отправку так, как её знают приложение человека и мини-приложение.
  • Отправки приходят через getUpdates или ваш webhook в порядке очереди, с теми же подтверждением, списком FAILED и сроком хранения 7 дней, что и любое событие (Получение событий).

Ответ человеку#

Отвечайте в chat.id. chat.access_revision отправки является версией диалога на момент, когда человек открыл мини-приложение; передайте её как expected_access_revision, а ключ постройте из события:

HTTP
POST /bot-api/v1/sendMessage HTTP/1.1
Host: messenger.scrile.com
Authorization: Bearer sbt1_EXAMPLE_REPLACE_WITH_YOUR_TOKEN
Idempotency-Key: 2c7a1e94-3b6f-4d1a-8e2b-6f0c9d3a5b17:reply
Content-Type: application/json

{"chat_id": "5501", "text": "Заявка SM-1042 создана. Ответим здесь.",
 "expected_access_revision": "1088"}
  • 403 BOT_STOPPED_OR_BLOCKED: человек остановил или заблокировал бота. 409 ACCESS_REVISION_CONFLICT: диалог изменился после отправки формы (например, Stop и снова Start). Оба ответа окончательны для этого ответа: не повторяйте его, а если работа важна, дождитесь, когда человек вернётся (Условные запросы).
  • Сервер без access_revisions в capabilities условие не проверяет: старый сервер пропускает параметр и выполняет действие без условия, а сервер 1.2.0 с выключенными условиями отклоняет вызов с 400 INVALID_REQUEST и "field": "expected_access_revision". Передавайте условие, только когда возможность есть в списке (Возможности сервера, правило 1).
  • Человек мог отозвать доступ мини-приложения через его меню. Тогда отправки, которые бот ещё не получил, отменяются, а сам диалог остаётся: на уже полученное бот может ответить.

Когда отправка отменяется#

Отправка, которая ещё не дошла до бота, отменяется, и программа на long polling видит её в skipped с причиной cancelled, когда:

Что произошлоЧто отменяется
Человек остановил или заблокировал бота либо вышел из пространства ботаКак любое событие этого чата
Человек выбрал «Отозвать доступ» в меню мини-приложенияОжидающие и FAILED отправки этого диалога
Владелец удалил мини-приложениеОжидающие и FAILED отправки этого мини-приложения
Платформа заблокировала мини-приложение или все мини-приложения его владельцаОжидающие и FAILED отправки этого мини-приложения
Организация выключила работу ботовСразу все ожидающие и FAILED события бота (Эксплуатация)
Организация выключила мини-приложенияВ момент, когда SMeet собирается передать отправку боту
Тестовая отправка, отправитель которой больше не владелец, не принявший приглашение тестировщик и не проверяющийВ момент, когда SMeet собирается передать отправку боту

Те же проверки выполняются, когда владелец повторяет FAILED-отправку: отправка, которая больше не может дойти до бота, отменяется вместо повтора. Пауза владельцем, техническая пауза платформы, закрытое окно и истёкший вход страницы ничего не отменяют; отправка ждёт в очереди, как и другие события.

Что видит человек#

Страница мини-приложения может спросить у SMeet, в каком состоянии её отправка:

СостояниеЗначит
pendingВ очереди бота, ещё не подтверждена
deliveredБот подтвердил её: offset long polling за ней или ответ 2xx вашего webhook
failedОна в списке FAILED у владельца
cancelledОна отменена до доставки, или владелец её пропустил
expiredЕё не подтвердили за 7 дней, или она старше этого срока

Поэтому подтверждайте отправку, только когда она сохранена у вас: с этого момента страница может сказать человеку «доставлено».

Тестовая среда#

"environment": "test" приходит из тестового адреса мини-приложения, который открывают только владелец, тестировщики, принявшие приглашение, и проверяющие открытой заявки. Рабочая и тестовая среды никогда не делят отправку, даже с одинаковым requestId. Не смешивайте тестовые отправки с настоящей работой: тестовая форма не должна создавать настоящую заявку.