Pull to refresh

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

Level of difficultyMedium
Reading time6 min
Views26K

Инструкция, посвящённая созданию 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 — пусть не самый простой, но очень эффективный и удобный способ.

Tags:
Hubs:
Total votes 12: ↑12 and ↓0+12
Comments0

Articles