Telegram Mini Apps с мгновенной оплатой

от автора

Инструкция, посвящённая созданию Telegram Mini Apps с вызовом окна оплаты без создания дополнительной кнопки для этого.


Mini Apps от Telegram — это веб-сайты, которые телеграмм позволяет запускать у себя внутри системы.

Один из вариантов использования Mini Apps — это реализация онлайн магазина: Mini Apps служат визуальным представлением, а оплата происходит через внутреннюю систему Telegram. Одному из способов такой реализации и посвящена эта инструкция.

Как это сделано в примере от Telegram:

Для реализации оплата в Bot API есть два способа:

1. Кнопка оплаты. Библиотеки телеграмм позволяют создать кнопку, при нажатии на которую создается и вызывается платежная url‑ссылка.
В документации этот метод значится как sendInvoice().

2. По ссылке. Создается url‑ссылка для оплаты методом createInvoiceLink(), в которой указываются токен платежного провайдера и детали покупки (стоимость, названия и т.д.). А после метод openInvoice(url) открывает платежную ссылку, вызвав системное окно оплаты.

Метод createInvoiceLink() вызывается у объекта бота, а openInvoice(url) вызывается в js-коде Mini Apps. В этом и заключается сложность этого метода. Получается, для реализации такого метода нужно по событию в Mini Apps отправлять запрос на создание url‑ссылки для оплаты серверной части с ботом. Там ссылка создастся, вернётся и вызовется из Mini Apps.

Иллюстрировано это выглядит следующим образом.

Иллюстрация оплаты

Иллюстрация оплаты

Приступим к программной реализации.


Для начала — что используется:

  • Python, библиотека Telebot 4.16.1;

  • Код логической части размещен на Yandex Cloud Function, а вызов — через API Gateway;

  • web-сайт для Mini Apps размещен на Netlify.

    Yandex Cloud Function позволяет запускать куски кода при обращении к ним извне. А API Gateway помогает обрабатывать внешние обращения.

1 шаг. Создать web-сайт

Создать сайт, который будет показываться в Mini Apps.

<!DOCTYPE html> <html lang="en">  <head>     <meta charset="UTF-8">     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <title>Document</title>     <style>         * {             margin: 0;             padding: 0;             box-sizing: border-box;         }          body {             font-family: 'Montserrat', sans-serif;             font-weight: 200;         }     </style> </head> <body>     <p>Привет! Получиолось!!!</p> </body> </html>

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

2 шаг. Создать телеграмм-бота

Создаем через BotFather бота, получаем его токен. Также подключаем к нему платежного провайдера и получаем токен.

/mybots → *Ваш бот* → Payments → *Любой банк* → Test режим → *Проследовать инструкциям от банка*

После этого в разделе Paymnets вашего бота появится платежный токен.
Test — это тестовый режим банка, протестировать оплату — без реальных карт и счетов.
Банк — быстрее всего удалось получить токен у ПСБ и Bank 131.

3 шаг. Логика бота.

Бот будет работать по webhook — то есть не он запрашивает с сервера телеграмма последние обновления по переписке, а сервер телеграмма будет обращаться к нему, когда поступят новости из чата.

На Yandex Function создаём новую функцию, после выбираем в настройках, что она публичная и язык Python 3.12.

Создаем файл requirements.txt и подключаем библиотеку для бота:

pyTelegramBotAPI==4.16.1

В файле index.handler пишем:

import asyncio, json, os, requests  import telebot from telebot import types from telebot.types import LabeledPrice, ShippingOption  provider_token = "ТОКЕН_ПРОВАЙДЕРА_ОПЛАТЫ" bot = telebot.TeleBot('ТОКЕН_БОТА')  @bot.message_handler(commands = ['start']) def url(message):     markup = types.InlineKeyboardMarkup()     webUrl = types.WebAppInfo("ССЫЛКА_НА_САЙТ")     web_btn = types.InlineKeyboardButton(text='Название для кнопки', web_app=webUrl)     markup.add(web_btn)     bot.send_message(message.from_user.id, "Перейти к Mini Apps", reply_markup = markup)  async def handler(event, context):     responce = None     if('X-Custom-Info' in event['headers']):         responce = bot.create_invoice_link("Покупка","Тестовый","true",provider_token,"rub",[types.LabeledPrice('Покупка',5 * 100)])         print(responce)     else:         data = json.loads(event['body'])         update = types.Update.de_json(data)         bot.process_new_updates([update])         responce = 'ok'     return {'statusCode': 200, 'body': responce}

Здесь важно, что в обработчике команды start мы создаем Mini Apps через KeyBoard, указав ссылку на наш сайт.

Настройка MiniApps
@bot.message_handler(commands = ['start']) def url(message):     markup = types.InlineKeyboardMarkup()     webUrl = types.WebAppInfo("ССЫЛКА_НА_САЙТ")     web_btn = types.InlineKeyboardButton(text='Название для кнопки', web_app=webUrl)     markup.add(web_btn)     bot.send_message(message.from_user.id, "Перейти к оплате", reply_markup = markup)

Также здесь важны еще эти строчки:

if('X-Custom-Info' in event['headers']):         responce = bot.create_invoice_link("Покупка","Тестовый","true",provider_token,"rub",[types.LabeledPrice('Покупка',5 * 100)])         print(responce)

К запросу из Mini Apps к нашей Yandex Function мы будем добавлять дополнительный заголовок, и его существование означает, что нужно сделать и вернуть url‑ссылку оплаты.

Это мы здесь и делаем — проверяем наличие заголовка и с помощью метода create_invoice_link() создаем ссылку, указав следующие параметры:

Название, описание, параметр под свои нужды, токен провайдера оплаты, валюта, массив объектов LabeledPrice — цены на товары

5 шаг. Добавить логику на сайт

После создания бота, сайта и Mini Apps нам нужно дописать логику, отправляющую запрос на сайт для создания url‑ссылки оплаты и после — для её открытия.

Для открытия url‑ссылки оплаты используется ранее названный метод — openInvoice(url), нужно подключить на сайт скрипт телеграмма:

<script src="https://telegram.org/js/telegram-web-app.js"></script>

Теперь на сайте можно использовать Telegram Mini Apps API.

Mini Apps включает в себя:

  • CSS-стиль адаптивный под тему, выбранную в Telegram;

  • Элементы — кнопки, popup, alert;

  • Методы для взаимодействия.

 const tg = window.Telegram.WebApp;

Так мы получаем объект Mini Apps для вызова методов и создания элементов.

tg.MainButton.show();         tg.MainButton.setText("Оплатить");         tg.MainButton.onClick(() => {             console.log("start");             var xhr = new XMLHttpRequest();             xhr.open("POST", url, true);             xhr.setRequestHeader("Content-Type", "application/json");             xhr.setRequestHeader("X-Custom-Info", "getOpenInvoiceUrl");             xhr.onreadystatechange = function () {                 if (xhr.readyState === 4 && xhr.status === 200) {                     tg.openInvoice(xhr.responseText);                 }             };             xhr.send();         });

Здесь создаем кнопку снизу для оплаты и обрабатываем ее нажатие. Внутри мы будем отправлять запрос к Yandex Function для получения url‑ссылки на оплату и после вызываем её.

Также здесь:
url — ваша ссылка на API Yandex Function.
data — данные json для отправки. Планируется, что вы отправляете данные для создания url‑ссылки оплаты.

В итоге код сайта выглядит следующим образом:

Сайт
<!DOCTYPE html> <html lang="en">  <head>     <script src="https://telegram.org/js/telegram-web-app.js">     </script>     <meta charset="UTF-8">     <meta name="viewport" content="width=device-width, initial-scale=1.0">     <title>Document</title>     <style>         * {             margin: 0;             padding: 0;             box-sizing: border-box;         }          body {             font-family: 'Montserrat', sans-serif;             font-weight: 200;             color: var(--tg-theme-text-color);             background: var(--tg-theme-bg-color);         }     </style> </head> <body>     <p>Привет! Получиолось!!!</p>     <script>         const tg = window.Telegram.WebApp;         let url = 'ССЫЛКА_НА_YANDEX_FUNCTION';                  var data = JSON.stringify("ДАННЫЕ_ДЛЯ ОТПРАВКИ");          tg.MainButton.show();         tg.MainButton.setText("Оплатить");         tg.MainButton.onClick(() => {             console.log("start");             var xhr = new XMLHttpRequest();             xhr.open("POST", url, true);             xhr.setRequestHeader("Content-Type", "application/json");             xhr.setRequestHeader("X-Custom-Info", "getOpenInvoiceUrl");             xhr.onreadystatechange = function () {                 if (xhr.readyState === 4 && xhr.status === 200) {                     tg.openInvoice(xhr.responseText);                 }             };             xhr.send(data);         });     </script> </body> </html>

6 шаг. Настройка API Gateway

Последним шагом нужно настроить API, по которому будет вызываться Yandex Function. Для этого в разделе API Gateway создаем новое API и в добавляем в него конфигурацию:

openapi: 3.0.0 info:   title: Sample API   version: 1.0.0 servers: - url:'здесь будет ссылка на api автоматически' x-yc-apigateway:   cors:     origin: '*'     methods: '*'     allowedHeaders: '*' paths:    /'название для запроса - обычно имя функции':     post:       x-yc-apigateway-integration:         type: cloud-functions         function_id: 'доменное имя функции, находится в ее настройках'       operationId: 'название функции' 

Здесь настроили пути обращения к функции, а также раздел с cors, который, обращаясь из Mini Apps js, сначала отправляет options-запрос, проверяя, можно ли вообще посылать post-запрос. По умолчанию его нет в конфигурационном файле. Последним надо из-за особенностей построения бота настроить WebHook. Инструкция для этого есть от Яндекса — ссылка.

В итоге получается следующее:


На этом всё. Telegram Mini Apps — довольно интересный инструмент, а реализация бота с помощью Yandex Cloud Fucntion — пусть не самый простой, но очень эффективный и удобный способ.


ссылка на оригинал статьи https://habr.com/ru/articles/796793/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *