Python

Как сделать оплату в Telegram-боте через ЮMoney на Python

Для приема оплаты в Telegram-боте на Python обычно используют не прямой перевод на личный кошелек ЮMoney, а платежный провайдер ЮKassa, подключенный к боту через BotFather. После подключения бот отправляет пользователю счет через sendInvoice, Telegram проводит платеж через провайдера, а ваш код получает событие об успешной оплате

Важно разделить два сценария. Если вы хотите принимать оплату прямо внутри Telegram, вам нужен платежный токен провайдера из BotFather. Если вы хотите создавать платеж на своей странице или через отдельную ссылку ЮKassa, это уже другая интеграция через API ЮKassa и redirect-сценарий

Как устроена оплата внутри Telegram

Схема такая

  1. Вы подключаете платежного провайдера к боту в BotFather
  2. BotFather выдает provider_token
  3. Бот отправляет счет пользователю через sendInvoice
  4. Пользователь оплачивает счет в интерфейсе Telegram
  5. Telegram отправляет боту pre_checkout_query
  6. Бот подтверждает, что заказ можно оплатить
  7. После оплаты бот получает сообщение successful_payment
  8. Вы выдаете товар, доступ, файл, курс или другой результат оплаты

Ключевой момент: оплату не нужно «проверять вручную» по сообщению пользователя. Нужно обрабатывать системное событие successful_payment

Что понадобится перед кодом

Перед программированием подготовьте

  • Telegram-бота, созданного через BotFather
  • подключение платежей в BotFather
  • provider_token от платежного провайдера
  • тестовый или рабочий аккаунт ЮKassa
  • Python 3.10+ и библиотеку для Telegram-бота
  • понимание, что суммы в Telegram передаются в минимальных единицах валюты, например в копейках для рублей

Для примеров ниже используем aiogram, потому что он хорошо подходит для асинхронных Telegram-ботов

python -m pip install aiogram

Минимальный пример счета в aiogram

Ниже пример учебной структуры. Токены нельзя хранить прямо в коде в реальном проекте, лучше брать их из переменных окружения

import asyncio
import os

from aiogram import Bot, Dispatcher, F
from aiogram.filters import Command
from aiogram.types import LabeledPrice, Message, PreCheckoutQuery

BOT_TOKEN = os.getenv("BOT_TOKEN")
PAYMENT_PROVIDER_TOKEN = os.getenv("PAYMENT_PROVIDER_TOKEN")

bot = Bot(token=BOT_TOKEN)
dp = Dispatcher()

@dp.message(Command("buy"))
async def buy_course(message: Message):
    prices = [
        LabeledPrice(label="Доступ к мини-курсу", amount=99000)
    ]

    await message.answer_invoice(
        title="Мини-курс Python",
        description="Доступ к учебным материалам и заданиям",
        payload="python_course_001",
        provider_token=PAYMENT_PROVIDER_TOKEN,
        currency="RUB",
        prices=prices
    )

@dp.pre_checkout_query()
async def process_pre_checkout(pre_checkout_query: PreCheckoutQuery):
    await pre_checkout_query.answer(ok=True)

@dp.message(F.successful_payment)
async def process_successful_payment(message: Message):
    payment = message.successful_payment
    await message.answer(
        f"Оплата прошла успешно. Номер платежа: {payment.provider_payment_charge_id}"
    )

async def main():
    await dp.start_polling(bot)

if __name__ == "__main__":
    asyncio.run(main())

В примере amount=99000 означает 990 рублей 00 копеек, потому что сумма передается в копейках. Если написать 990, пользователь увидит 9 рублей 90 копеек

Как хранить токены

Не пишите токены прямо в файл

Плохо

BOT_TOKEN = "123456:secret"
PAYMENT_PROVIDER_TOKEN = "381764678:TEST:secret"

Лучше через переменные окружения

export BOT_TOKEN="ваш_токен_бота"
export PAYMENT_PROVIDER_TOKEN="токен_провайдера"
python bot.py
$env:BOT_TOKEN="ваш_токен_бота"
$env:PAYMENT_PROVIDER_TOKEN="токен_провайдера"
python bot.py

Так меньше риск случайно отправить токен в GitHub, скриншот или чат

Что такое payload и зачем он нужен

payload — это ваша внутренняя метка заказа. Пользователь ее не видит, но вы можете по ней понять, что именно он покупал

Примеры payload

payload="python_course_001"
payload="premium_month_2026_06"
payload="order_4581"

В реальном проекте лучше не ограничиваться статичной строкой. Создайте заказ в базе данных, получите его ID и положите этот ID в payload. После успешной оплаты вы найдете заказ и отметите его оплаченным

Зачем нужен pre_checkout_query

Перед финальным списанием Telegram отправляет боту pre_checkout_query. Бот должен быстро ответить ok=True, если заказ можно оплатить

@dp.pre_checkout_query()
async def process_pre_checkout(pre_checkout_query: PreCheckoutQuery):
    await pre_checkout_query.answer(ok=True)

Здесь можно проверить

  • существует ли заказ
  • актуальна ли цена
  • доступен ли товар
  • не был ли заказ уже оплачен
  • не истек ли срок действия счета

Если проверка не прошла, можно ответить ok=False и показать причину

await pre_checkout_query.answer(
    ok=False,
    error_message="Заказ устарел, создайте новый счет"
)

Как выдать доступ после оплаты

После оплаты приходит successful_payment. Только после этого события стоит выдавать доступ

@dp.message(F.successful_payment)
async def process_successful_payment(message: Message):
    payment = message.successful_payment

    user_id = message.from_user.id
    payload = payment.invoice_payload
    charge_id = payment.provider_payment_charge_id

    print("Пользователь:", user_id)
    print("Заказ:", payload)
    print("Платеж провайдера:", charge_id)

    await message.answer("Оплата получена, доступ открыт")

Для учебного бота достаточно сообщения. Для рабочего проекта нужно записать платеж в базу, связать его с пользователем и заказом, а затем выдать доступ идемпотентно: если событие придет повторно, доступ не должен задвоиться

ЮMoney и ЮKassa: что не перепутать

В быту часто говорят «оплата через ЮMoney», но для бизнеса и приема платежей в Telegram обычно используется ЮKassa. В документации Telegram и BotFather логика строится вокруг платежного провайдера и provider_token

Если вам нужен прием платежей за товары, курсы, услуги или подписку, проверяйте именно сценарий ЮKassa для Telegram-ботов. Перевод на личный кошелек ЮMoney не заменяет нормальную платежную интеграцию: там сложнее автоматическая проверка, фискализация, учет заказов и статусы оплаты

Типичные ошибки при оплате в боте

Сумму передают в рублях, а не копейках

Для RUB сумма 99000 означает 990 рублей. Сумма 990 означает 9 рублей 90 копеек

Не обрабатывают pre_checkout_query

Если бот не отвечает на pre_checkout_query, платеж не завершится корректно

Выдают товар до successful_payment

Нажатие на кнопку оплаты еще не равно успешной оплате. Доступ открывается только после события successful_payment

Путают токен бота и provider token

BOT_TOKEN нужен для управления ботом. provider_token нужен для платежей. Это разные значения

Хранят токены в коде

Токены должны лежать в переменных окружения или секретах сервера, а не в файле проекта

Мини-практика

Сделайте тестового бота с командой /buy, которая отправляет счет на 100 рублей. После успешной оплаты бот должен вывести сообщение: «Оплата получена, заказ открыт»

Проверьте три вещи

  • сумма отображается правильно
  • pre_checkout_query подтверждается
  • после оплаты вы видите provider_payment_charge_id

Если эти три пункта работают, у вас есть базовая платежная схема. Дальше можно подключать базу данных, реальные заказы и выдачу доступа

Что почитать дальше по Python

Если нужен общий маршрут по теме, откройте рубрику Python. Для соседних задач пригодятся эти разборы:

Подписаться
Уведомить о
guest
0 комментариев
Старые
Новые Популярные

Настройки cookie

0
Оставьте комментарий! Напишите, что думаете по поводу статьи.x