Для разработчиков

Обработка форм

Открытие представления

Чтобы открыть модальное окно с представлением, ваше приложение должно иметь действительный, неистекший trigger_id. Это требование связано с тем, чтобы приложение открывало модальное окно только с разрешения пользователя и делало это быстро.

Для открытия представления используйте метод POSTОткрытие представления.

С целью поддержания интерактивности и отзывчивости интерфейсов Пачки, срок жизни trigger_id ограничен и составляет 3 секунды

Получение результатов

После заполнения пользователем полей в представлении и отправки их, в ваше приложение отправляется исходящий вебхук. Вебхук будет отправлен на Webhook URL того бота, от имени которого было отправлено сообщение с кнопкой (нажатие на неё и открыло представление). Адрес задаётся на вкладке «Исходящий вебхук» в карточке бота.

Отправку формы бот получает, только если у него включено событие Нажатие кнопок (button_click). Добавлять бота в чат для этого не нужно: вебхук приходит тому боту, который открыл форму.

Задача вашего приложения — быстро обработать вебхук и ответить: закрыть представление или показать ошибки под полями. Срок ответа — 3 секунды, подробнее в разделе Закрытие и отображение ошибок.

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

Вебхук содержит информацию, которая была заложена при открытии представления пользователю (такие поля, как private_metadata и callback_id), и данные заполненных полей представления.

Каждый исходящий вебхук защищён с помощью подписи, основанной на хешировании содержимого. Подробнее об этом — в разделе Безопасность.

ViewSubmitWebhookPayloadobject
Пример вебхука о заполнении формы
{    "type": "view",    "event": "submit",    "private_metadata": "{\"timeoff_id\":4378}",    "callback_id": "timeoff_request_form",    "user_id": 1235523,    "view_id": "01KAJZ2XDSS2S3DSW9EXJZ0TBV",    "submit_id": "791a056b-006c-49dd-834b-c633fde52fe8",    "data": {        "date_start": "2025-07-01",        "date_end": "2025-07-14",        "request_doc": [            {                "name": "request.png",                "size": 19153,                "url": "<url>"            }        ],        "accessibility": "phone_only",        "info": "Поеду в сибирь на свадьбу лучшего друга",        "newsletters": ["new_tasks", "project_updates"],        "team": "success",        "time": "22:00"    },    "webhook_timestamp": 1755075544}

Значение блока file_input приходит массивом объектов с полями name, size и url. Расширение файла проверяйте у себя: список filetypes подставляется в фильтр окна выбора файла.

Скачивайте файл сразу после получения вебхука. Прямая ссылка действует 2 часа, а сам файл хранится сутки с момента отправки формы, после чего удаляется. Если файл нужен дольше, скачайте его по ссылке и сохраните у себя.

Закрытие и отображение ошибок

После заполнения пользователем полей в представлении в приложение будет отправлен исходящий вебхук. В этот момент вы можете сохранить полученные значения или провести валидацию правильности заполнения полей и отправить пользователю ошибки.

Вам необходимо оперативно ответить на вебхук (кодом 200 или 400 со списком ошибок). В ином случае, пользователь получит ошибку отправки в интерфейсе Пачки. Все значения полей будут сохранены и пользователь повторит попытку отправки формы.

С целью поддержания интерактивности и отзывчивости интерфейсов Пачки, время на ответ ограничено. Ваше приложение должно дать ответ на вебхук в течение 3 секунд.

Отображение ошибок

Если вы хотите отобразить пользователю ошибки заполнения конкретных полей представления, то ответ должен быть HTTP 400 Bad Request, а тело ответа содержать массив полей с указанием текста ошибки.

Тело ответа с указанием текста ошибки для каждого поляobject
Пример ответа на вебхук для отображения ошибок
HTTP/1.1 400 Bad RequestServer: nginx/1.14.2Date: Wed, 22 Apr 2025 12:32:29 GMTContent-Type: application/json; charset=utf-8Transfer-Encoding: chunkedConnection: closeETag: W/"4d63aae1430a3bbd35e95e3db6b364df"Cache-Control: max-age=0, private, must-revalidateX-Request-Id: 12f8a05c-c5cf-4a79-8d2f-f82cc477c410X-Runtime: 0.117503Vary: OriginX-Rack-CORS: miss; no-origin {    "errors": {        "date_end": "Дата окончания отпуска не может быть меньше даты начала",        "request_doc": "В заявлении не найдена электронная подпись"    }}

Пример отображения ошибок в интерфейсе представления

Закрытие представления

Если вы хотите просто закрыть пользователю представление (нет необходимости отображать ошибки), то ответ должен быть HTTP 200 OK. Никакое тело ответа не требуется.

Пример ответа на вебхук для закрытия представления
HTTP/1.1 200 OKServer: nginx/1.14.2Date: Wed, 22 Apr 2025 12:32:29 GMTContent-Type: text/plain; charset=utf-8

Ответ через журнал событий

Этот раздел нужен, только если у бота не задан адрес исходящего вебхука. Отвечать на вебхук такому боту некуда, поэтому при включённой истории событий событие view_submit забирают методом GETИстория событий, а ответ отправляется методом POSTОтвет на отправку формы. Значения view_id и submit_id берутся из payload события.

Если адрес вебхука задан, пользуйтесь обычным ответом на вебхук: он проще и не требует опроса журнала.

Нажатие на кнопку такой бот тоже забирает из журнала, и три секунды жизни trigger_id отсчитываются от записи нажатия в журнал, а не от самого нажатия. Поэтому открыть представление успевает и бот, который опрашивает журнал с паузами.

Ответить нужно в течение 5 секунд с момента отправки формы. Если бот промолчал, пользователь получит ошибку отправки, значения полей сохранятся и он повторит попытку.

Тело запроса без поля errors закрывает представление как успешно отправленное. С полем errors — показывает ошибки под соответствующими полями, как и ответ HTTP 400 на исходящий вебхук.

Пример ответа с ошибками полей
{    "submit_id": "791a056b-006c-49dd-834b-c633fde52fe8",    "errors": {        "date_end": "Дата окончания отпуска не может быть меньше даты начала",        "request_doc": "В заявлении не найдена электронная подпись"    }}
Пример ответа для закрытия представления
{    "submit_id": "791a056b-006c-49dd-834b-c633fde52fe8"}

Ответ на отправку принимается один раз: первый успешный вызов забирает ожидающую отправку, и повторный вызов с той же парой view_id и submit_id уже ничего не меняет. И в этом случае, и когда пять секунд истекли, метод отвечает 410 с кодом submit_expired.