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