AIOgram3 18. Connecting payment Telegram Stars
On June 6, Pavel Durov announced that Telegram was introducing a new currency — Stars. Stars will allow you to purchase digital goods and services, or, in other words, pay for purchases within Telegram, for example, in bots or MiniApps. However, not everything is so rosy. The introduction of a new payment method entails the disabling of all other payment methods. If your bot accepted payments through UKassa, now only "Stars" will be accepted. We will leave the reasons for such changes out of the equation and focus on more important things, namely, how to implement a new payment method — Telegram Stars — into a Telegram bot.
You can purchase stars by opening Telegram settings and finding the "Telegram Stars" item.
It is worth noting. At the time of writing, there was no up-to-date information on how and where to use the stars received from users. The article will be supplemented as information from Telegram is updated. If you know anything, let us know!
Attention! The post is a continuation of the series " Telegram bot on AIOgram3 ".
Updating dependencies
For full support of the new payment method, AIOgram version 3.7.0 is required. To update the library, simply run the command:
pip install -U aiogram
After that, update the version in the requirements.txt.
aiogram==3.7.0
Payment button
Before we start writing the invoice command handler, we need to create a payment button that will open a payment window when clicked.
In the package botlogicwe will create a new package keyboards, and in it a file payment_keyboard.py.
Let's write a function payment_keyboardthat doesn't accept anything.
In the body of the function, we will create a variable builderin which we will define an instance of the class InlineKeyboardBuilder.
You can pass a list of lists with objects of the button class to it, but this is not very convenient, it is easier to use class methods. On the next line, we call the method of the class object .button, which adds the button to the keyboard collector. We pass two arguments:
text— Defines the text on the button. If the text containsXTRa star emoji ⭐️, it will automatically be replaced with the Telegram Stars icon.pay— Defines the button type as a payment button.
Next, we return the variable builderby applying the method to it .as_markupto get an object ready to be placed in the keyboard message.
File code:
from aiogram.utils.keyboard import InlineKeyboardBuilder
def payment_keyboard():
builder = InlineKeyboardBuilder()
builder.button(text=f"Оплатить 20 ⭐️", pay=True)
return builder.as_markup()Creating a keyboard is not necessary, you can send an invoice without it. However, it allows you to customize the button text, as well as add additional functional buttons, such as cancel payment, select another product, etc.
Invoice Processor
Let's start writing the command handler.
In the package handlerswe will create a file payment.py.
In this file we will write an asynchronous function send_invoice_handlerthat accepts messagean object of the class Message.
Let's create a variable pricesin which we'll place a list with objects of the class LabeledPrice, or rather, with one object, since for payment via Telegram Stars this list must consist of one element. We pass the following arguments to the class object:
Next, messagewe call the method on the variable .answer_invoiceso that the bot responds to the user's message with a button with an invoice for payment. We pass the following arguments to the method:
title— Name of payment, product or service.description— Description of payment, product or service.prices— A list of objectsLabeledPricepreviously defined in the variable of the same name.provider_token— Payment system token, for Telegram Stars we simply send an empty string.payload— Payment label. It is not displayed to the user, but can be used to separate payments by their types, etc. Maximum 128 bytes of data (in Python, one character takes up one byte, but keep in mind that special characters or emojis may take up more space).currency— Payment currency, for Telegram Stars it isXTR.reply_markup— Keyboard object.
Handler code:
from aiogram.types import LabeledPrice, Message
from botlogic.keyboards.payment_keyboard import payment_keyboard
async def send_invoice_handler(message: Message):
prices = [LabeledPrice(label="XTR", amount=20)]
await message.answer_invoice(
title="Поддержка канала",
description="Поддержать канал на 20 звёзд!",
prices=prices,
provider_token="",
payload="channel_support",
currency="XTR",
reply_markup=payment_keyboard(),
)Pre-sale inspection
The invoice is issued, the user clicks "Pay". If he does not have enough stars, the system will offer to buy them. If he has enough stars, he will make the payment, and at that moment Telegram will send a request to the bot "is everything really okay?" We will have exactly 10 seconds to respond. If for some reason we do not want to accept payments from this user or the bot logic is set to cancel the payment, in this case it is necessary to give a response signaling the cancellation of the payment, accompanying it with the reason for the cancellation. Otherwise, we confirm that everything is "OK".
In the same file, we will create an asynchronous function pre_checkout_handlerthat takes an argument pre_checkout_query- an object of the class PreCheckoutQuery.
In the body of the function, pre_checkout_querywe call the method on the variable .answer, passing an argument okwith the value to it True.
Function code:
from aiogram.types import PreCheckoutQueryasync
def pre_checkout_handler(pre_checkout_query: PreCheckoutQuery):
await pre_checkout_query.answer(ok=True)Informing about purchase
The bureaucracy is behind us, all that's left is to congratulate the user on their purchase!
In the same file, we will create an asynchronous function success_payment_handlerthat takes an argument message- an object of the class Message.
The class object Messagestores various information about the current message, and the field successful_paymentcontains information about the payment, such as the payment identifier, amount, currency, information received from the user. Ideally, all this should be saved to avoid possible questions about payments in the future.
In the body of the function, we make a normal response, reporting that the purchase was successful.
Function code:
async def success_payment_handler(message: Message):
await message.answer(text="🥳Спасибо за вашу поддержку!🤗")Paysupport team and a little about refunds
Telegram also has conditions for refunding users. Not all products and services are eligible for refunds, but the user should still be able to request a refund or be informed about it.
To inform the user, there must be a command /paysupport. It can contain return conditions, contact information, etc. Let's make this command.
Let's create an asynchronous function pay_support_handlerthat accepts messagean object of class Message. In the body of the function, we'll write a response to the message with text describing the conditions for returning funds.
Function code:
async def pay_support_handler(message: Message):
await message.answer(
text="Добровольные пожертвования не подразумевают возврат средств, "
"однако, если вы очень хотите вернуть средства - свяжитесь с нами." )The refund itself can be made available to the user. To do this, you need to create a handler for the refund command, in which, when accessing the method .refund_star_paymentof the object Bot, pass user_idand to it telegram_payment_charge_id.
user_id— Telegram ID of the user requesting a refund.telegram_payment_charge_id— Identifier of the payment made by the user.
Registering handlers
Everything is ready, all that remains is to register the handlers in main.py.
Let's open the file main.pyand add four registrations to the function start:
send_invoice_handler— We register it as a regular message, specifying the command filterdonate.pre_checkout_handler— We register it as an eventpre_checkout_query.success_payment_handler— We register it as a normal message. As a filter we use the so-called "Magic filterF", which is an objectMessage. In the filter we access the fieldsuccessful_payment. If it is not empty (successful payment), the handler will be called.pay_support_handler— We register it as a normal message with a filter for the commandpaysupport.
from aiogram import F dp.message.register(payment.send_invoice_handler, Command(commands="donate")) dp.pre_checkout_query.register(payment.pre_checkout_handler) dp.message.register(payment.success_payment_handler, F.successful_payment) dp.message.register(payment.pay_support_handler, Command(commands="paysupport"))
Testing
Let's launch the bot and execute the command /donate.
We will receive a message with payment information and a bill button. We will click on the button.
A window will open with payment confirmation (if you don't have stars, a purchase window will open, as in the first screenshot at the beginning of the post). Click "Confirm and pay".
Confetti will shoot out in the chat and we will see a message about a successful payment.
Conclusion
The innovation, of course, surprised everyone and took them a little by surprise. They gave little time for the transition, and probably not everyone even knew about it. It will be interesting to see where all this leads.