Как принимать оплату в Telegram-боте через Payme и Click
Практика4 минРедакция Innovialabs
Коротко
Есть два пути: подключить Payme или Click как провайдера в BotFather и выставлять инвойс прямо в чате, либо отправлять ссылку на оплату и подтверждать заказ по callback от платежной системы; в обоих случаях заказ считается оплаченным только после серверного подтверждения.
Короткий ответ
Принять оплату в боте через узбекские платежные системы можно двумя способами:
- Встроенный инвойс Telegram. Вы подключаете Payme или Click как платежного провайдера в BotFather, бот отправляет счет, пользователь платит, не выходя из чата.
- Ссылка на оплату (redirect). Бот создает заказ у себя, формирует ссылку на страницу оплаты Payme или Click и ждет callback от платежной системы на ваш сервер.
Важное ограничение: цифровые товары и услуги внутри Telegram (подписки, доступ к контенту, внутриигровые бонусы) по правилам Telegram продаются за Telegram Stars. Payme и Click подходят для физических товаров, доставки, записи на услуги и других офлайн-сценариев.
Сравнение двух подходов
| Критерий | Инвойс Telegram | Ссылка на оплату |
|---|---|---|
| Где платит клиент | В окне Telegram | На странице платежной системы |
| Что нужно подключить | Провайдер в BotFather | Мерчант-аккаунт и API платежной системы |
| Кто подтверждает оплату | Telegram присылает successful_payment | Платежная система вызывает ваш сервер |
| Гибкость | Ограничена форматом инвойса | Полный контроль над логикой и чеками |
| Сложность | Ниже | Выше: нужен отдельный endpoint для callback |
Инвойс удобнее для клиента и быстрее в запуске. Redirect выбирают, когда оплата уже интегрирована на сайте, нужна общая логика заказов для сайта и бота или формат инвойса не подходит.
Вариант 1: инвойс через провайдера
- В BotFather откройте бота, раздел Payments, выберите Payme или Click и пройдите подключение. Сначала берите тестовый режим.
- Получите provider token и храните его в переменных окружения, а не в коде.
- Отправьте счет методом
sendInvoice. Сумма передается в минимальных единицах валюты: дляUZSэто тийины, то есть сумму в сумах умножаем на 100. - Ответьте на
pre_checkout_query. Это последний шанс отказать: товар закончился, цена изменилась, заказ отменен. Ответить нужно быстро, иначе Telegram отменит платеж. - Дождитесь сообщения с
successful_paymentи только после этого отметьте заказ оплаченным.
Минимальный пример на aiogram 3:
from aiogram import Bot, F, Router
from aiogram.types import LabeledPrice, Message, PreCheckoutQuery
router = Router()
@router.message(F.text == "/buy")
async def buy(message: Message, bot: Bot):
await bot.send_invoice(
chat_id=message.chat.id,
title="Заказ #1024",
description="Доставка по Ташкенту",
payload="order:1024",
provider_token=PROVIDER_TOKEN,
currency="UZS",
prices=[LabeledPrice(label="Товар", amount=15000000)], # 150 000 сум
)
@router.pre_checkout_query()
async def pre_checkout(query: PreCheckoutQuery):
ok = await order_is_valid(query.invoice_payload, query.total_amount)
await query.answer(ok=ok, error_message=None if ok else "Заказ больше недоступен")
@router.message(F.successful_payment)
async def paid(message: Message):
sp = message.successful_payment
await mark_paid(sp.invoice_payload, sp.provider_payment_charge_id)
В payload кладите идентификатор заказа из вашей базы, а не данные о товаре: по нему вы найдете заказ на всех следующих шагах.
Вариант 2: ссылка на оплату
- Бот создает заказ в вашей базе со статусом «ожидает оплаты».
- Сервер формирует ссылку на страницу оплаты с ID заказа и суммой по правилам платежной системы и отправляет ее кнопкой.
- Клиент платит на стороне Payme или Click.
- Платежная система обращается к вашему серверу: у Payme это Merchant API с методами вроде
CheckPerformTransaction,CreateTransaction,PerformTransaction, у Click — запросы Prepare и Complete. - Сервер проверяет подпись или авторизацию запроса, сумму и статус заказа, после чего бот пишет клиенту, что оплата прошла.
Обратите внимание на единицы суммы: у разных систем они отличаются (тийины или сумы), это проверяется по их документации.
Подтверждение заказа: что проверять
- Сумма и валюта в подтверждении совпадают с заказом в базе.
- Идемпотентность: повторный callback или повторное сообщение не создают второй оплаты. Храните ID транзакции и проверяйте его.
- Статус заказа меняется только на сервере. Кнопка «Я оплатил» от клиента не доказательство оплаты.
- Отмены и возвраты обрабатываются: у Payme для этого есть отдельный метод отмены транзакции.
- Уведомление менеджеру уходит после подтверждения, а не после нажатия кнопки «Оплатить».
Частые ошибки
- Сумма в сумах вместо тийинов в
sendInvoice, и клиент видит счет в сто раз меньше. - Долгая логика в обработчике
pre_checkout_query: платеж отменяется по таймауту. - Продажа цифрового доступа через Payme или Click внутри Telegram, что противоречит правилам платформы.
- Тестовый токен на продакшене или боевой токен в репозитории.
Подробности о платежах в ботах — в документации Telegram.