What We're Building
A fully functional e-commerce bot that:
- Displays product catalog with categories
- Accepts Telegram Stars as payment
- Delivers digital files instantly
- Tracks purchases in SQLite
Prerequisites
- Python 3.9+
-
pyTelegramBotAPIlibrary - Bot token from @botfather
pip install pyTelegramBotAPI
Step 1: Bot Setup
import telebot
from telebot.types import (
InlineKeyboardMarkup, InlineKeyboardButton,
LabeledPrice
)
import sqlite3
import os
TOKEN = os.environ.get('BOT_TOKEN')
bot = telebot.TeleBot(TOKEN)
Step 2: Product Catalog
CATEGORIES = {
'templates': 'Code Templates',
'notion': 'Notion Systems',
'career': 'Career Guides',
'ai': 'AI Toolkits'
}
PRODUCTS = {
'starter_kit': {
'name': 'Starter Kit Pro',
'description': 'Complete project templates with MVVM, networking, and more',
'stars': 75,
'category': 'templates',
'file': 'products/starter_kit.pdf'
},
'notion_brain': {
'name': 'Second Brain System',
'description': 'Notion-based knowledge management',
'stars': 40,
'category': 'notion',
'file': 'products/notion_brain.pdf'
},
# Add more products...
}
Step 3: Main Menu
@bot.message_handler(commands=['start'])
def start(message):
keyboard = InlineKeyboardMarkup(row_width=2)
for cat_id, cat_name in CATEGORIES.items():
keyboard.add(InlineKeyboardButton(
cat_name,
callback_data=f'category_{cat_id}'
))
bot.send_message(
message.chat.id,
'Welcome to the Digital Shop!\n'
'Browse our products by category:',
reply_markup=keyboard
)
Step 4: Category Browsing
@bot.callback_query_handler(func=lambda c: c.data.startswith('category_'))
def show_category(call):
category = call.data.replace('category_', '')
keyboard = InlineKeyboardMarkup(row_width=1)
for pid, product in PRODUCTS.items():
if product['category'] == category:
keyboard.add(InlineKeyboardButton(
f"{product['name']} — {product['stars']}⭐",
callback_data=f'product_{pid}'
))
keyboard.add(InlineKeyboardButton(
'← Back to Menu',
callback_data='main_menu'
))
bot.edit_message_text(
f"📂 {CATEGORIES[category]}",
call.message.chat.id,
call.message.message_id,
reply_markup=keyboard
)
Step 5: Product Details
@bot.callback_query_handler(func=lambda c: c.data.startswith('product_'))
def show_product(call):
pid = call.data.replace('product_', '')
product = PRODUCTS[pid]
keyboard = InlineKeyboardMarkup()
keyboard.add(InlineKeyboardButton(
f"Buy for {product['stars']}⭐",
callback_data=f'buy_{pid}'
))
keyboard.add(InlineKeyboardButton(
'← Back',
callback_data=f"category_{product['category']}"
))
bot.edit_message_text(
f"**{product['name']}**\n\n"
f"{product['description']}\n\n"
f"Price: {product['stars']} ⭐",
call.message.chat.id,
call.message.message_id,
reply_markup=keyboard,
parse_mode='Markdown'
)
Step 6: Payment (The Key Part)
@bot.callback_query_handler(func=lambda c: c.data.startswith('buy_'))
def buy_product(call):
pid = call.data.replace('buy_', '')
product = PRODUCTS[pid]
bot.send_invoice(
call.message.chat.id,
title=product['name'],
description=product['description'],
invoice_payload=pid,
provider_token='', # Empty for Stars!
currency='XTR', # Telegram Stars
prices=[LabeledPrice(
label=product['name'],
amount=product['stars']
)]
)
@bot.pre_checkout_query_handler(func=lambda q: True)
def pre_checkout(query):
bot.answer_pre_checkout_query(query.id, ok=True)
@bot.message_handler(content_types=['successful_payment'])
def payment_success(message):
pid = message.successful_payment.invoice_payload
product = PRODUCTS[pid]
# Deliver the product
with open(product['file'], 'rb') as f:
bot.send_document(
message.chat.id, f,
caption=f"Here's your {product['name']}!"
)
# Save purchase
save_to_db(message.from_user.id, pid, product['stars'])
Step 7: Database
def init_db():
conn = sqlite3.connect('shop.db')
conn.execute('''CREATE TABLE IF NOT EXISTS purchases (
id INTEGER PRIMARY KEY AUTOINCREMENT,
user_id INTEGER,
product_id TEXT,
amount INTEGER,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
)''')
conn.commit()
conn.close()
def save_to_db(user_id, product_id, amount):
conn = sqlite3.connect('shop.db')
conn.execute(
'INSERT INTO purchases (user_id, product_id, amount) VALUES (?, ?, ?)',
(user_id, product_id, amount)
)
conn.commit()
conn.close()
Step 8: Run
if __name__ == '__main__':
init_db()
print('Bot is running...')
bot.infinity_polling()
Key Points
-
provider_token=''means Telegram Stars (no external payment provider) -
currency='XTR'is the currency code for Stars - Always handle
pre_checkout_queryor payments will fail -
successful_paymentis where you deliver the product
Live Example
Try @SwiftUIDailyBot on Telegram to see this in action with 26 real products.
Channel: t.me/SwiftUIDaily
Found this helpful? Follow me for more Python and SwiftUI tutorials.
Top comments (0)