Mini App — это полноценный веб‑интерфейс внутри Telegram. Для каталога товаров удобно разделить ответственность: фронтенд на Vue 3 (Pinia + localStorage) отвечает за UI и состояние корзины, бэкенд на PHP (Laravel или Yii2) отдаёт список товаров, проверяет initData и при необходимости создаёт счёт через sendInvoice.
Архитектура и поток данных
1. Пользователь открывает Mini App по глубокой ссылке https://t.me/YourBot/YourApp?startapp=catalog.
2. При загрузке Vue‑приложение вызывает Telegram.WebApp.ready() и читает Telegram.WebApp.initData.
3. Фронтенд шлёт initData на эндпоинт /api/catalog (POST, JSON). Бэкенд валидирует подпись (HMAC‑SHA256 от токена бота) и возвращает массив товаров.
4. Товары рендерятся в списке. Добавление в корзину мутирует Pinia‑store; после каждого изменения store сериализуется в localStorage.
5. Нажатие «Оплатить» запускает один из двух сценариев:
- Telegram Invoice — бэкенд вызывает
sendInvoiceи возвращаетinvoice_url; фронтенд делаетTelegram.WebApp.openInvoice(url). - Внешний платёж — бэкенд создаёт заказ в своей БД, генерирует
lead_id = bin2hex(random_bytes(7)), сохраняет его и возвращает URL платёжного шлюза. Фронтенд открывает его черезTelegram.WebApp.openLink(url).
pre_checkout_query и successful_payment (или вебхук от платёжного шлюза) и завершает заказ.
Получение товаров и валидация initData на PHP
Корзина на Pinia с персистом в localStorage
В main.js вызываем useCartStore().load() сразу после создания приложения.
Оформление заказа: Telegram Invoice
Бэкенд формирует параметры счёта и вызывает sendInvoice через cURL. Важно: payload — строка ≤ 128 байт, туда кладут lead_id.
Фронтенд получает URL и делает:
Внешний платёжный шлюз
Если бизнес требует собственный эквайринг, бэкенд создаёт заказ, генерирует lead_id = bin2hex(random_bytes(7)) (14 символов, укладывается в 64‑байтовый callback_data), сохраняет запись в БД и возвращает URL платёжной страницы. Фронтенд открывает её через Telegram.WebApp.openLink(url). После оплаты шлюз шлёт вебхук на ваш эндпоинт; там проверяете подпись, находите заказ по lead_id и меняете статус.
Безопасность, лимиты и идемпотентность
- initData — всегда проверяйте HMAC на сервере; не доверяйте данным из Mini App без валидации.
- callback_data — не превышайте 64 байта. Для идентификаторов заказов используйте короткие hex‑строки (14 символов) или числовые ID.
- Webhook — настройте
secret_tokenприsetWebhook. В контроллере сверяйте заголовокX-Telegram-Bot-Api-Secret-Token. Сохраняйте обработанныеupdate_idв таблице (уникальный индекс) — это гарантирует идемпотентность при повторной доставке. - sendInvoice —
provider_tokenвыдаётся @BotFather для каждого платёжного провайдера. Тестовый токен работает только в тестовом режиме. - Локальное хранение —
localStorageочищается пользователем; при критических данных дублируйте корзину на сервере (например, при авторизации пользователя).
Типичные ошибки и отладка
Ошибка 400 Bad Request при sendInvoice — чаще всего неверный
provider_tokenили сумма вamountне кратна минимальной единице валюты (копейки для RUB). Проверьте ответ Telegram: полеdescriptionсодержит подробности.
initData валидация падает — убедитесь, что на бэкенде используется тот же токен бота, что и в @BotFather. Пробелы и переносы строк в
data_check_stringдолжны совпадать с документацией (сортировка по ключам, разделитель \n).
Корзина теряется после перезахода — проверьте, что
useCartStore().load()вызывается до первого рендера списка. Добавьтеconsole.logвload()для диагностики.
Для локальной разработки удобно пробросить вебхук через ngrok и смотреть сырые апдейты в логах. В продакшене используйте очередь (RabbitMQ, Redis Streams) для обработки pre_checkout_query и successful_payment — это снимает нагрузку с PHP‑воркеров.
Готовый проект можно развернуть на BotCreator — платформа упрощает настройку вебхуков, хранение секретов и мониторинг ошибок. https://botservice.biz