DEV Community

Cover image for Integrating Telegram Stars ⭐️ Payment in a Python Bot
King Triton
King Triton

Posted on

Integrating Telegram Stars ⭐️ Payment in a Python Bot

Today I'll show you how to set up payments in your bot using Telegram's internal currency, Telegram Stars ⭐️.

Step 1: Create a Bot

First, create a bot using BotFather. If you're familiar with this process, you can use your own test bot. In this example, I'll use the bot @repeats_bot.

The use of the bot

Step 2: Prepare the Project Structure

Here’s an example of your project structure:



TelegramStarsBot (root)
|-img/
|-img-X9ptcIuiOMICY0BUQukCpVYS.png
|-bot.py
|-config.py
|-database.py
|-.env

Enter fullscreen mode Exit fullscreen mode




Step 3: Bot Code

bot.py



import telebot
from telebot import types
from config import TOKEN
from database import init_db, save_payment
import os

bot = telebot.TeleBot(TOKEN)

# Initialize the database
init_db()

# Function to create a payment keyboard
def payment_keyboard():
keyboard = types.InlineKeyboardMarkup()
button = types.InlineKeyboardButton(text="Pay 1 XTR", pay=True)
keyboard.add(button)
return keyboard

# Function to create a keyboard with the "Buy Image" button
def start_keyboard():
keyboard = types.InlineKeyboardMarkup()
button = types.InlineKeyboardButton(text="Buy Image", callback_data="buy_image")
keyboard.add(button)
return keyboard

# /start command handler
@bot.message_handler(commands=['start'])
def handle_start(message):
bot.send_message(
message.chat.id,
"Welcome! Click the button below to buy an image.",
reply_markup=start_keyboard()
)

# Handler for the "Buy Image" button press
@bot.callback_query_handler(func=lambda call: call.data == "buy_image")
def handle_buy_image(call):
prices = [types.LabeledPrice(label="XTR", amount=1)] # 1 XTR
bot.send_invoice(
call.message.chat.id,
title="Image Purchase",
description="Purchase an image for 1 star!",
invoice_payload="image_purchase_payload",
provider_token="", # For XTR, this token can be empty
currency="XTR",
prices=prices,
reply_markup=payment_keyboard()
)

# Handler for pre-checkout queries
@bot.pre_checkout_query_handler(func=lambda query: True)
def handle_pre_checkout_query(pre_checkout_query):
bot.answer_pre_checkout_query(pre_checkout_query.id, ok=True)

# Handler for successful payments
@bot.message_handler(content_types=['successful_payment'])
def handle_successful_payment(message):
user_id = message.from_user.id
payment_id = message.successful_payment.provider_payment_charge_id
amount = message.successful_payment.total_amount
currency = message.successful_payment.currency

<span class="c1"># Send a purchase confirmation message
Enter fullscreen mode Exit fullscreen mode

bot.send_message(message.chat.id, "✅ Payment accepted, please wait for the photo. It will arrive soon!")

<span class="c1"># Save payment information to the database
Enter fullscreen mode Exit fullscreen mode

save_payment(user_id, payment_id, amount, currency)

<span class="c1"># Send the image
Enter fullscreen mode Exit fullscreen mode

photo_path = 'img/img-X9ptcIuiOMICY0BUQukCpVYS.png'
if os.path.exists(photo_path):
with open(photo_path, 'rb') as photo:
bot.send_photo(message.chat.id, photo, caption="🥳Thank you for your purchase!🤗")
else:
bot.send_message(message.chat.id, "Sorry, the image was not found.")

# /paysupport command handler
@bot.message_handler(commands=['paysupport'])
def handle_pay_support(message):
bot.send_message(
message.chat.id,
"Purchasing an image does not imply a refund. "
"If you have any questions, please contact us."
)

# Start polling
bot.polling()

Enter fullscreen mode Exit fullscreen mode




config.py




import os
from dotenv import load_dotenv

# Load environment variables from .env file
load_dotenv()

# Get values from environment variables
TOKEN = os.getenv('TOKEN')
DATABASE = os.getenv('DATABASE')

Enter fullscreen mode Exit fullscreen mode




database.py




import sqlite3
from config import DATABASE

def init_db():
with sqlite3.connect(DATABASE) as conn:
cursor = conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS payments (
user_id INTEGER,
payment_id TEXT,
amount INTEGER,
currency TEXT,
PRIMARY KEY (user_id, payment_id)
)
''')
conn.commit()

def save_payment(user_id, payment_id, amount, currency):
with sqlite3.connect(DATABASE) as conn:
cursor = conn.cursor()
cursor.execute('''
INSERT INTO payments (user_id, payment_id, amount, currency)
VALUES (?, ?, ?, ?)
''', (user_id, payment_id, amount, currency))
conn.commit()

Enter fullscreen mode Exit fullscreen mode




Code Explanation

Payments with Telegram Stars

  • payment_keyboard and start_keyboard create buttons for user interaction. The first button allows payment, and the second initiates the image purchase.
  • handle_buy_image creates and sends an invoice for payment using the XTR currency. Here, provider_token can be empty as XTR does not require a token.
  • handle_pre_checkout_query and handle_successful_payment handle the payment verification and confirmation process.
  • Upon successful payment, the bot sends the image to the user and saves the payment information in the database.

Working with the Database

  • init_db creates the payments table if it does not exist. This table stores information about the user, payment, amount, and currency.
  • save_payment saves payment information to the database. This is necessary for potential refunds and transaction reports.

Important Notes

  • Bot Owner Payment: If the bot owner tries to make a purchase within the bot, the purchase will not be completed. This prevents fraud or erroneous purchases made by the administrator.
  • Managing Stars: Stars are stored within the Telegram bot. To view the balance, go to the bot settings in Telegram, select "Manage Bot," and click "Balance." Here, you can view and manage earned stars, withdraw them, or spend them on advertising.

Bot management

Balance

Statistics telegram stars

Statistics of purchases

Conclusion

Your bot is now set up to accept payments via Telegram Stars and send an image after a successful purchase. Make sure all settings and data in the configuration files are correct.

I’d appreciate it if you leave a reaction or comment! You can also find the complete source code on GitHub.

Top comments (0)