услуга: Мобильная разработка
направление: Информационное
Как создать чат-бот в Максе на Laravel: архитектура вебхука, обработка JSON и двухэтапная загрузка медиа
Архитектура взаимодействия: принцип работы Webhook и общая схема
Создание чат-бота в Макс на Laravel строится на событийной модели и вебхуках. MAX фиксирует действия пользователя, например сообщение, нажатие кнопки или запуск бота, затем передает событие на URL Laravel-приложения. Сервер принимает данные, обрабатывает их и отправляет ответные сообщения или команды обратно в мессенджер.
Вебхуки позволяют получать события сразу после их появления, без периодического опроса сервера. Это снижает задержки и уменьшает нагрузку на инфраструктуру. В такой схеме MAX выступает источником событий, Laravel-приложение обрабатывает входящие запросы, а пользователь инициирует взаимодействие или получает результат.
Работа начинается с регистрации бота на бизнес-платформе. На этом этапе разработчик создает чат-бота в Макс, задает его параметры и указывает URL вебхука. Этот адрес становится точкой входа для всех входящих событий, которые Laravel должен принять, проверить и обработать.


Интерфейс Business Max
После настройки вебхука взаимодействие работает по циклу «событие, обработка, ответ». Когда пользователь отправляет сообщение, нажимает кнопку или запускает бота, MAX формирует HTTP POST-запрос. Например, при создании нового сообщения приходит событие message_created. В теле запроса передается JSON с данными о событии, чате, отправителе и содержимом сообщения. Этот запрос поступает на URL, указанный в настройках бота.

Вэбхук непосредственно в приложении
Laravel-приложение принимает запрос через привязанный маршрут и сначала проверяет его подлинность. Это защищает систему от внешних запросов, которые могут имитировать события MAX. После проверки приложение разбирает JSON, определяет тип события, идентификатор чата chat_id, пользователя и текст сообщения.
Далее Laravel выполняет нужную бизнес-логику: сохраняет данные в базе, обращается к CRM, получает информацию из других сервисов или формирует ответ. После обработки сервер должен вернуть корректный HTTP-статус, обычно 200 OK. Если мессенджер не получит подтверждение, он может повторить отправку события, что приведет к дублям и ошибкам синхронизации.
Если пользователю нужен ответ, Laravel отправляет отдельный HTTP-запрос к API MAX. В нем передаются chat_id, по которому мессенджер определяет нужный чат, и содержимое сообщения: текст, медиа или другие данные. В итоге схема замыкается: MAX передает событие message_created в Laravel, Laravel обрабатывает его и при необходимости отправляет ответ обратно в MAX.
Для наглядности, общую схему взаимодействия можно представить следующим образом:
| Шаг | Участник | Действие | Канал |
| 1 | Пользователь MAX | Отправляет сообщение или нажимает кнопку. | Мессенджер MAX |
| 2 | MAX | Генерирует событие (message_created, message_callback). | — |
| 3 | MAX | Отправляет HTTP POST-запрос на URL вебхука. | Интернет (HTTPS) |
| 4 | Laravel-приложение | Принимает POST-запрос, проверяет подлинность. | Сервер |
| 5 | Laravel-приложение | Парсит JSON-полезную нагрузку, выполняет бизнес-логику. | Сервер |
| 6 | Laravel-приложение | Формирует и отправляет ответный HTTP POST-запрос к API MAX. | Интернет (HTTPS) |
| 7 | MAX | Получает ответный запрос, отображает сообщение в чате пользователя. | Мессенджер MAX |
Форматы входящих данных: анализ JSON-полезной нагрузки от MAX
Структура входящих данных определяет, как Laravel-приложение обрабатывает события от MAX. Когда мессенджер отправляет вебхук, сервер получает HTTP POST-запрос с JSON-объектом. В нем содержатся ключи, которые описывают тип события, время его создания, контекст и связанные данные.
На верхнем уровне JSON находятся обязательные поля. Одно из ключевых полей называется update_type, в некоторых случаях используется type. Оно указывает, какое событие пришло в приложение. Например, message_created означает новое сообщение, bot_started указывает на запуск бота пользователем, а message_callback связан с нажатием кнопки с колбэком.
По значению update_type или type Laravel распределяет запросы между нужными обработчиками. Для message_created приложение анализирует текст сообщения, для bot_started запускает стартовый сценарий, для message_callback обрабатывает действие пользователя по кнопке. Такой подход позволяет держать один входной маршрут для вебхуков и внутри приложения направлять события в отдельные методы.

Пример разбора элементом полученного по API сообщения
Поле timestamp хранит время возникновения события. В MAX его нужно обрабатывать внимательно: значение может передаваться в миллисекундах, а многие функции работают с Unix-временем в секундах. Поэтому при разработке чат-бота в Макс стоит проверять размер значения. Если timestamp больше условного порога, например 1000000000000, его делят на 1000. Это помогает корректно сортировать сообщения, вести историю переписки и работать с датами.
Основные данные о сообщении находятся в объекте message. Для безопасного доступа к вложенным полям в Laravel удобно использовать оператор ??. Если нужный ключ отсутствует, приложение получит пустое значение или значение по умолчанию, а не ошибку. Такой подход повышает устойчивость интеграции, поскольку структура ответа API может меняться.
Внутри message важны данные о чате и отправителе. Идентификатор чата находится в поле recipient.chat_id. Он нужен для отправки ответа, логирования диалога и связи пользователя MAX с внутренней учетной записью в системе. В объекте recipient также могут находиться дополнительные метаданные чата. Данные отправителя хранятся в объекте sender: обычно это user_id и first_name. По ним приложение определяет, кто отправил сообщение.
Текст сообщения чаще всего находится в поле body.text. Но при работе с медиа нужно учитывать другие варианты. Если пользователь отправил файл без подписи, body.text может отсутствовать. Если сообщение содержит медиа и подпись, текст может находиться в body.text или в caption первого вложения из body.attachments.
Медиафайлы передаются в массиве body.attachments или attachments. Каждый элемент attachment описывает отдельное вложение. Поле type указывает тип файла: image, file, video, audio или voice. Поле payload содержит технические данные, которые нужны для скачивания и обработки файла.
В payload могут входить:
Для работы с вложениями используется сервис MaxMediaService. Он проходит по attachments, определяет type, извлекает данные из payload, собирает ID, MIME-тип, размер, URL, токен и другие метаданные. На выходе приложение получает единый массив данных, с которым проще работать в бизнес-логике. Это снижает зависимость основного кода от сложной структуры API MAX.
В таблице ниже представлена сводная информация по ключевым полям входящего JSON-объекта.
| Поле (Путь) | Тип данных | Описание | Пример значения |
|---|---|---|---|
| update_type | String | Тип события. Может быть message_created, bot_started, message_callback и др. | «message_created» |
| type | String | Альтернативное название для update_type. | «bot_started» |
| timestamp | Integer | Временная метка события в миллисекундах с начала эпохи Unix. | 1677610000000 |
| message | Object | Объект, содержащий детали сообщения. | {…} |
| ├── recipient | Object | Объект-контейнер для данных получателя. | {…} |
| │ └── chat_id | String | Уникальный идентификатор чата в MAX. Ключевой идентификатор. | «chat_12345:user_id_67890» |
| ├── sender | Object | Объект-контейнер для данных отправителя. | {…} |
| │ ├── user_id | String | Уникальный идентификатор пользователя-отправителя. | «user_id_67890» |
| │ └── first_name | String | Имя отправителя. | «Иван» |
| └── body | Object | Объект, содержащий основное содержимое сообщения. | {…} |
| ├── text | String | Текстовое содержимое сообщения. | «Привет!» |
| └── attachments | Array | Массив объектов, описывающих медиа-вложения. | [{«type»: «image», «payload»: {«fileId»: «…», «mime_type»: «image/jpeg»}}] |
После того как Laravel-приложение получило и успешно обработало JSON-полезную нагрузку, оно должно вернуть ответ HTTP 200 OK. Если этого не сделать, MAX может продолжать повторять отправку этого же события, что приведет к дублированию сообщений и неконсистентности данных.
Отправка исходящих сообщений: текст, кнопки и ответная логика
После обработки входящего события Laravel-приложение формирует ответ пользователю через REST API мессенджера MAX. Ответ может содержать простой текст, медиафайл, интерактивные кнопки или другие элементы, которые поддерживает платформа.
Для отправки сообщений в Laravel обычно используют сервис-обертку над API, например класс MaxBot. Он скрывает работу с HTTP-запросами и дает разработчику удобные методы. В простом сценарии отправка текста сводится к вызову $this->bot->sendMessage($chatId, $text).
Внутри метод формирует HTTP POST-запрос к эндпоинту API MAX, например /messages. В теле запроса передается JSON-объект с ключевыми полями: chat_id, куда нужно отправить сообщение, и message, где хранится текст ответа. Обычно chat_id берется из входящего события, чтобы бот ответил в тот же чат.
После успешной отправки MAX возвращает ответ с подтверждением. Laravel-приложение может сохранить результат в лог, записать статус сообщения в базу данных или использовать эти данные в дальнейшей бизнес-логике.

Код, отвечающий за обработку входящих сообщений в MAX

Результат
Более функциональный сценарий ответа, отправка сообщения с кнопками. Клавиатуры позволяют строить диалоговые меню, предлагать пользователю варианты действий и управлять логикой сценария. Для этого Laravel-приложение передает в JSON-запросе не только текст сообщения, но и объект клавиатуры с массивом кнопок. У каждой кнопки есть текст и уникальный идентификатор действия.
При нажатии на кнопку MAX отправляет в вебхук новое событие message_callback. Вместе с ним приходит поле callback_data, где хранится идентификатор выбранного действия. Laravel принимает это событие и по значению callback_data запускает нужную логику: подтверждает заявку, отклоняет запрос, открывает следующий шаг меню или меняет состояние диалога. Такой механизм позволяет строить управляемые сценарии и конечные автоматы внутри бота.
Отдельный блок логики связан с отправкой медиафайлов. Текстовое сообщение можно отправить одним запросом, а медиа требуют предварительной подготовки. Если бот должен отправить изображение, документ или другой файл, Laravel сначала получает разрешение на загрузку и временный адрес для передачи файла.
Для этого приложение отправляет запрос POST /uploads?type=X, где X обозначает тип медиа. Например, для изображения используется значение photo. В ответ MAX возвращает JSON с временным URL для загрузки. Этот адрес действует ограниченное время и позволяет безопасно передать файл без постоянного доступа к хранилищу.
После получения URL Laravel загружает файл по выданному адресу, обычно отдельным запросом PUT или другим методом, который требует API MAX. Затем приложение использует данные загруженного файла при отправке сообщения пользователю. Такой двухэтапный процесс разделяет получение прав на загрузку и саму передачу файла, что повышает безопасность и упрощает работу с крупными медиа.

Шаг 2: Загрузка файла и получение токена
После получения URL от API MAX приложение переходит ко второму этапу: загружает файл по выданному адресу. Для этого Laravel отправляет второй HTTP POST-запрос уже на полученный специфический URL, а в теле запроса передает сам файл.
Формат передачи здесь критически важен. Для HTTP POST обычно используют два варианта: application/x-www-form-urlencoded и multipart/form-data [41]. При загрузке бинарных данных подходит multipart/form-data, поскольку этот формат позволяет передавать файл и связанные с ним параметры отдельными частями запроса, каждая со своими заголовками и содержимым.
Такой способ используют многие HTTP-клиенты, включая Python-библиотеку requests, и он считается стандартным решением для загрузки файлов через API.

На этом этапе важно правильно передать файл в теле запроса. Обычно файл помещают в поле data: в структуре multipart/form-data эта часть содержит бинарные данные файла, а дополнительные части могут передавать метаданные, если их требует API.
После отправки запроса на полученный URL сервер MAX принимает файл, сохраняет его во временное хранилище и возвращает новый JSON-ответ. В нем указывается результат загрузки и передается токен доступа к файлу.
Этот token является уникальной строкой, по которой MAX идентифицирует загруженный файл. Он нужен для следующего шага, когда Laravel-приложение будет использовать файл в сообщении пользователю.
Использование токена для отправки сообщения
После получения token от MAX Laravel-приложение может отправить сообщение с медиафайлом. Для этого оно формирует POST-запрос к эндпоинту отправки сообщений, например /messages.
В теле запроса передается JSON с получателем chat_id и содержанием сообщения. Чтобы добавить загруженный файл, в JSON включается секция вложений: массив attachments или отдельный объект вложения, если так устроен API MAX.
Внутри вложения указывается тип файла, например photo, и полученный ранее token. По этому токену MAX понимает, что нужно прикрепить уже загруженный файл, а не загружать его заново.
В итоге, весь двухэтапный процесс можно свести к следующей последовательности действий:
| Шаг | Действие | Описание | Пример запроса/API |
|---|---|---|---|
| 1 | Запрос URL | Приложение отправляет POST на /uploads с параметром type=…. | POST /uploads?type=photo |
| 2 | Получение URL | MAX возвращает JSON с полем, содержащим временный URL для загрузки. | {«upload_url»: «https://…temporary-upload-endpoint…»} |
| 3 | Загрузка файла | Приложение отправляет POST на полученный upload_url с файлом в теле в формате multipart/form-data и полем data. | POST {upload_url} с multipart/form-data и полем data |
| 4 | Получение токена | MAX обрабатывает файл и возвращает JSON с токеном доступа к файлу. | {«token»: «xyz.abc123…», «id»: «photo_123»} |
| 5 | Отправка сообщения | Приложение отправляет POST на /messages с chat_id и объектом вложения, содержащим полученный token. | POST /messages с телом {«chat_id»: «…», «attachment»: {«type»: «photo», «token»: «xyz.abc123…»}} |
Безопасность, ограничения и заключительные рекомендации
При интеграции бота MAX с Laravel важно учитывать не только основную логику, но и безопасность, обработку ошибок и ограничения API. От этих решений зависит стабильность, корректность данных и устойчивость к сбоям.
Главный риск связан с вебхуком. Это открытая точка входа по URL, на которую MAX отправляет события. Если злоумышленник узнает этот адрес, он может отправлять произвольные JSON-данные и имитировать события мессенджера. Это способно привести к ложным записям в базе, ошибкам бизнес-логики или DoS-нагрузке.
Поэтому каждый входящий запрос нужно проверять. Для этого используют секретный токен или подпись HMAC. Laravel-приложение сравнивает подпись из запроса с подписью, рассчитанной на своей стороне по тем же данным и секретному ключу. Если значения не совпадают, запрос отклоняется как недостоверный.
Отдельно стоит продумать обработку ошибок. Код вебхука должен работать через try…catch: исключения логируются, а приложение не падает из-за одного некорректного события. После успешного приема события сервер возвращает HTTP 200 OK, чтобы MAX не отправлял тот же запрос повторно. Тяжелые операции лучше выносить в очереди Laravel, например через Redis или Database. Тогда вебхук быстро принимает событие, а обработка выполняется асинхронно.
Также нужно учитывать ограничения API: размер JSON-нагрузки, лимиты на файлы и требования к заголовкам вроде Content-Length. Если MAX отклоняет слишком большой файл, Laravel должен корректно обработать ошибку и отправить пользователю понятное сообщение о превышении лимита.
В качестве итоговых рекомендаций для создания чат-бота в Максе можно предложить следующий план действий:
- Начните с планирования: Перед написанием кода четко определите все типы событий, которые ваш бот должен обрабатывать, и логику для каждого из них.
- Создайте защищенную точку входа: Настройте вебхук на платформе business.max.ru и немедленно реализуйте механизм проверки подлинности запросов. Не пренебрегайте этим шагом.
- Структурируйте код с помощью архитектурных паттернов: Используйте модульную структуру в Laravel, разделяйте логику на сервисы, репозитории и действия. Абстрагируйте внешние API.
- Изолируйте сложную логику: Перенесите обработку медиафайлов, взаимодействие с базой данных и другими внешними системами в отдельные сервисы.
- Реализуйте отказоустойчивость: Оберните основную логику обработки вебхука в блок try…catch и всегда возвращайте 200 OK. Рассмотрите использование очередей для тяжелых задач.
- Тщательно протестируйте: Не забывайте про тестирование. Напишите юнит-тесты для ваших сервисов и интеграционные тесты для проверки взаимодействия с API MAX.
Проконсультируем по всем вопросам