├── requirements.txt ├── .env ├── .env.example ├── config.py ├── models.py ├── README.md └── bot.py /requirements.txt: -------------------------------------------------------------------------------- 1 | python-telegram-bot==20.7 2 | sqlalchemy==2.0.28 3 | stripe==7.11.0 4 | paypalrestsdk==1.13.1 5 | coinbase-commerce==1.0.1 6 | python-dotenv==1.0.0 7 | aiosqlite==0.19.0 -------------------------------------------------------------------------------- /.env: -------------------------------------------------------------------------------- 1 | # Telegram Bot Token (Get from @BotFather) 2 | TELEGRAM_TOKEN= 3 | 4 | # Stripe API Keys (Get from Stripe Dashboard) 5 | STRIPE_API_KEY=your_stripe_secret_key 6 | 7 | # PayPal API Keys (Get from PayPal Developer Dashboard) 8 | PAYPAL_CLIENT_ID=your_paypal_client_id 9 | PAYPAL_CLIENT_SECRET=your_paypal_client_secret 10 | 11 | # Coinbase Commerce API Key (Get from Coinbase Commerce Dashboard) 12 | COINBASE_API_KEY=your_coinbase_api_key 13 | 14 | # Admin Configuration (Comma-separated list of Telegram user IDs) 15 | ADMIN_USER_IDS= 16 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # Telegram Bot Token (Get from @BotFather) 2 | TELEGRAM_TOKEN=your_telegram_bot_token 3 | 4 | # Stripe API Keys (Get from Stripe Dashboard) 5 | STRIPE_API_KEY=your_stripe_secret_key 6 | 7 | # PayPal API Keys (Get from PayPal Developer Dashboard) 8 | PAYPAL_CLIENT_ID=your_paypal_client_id 9 | PAYPAL_CLIENT_SECRET=your_paypal_client_secret 10 | 11 | # Coinbase Commerce API Key (Get from Coinbase Commerce Dashboard) 12 | COINBASE_API_KEY=your_coinbase_api_key 13 | 14 | # Admin Configuration (Comma-separated list of Telegram user IDs) 15 | ADMIN_USER_IDS=123456789,987654321 -------------------------------------------------------------------------------- /config.py: -------------------------------------------------------------------------------- 1 | import os 2 | from dotenv import load_dotenv 3 | 4 | load_dotenv() 5 | 6 | # Telegram Bot Token 7 | TELEGRAM_TOKEN = os.getenv('TELEGRAM_TOKEN') 8 | 9 | # Payment API Keys 10 | STRIPE_API_KEY = os.getenv('STRIPE_API_KEY') 11 | PAYPAL_CLIENT_ID = os.getenv('PAYPAL_CLIENT_ID') 12 | PAYPAL_CLIENT_SECRET = os.getenv('PAYPAL_CLIENT_SECRET') 13 | COINBASE_API_KEY = os.getenv('COINBASE_API_KEY') 14 | 15 | # Admin Configuration 16 | ADMIN_USER_IDS = [int(id) for id in os.getenv('ADMIN_USER_IDS', '').split(',') if id] 17 | 18 | # Database Configuration 19 | DATABASE_URL = "sqlite:///digital_store.db" -------------------------------------------------------------------------------- /models.py: -------------------------------------------------------------------------------- 1 | from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, ForeignKey, Enum 2 | from sqlalchemy.ext.declarative import declarative_base 3 | from sqlalchemy.orm import relationship 4 | import enum 5 | from datetime import datetime 6 | 7 | Base = declarative_base() 8 | 9 | class PaymentMethod(enum.Enum): 10 | CREDIT_CARD = "credit_card" 11 | PAYPAL = "paypal" 12 | CRYPTOCURRENCY = "cryptocurrency" 13 | 14 | class PaymentStatus(enum.Enum): 15 | PENDING = "pending" 16 | COMPLETED = "completed" 17 | FAILED = "failed" 18 | 19 | class Customer(Base): 20 | __tablename__ = 'customers' 21 | 22 | id = Column(Integer, primary_key=True) 23 | telegram_id = Column(Integer, unique=True) 24 | username = Column(String) 25 | first_name = Column(String) 26 | last_name = Column(String) 27 | created_at = Column(DateTime, default=datetime.utcnow) 28 | 29 | orders = relationship("Order", back_populates="customer") 30 | 31 | class Product(Base): 32 | __tablename__ = 'products' 33 | 34 | id = Column(Integer, primary_key=True) 35 | name = Column(String, nullable=False) 36 | description = Column(String) 37 | price = Column(Float, nullable=False) 38 | digital_content_url = Column(String, nullable=False) 39 | created_at = Column(DateTime, default=datetime.utcnow) 40 | 41 | orders = relationship("Order", back_populates="product") 42 | 43 | class Order(Base): 44 | __tablename__ = 'orders' 45 | 46 | id = Column(Integer, primary_key=True) 47 | customer_id = Column(Integer, ForeignKey('customers.id')) 48 | product_id = Column(Integer, ForeignKey('products.id')) 49 | payment_method = Column(Enum(PaymentMethod)) 50 | payment_status = Column(Enum(PaymentStatus), default=PaymentStatus.PENDING) 51 | amount = Column(Float, nullable=False) 52 | transaction_id = Column(String) 53 | created_at = Column(DateTime, default=datetime.utcnow) 54 | 55 | customer = relationship("Customer", back_populates="orders") 56 | product = relationship("Product", back_populates="orders") -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Digital Products Telegram Bot 2 | 3 | A Telegram bot for selling digital products with multiple payment methods support (Credit Card, PayPal, and Cryptocurrency). 4 | 5 | ## Features 6 | 7 | - 🛍️ Digital product catalog management 8 | - 💳 Multiple payment methods: 9 | - Credit Card (via Stripe) 10 | - PayPal 11 | - Cryptocurrency (via Coinbase Commerce) 12 | - 👤 Customer management 13 | - 📦 Order tracking 14 | - 🔐 Admin panel for product management 15 | 16 | ## Prerequisites 17 | 18 | - Python 3.11 (recommended) or lower version 19 | - Telegram Bot Token (from [@BotFather](https://t.me/BotFather)) 20 | - Payment service accounts: 21 | - [Stripe](https://stripe.com) 22 | - [PayPal Developer](https://developer.paypal.com) 23 | - [Coinbase Commerce](https://commerce.coinbase.com) 24 | 25 | ## Setup Instructions 26 | 27 | 1. **Clone the repository** 28 | ```bash 29 | git clone 30 | cd telegram-bot 31 | ``` 32 | 33 | 2. **Create and activate virtual environment** 34 | ```bash 35 | # Windows 36 | python -m venv .venv 37 | .\.venv\Scripts\activate 38 | 39 | # Linux/Mac 40 | python3 -m venv .venv 41 | source .venv/bin/activate 42 | ``` 43 | 44 | 3. **Install dependencies** 45 | ```bash 46 | pip install -r requirements.txt 47 | ``` 48 | 49 | 4. **Configure environment variables** 50 | ```bash 51 | # Copy example environment file 52 | cp .env.example .env 53 | 54 | # Edit .env file with your credentials: 55 | # - TELEGRAM_TOKEN (from @BotFather) 56 | # - STRIPE_API_KEY 57 | # - PAYPAL_CLIENT_ID and PAYPAL_CLIENT_SECRET 58 | # - COINBASE_API_KEY 59 | # - ADMIN_USER_IDS (your Telegram user ID, get it from @userinfobot) 60 | ``` 61 | 62 | 5. **Run the bot** 63 | ```bash 64 | python bot.py 65 | ``` 66 | 67 | ## Usage 68 | 69 | ### Admin Commands 70 | - `/start` - Start the bot 71 | - `/add_product` - Add a new digital product 72 | - `/cancel` - Cancel current operation 73 | 74 | ### Customer Flow 75 | 1. Start chat with bot 76 | 2. Browse products using "View Products 🛍" button 77 | 3. Select a product 78 | 4. Choose payment method 79 | 5. Complete payment 80 | 6. Receive digital product 81 | 82 | ### Managing Products (Admin) 83 | 1. Use `/add_product` command 84 | 2. Follow the prompts to enter: 85 | - Product name 86 | - Description 87 | - Price 88 | - Digital content URL 89 | 90 | ### Viewing Orders 91 | - Click "My Orders 📦" to view order history 92 | - Orders show status, payment method, and delivery status 93 | 94 | ## Payment Methods 95 | 96 | ### Credit Card (Stripe) 97 | - Secure checkout page 98 | - Supports major credit cards 99 | - Instant payment confirmation 100 | 101 | ### PayPal 102 | - Redirect to PayPal login 103 | - Secure payment processing 104 | - Support for PayPal balance and linked accounts 105 | 106 | ### Cryptocurrency (Coinbase Commerce) 107 | - Support for multiple cryptocurrencies 108 | - Real-time exchange rates 109 | - Secure blockchain transactions 110 | 111 | ## Troubleshooting 112 | 113 | If you encounter any issues: 114 | 115 | 1. **Bot not responding** 116 | - Check if bot is running 117 | - Verify TELEGRAM_TOKEN in .env 118 | 119 | 2. **Payment errors** 120 | - Verify API keys in .env 121 | - Check payment service dashboard for errors 122 | 123 | 3. **Database issues** 124 | - Check if digital_store.db exists 125 | - Verify database permissions 126 | 127 | ## Security Notes 128 | 129 | - Never share your .env file 130 | - Keep API keys confidential 131 | - Regularly update dependencies 132 | - Monitor transactions for suspicious activity 133 | 134 | ## Support 135 | 136 | For support, please: 137 | 1. Check troubleshooting guide 138 | 2. Review error logs 139 | 3. Contact administrator 140 | 141 | ## License 142 | 143 | This project is licensed under the MIT License - see the LICENSE file for details. -------------------------------------------------------------------------------- /bot.py: -------------------------------------------------------------------------------- 1 | import logging 2 | from telegram import Update, InlineKeyboardButton, InlineKeyboardMarkup 3 | from telegram.ext import Application, CommandHandler, CallbackQueryHandler, MessageHandler, ContextTypes, filters, ConversationHandler 4 | from sqlalchemy import create_engine 5 | from sqlalchemy.orm import sessionmaker 6 | import stripe 7 | import paypalrestsdk 8 | from coinbase_commerce.client import Client 9 | import json 10 | from decimal import Decimal 11 | 12 | from config import ( 13 | TELEGRAM_TOKEN, DATABASE_URL, STRIPE_API_KEY, 14 | PAYPAL_CLIENT_ID, PAYPAL_CLIENT_SECRET, COINBASE_API_KEY, 15 | ADMIN_USER_IDS 16 | ) 17 | from models import Base, Customer, Product, Order, PaymentMethod, PaymentStatus 18 | 19 | # Setup logging 20 | logging.basicConfig(format='%(asctime)s - %(name)s - %(levelname)s - %(message)s', level=logging.INFO) 21 | logger = logging.getLogger(__name__) 22 | 23 | # Setup database 24 | engine = create_engine(DATABASE_URL) 25 | Base.metadata.create_all(engine) 26 | SessionLocal = sessionmaker(bind=engine) 27 | 28 | # Setup payment providers 29 | stripe.api_key = STRIPE_API_KEY 30 | paypalrestsdk.configure({ 31 | "mode": "sandbox", # Change to "live" in production 32 | "client_id": PAYPAL_CLIENT_ID, 33 | "client_secret": PAYPAL_CLIENT_SECRET 34 | }) 35 | coinbase_client = Client(api_key=COINBASE_API_KEY) 36 | 37 | # Conversation states 38 | PRODUCT_NAME, PRODUCT_DESCRIPTION, PRODUCT_PRICE, PRODUCT_URL = range(4) 39 | 40 | def is_admin(user_id: int) -> bool: 41 | """Check if user is admin""" 42 | return user_id in ADMIN_USER_IDS 43 | 44 | async def add_product(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 45 | """Start the product addition process""" 46 | if not is_admin(update.effective_user.id): 47 | await update.message.reply_text("Sorry, this command is only available to administrators.") 48 | return ConversationHandler.END 49 | 50 | await update.message.reply_text("Let's add a new product! First, what's the product name?") 51 | return PRODUCT_NAME 52 | 53 | async def product_name(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 54 | """Save product name and ask for description""" 55 | context.user_data['product_name'] = update.message.text 56 | await update.message.reply_text("Great! Now, please provide a description for the product:") 57 | return PRODUCT_DESCRIPTION 58 | 59 | async def product_description(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 60 | """Save product description and ask for price""" 61 | context.user_data['product_description'] = update.message.text 62 | await update.message.reply_text("Please enter the price in USD (e.g., 9.99):") 63 | return PRODUCT_PRICE 64 | 65 | async def product_price(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 66 | """Save product price and ask for digital content URL""" 67 | try: 68 | price = float(update.message.text) 69 | context.user_data['product_price'] = price 70 | await update.message.reply_text("Please provide the URL where the digital content can be accessed:") 71 | return PRODUCT_URL 72 | except ValueError: 73 | await update.message.reply_text("Please enter a valid price (e.g., 9.99)") 74 | return PRODUCT_PRICE 75 | 76 | async def product_url(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 77 | """Save product URL and finish product creation""" 78 | context.user_data['product_url'] = update.message.text 79 | 80 | session = SessionLocal() 81 | new_product = Product( 82 | name=context.user_data['product_name'], 83 | description=context.user_data['product_description'], 84 | price=context.user_data['product_price'], 85 | digital_content_url=context.user_data['product_url'] 86 | ) 87 | session.add(new_product) 88 | session.commit() 89 | session.close() 90 | 91 | await update.message.reply_text("Product added successfully! ✅") 92 | return ConversationHandler.END 93 | 94 | async def cancel(update: Update, context: ContextTypes.DEFAULT_TYPE) -> int: 95 | """Cancel the conversation.""" 96 | await update.message.reply_text("Product addition cancelled.") 97 | return ConversationHandler.END 98 | 99 | async def start(update: Update, context: ContextTypes.DEFAULT_TYPE): 100 | """Start command handler""" 101 | user = update.effective_user 102 | session = SessionLocal() 103 | 104 | # Register customer if not exists 105 | customer = session.query(Customer).filter_by(telegram_id=user.id).first() 106 | if not customer: 107 | customer = Customer( 108 | telegram_id=user.id, 109 | username=user.username, 110 | first_name=user.first_name, 111 | last_name=user.last_name 112 | ) 113 | session.add(customer) 114 | session.commit() 115 | 116 | keyboard = [ 117 | [InlineKeyboardButton("View Products 🛍", callback_data="view_products")], 118 | [InlineKeyboardButton("My Orders 📦", callback_data="my_orders")] 119 | ] 120 | reply_markup = InlineKeyboardMarkup(keyboard) 121 | 122 | await update.message.reply_text( 123 | f"Welcome to the Digital Products Store, {user.first_name}! 🎉\n" 124 | "What would you like to do?", 125 | reply_markup=reply_markup 126 | ) 127 | session.close() 128 | 129 | async def view_products(update: Update, context: ContextTypes.DEFAULT_TYPE): 130 | """Handler for viewing products""" 131 | query = update.callback_query 132 | session = SessionLocal() 133 | 134 | products = session.query(Product).all() 135 | keyboard = [] 136 | 137 | for product in products: 138 | keyboard.append([ 139 | InlineKeyboardButton( 140 | f"{product.name} - ${product.price:.2f}", 141 | callback_data=f"product_{product.id}" 142 | ) 143 | ]) 144 | 145 | keyboard.append([InlineKeyboardButton("Back to Menu 🔙", callback_data="start")]) 146 | reply_markup = InlineKeyboardMarkup(keyboard) 147 | 148 | await query.edit_message_text( 149 | "Here are our available products:", 150 | reply_markup=reply_markup 151 | ) 152 | session.close() 153 | 154 | async def handle_product_selection(update: Update, context: ContextTypes.DEFAULT_TYPE): 155 | """Handler for product selection""" 156 | query = update.callback_query 157 | product_id = int(query.data.split('_')[1]) 158 | session = SessionLocal() 159 | 160 | product = session.query(Product).filter_by(id=product_id).first() 161 | 162 | keyboard = [ 163 | [ 164 | InlineKeyboardButton("Credit Card 💳", callback_data=f"pay_cc_{product_id}"), 165 | InlineKeyboardButton("PayPal 📱", callback_data=f"pay_pp_{product_id}") 166 | ], 167 | [InlineKeyboardButton("Cryptocurrency 🪙", callback_data=f"pay_crypto_{product_id}")], 168 | [InlineKeyboardButton("Back to Products 🔙", callback_data="view_products")] 169 | ] 170 | reply_markup = InlineKeyboardMarkup(keyboard) 171 | 172 | await query.edit_message_text( 173 | f"Product: {product.name}\n" 174 | f"Price: ${product.price:.2f}\n" 175 | f"Description: {product.description}\n\n" 176 | "Choose your payment method:", 177 | reply_markup=reply_markup 178 | ) 179 | session.close() 180 | 181 | async def my_orders(update: Update, context: ContextTypes.DEFAULT_TYPE): 182 | """Handler for viewing order history""" 183 | query = update.callback_query 184 | user_id = update.effective_user.id 185 | session = SessionLocal() 186 | 187 | customer = session.query(Customer).filter_by(telegram_id=user_id).first() 188 | if not customer: 189 | await query.edit_message_text("No orders found.") 190 | session.close() 191 | return 192 | 193 | orders = session.query(Order).filter_by(customer_id=customer.id).all() 194 | if not orders: 195 | await query.edit_message_text( 196 | "You haven't placed any orders yet.", 197 | reply_markup=InlineKeyboardMarkup([[InlineKeyboardButton("Back to Menu 🔙", callback_data="start")]]) 198 | ) 199 | session.close() 200 | return 201 | 202 | order_text = "Your Orders:\n\n" 203 | for order in orders: 204 | product = order.product 205 | order_text += f"Order #{order.id}\n" 206 | order_text += f"Product: {product.name}\n" 207 | order_text += f"Amount: ${order.amount:.2f}\n" 208 | order_text += f"Status: {order.payment_status.value}\n" 209 | order_text += f"Date: {order.created_at.strftime('%Y-%m-%d %H:%M:%S')}\n\n" 210 | 211 | keyboard = [[InlineKeyboardButton("Back to Menu 🔙", callback_data="start")]] 212 | await query.edit_message_text( 213 | order_text, 214 | reply_markup=InlineKeyboardMarkup(keyboard) 215 | ) 216 | session.close() 217 | 218 | async def process_stripe_payment(update: Update, context: ContextTypes.DEFAULT_TYPE): 219 | """Handle Stripe payment""" 220 | query = update.callback_query 221 | product_id = int(query.data.split('_')[2]) 222 | session = SessionLocal() 223 | 224 | product = session.query(Product).filter_by(id=product_id).first() 225 | customer = session.query(Customer).filter_by(telegram_id=update.effective_user.id).first() 226 | 227 | try: 228 | # Create Stripe checkout session 229 | checkout_session = stripe.checkout.Session.create( 230 | payment_method_types=['card'], 231 | line_items=[{ 232 | 'price_data': { 233 | 'currency': 'usd', 234 | 'product_data': { 235 | 'name': product.name, 236 | 'description': product.description, 237 | }, 238 | 'unit_amount': int(product.price * 100), 239 | }, 240 | 'quantity': 1, 241 | }], 242 | mode='payment', 243 | success_url='https://t.me/your_bot_username', 244 | cancel_url='https://t.me/your_bot_username', 245 | ) 246 | 247 | # Create pending order 248 | order = Order( 249 | customer_id=customer.id, 250 | product_id=product.id, 251 | payment_method=PaymentMethod.CREDIT_CARD, 252 | payment_status=PaymentStatus.PENDING, 253 | amount=product.price, 254 | transaction_id=checkout_session.id 255 | ) 256 | session.add(order) 257 | session.commit() 258 | 259 | # Send payment link 260 | await query.edit_message_text( 261 | f"Please complete your payment using this link:\n{checkout_session.url}\n\n" 262 | "After payment, you'll receive your digital product.", 263 | reply_markup=InlineKeyboardMarkup([[ 264 | InlineKeyboardButton("Back to Menu 🔙", callback_data="start") 265 | ]]) 266 | ) 267 | 268 | except Exception as e: 269 | logger.error(f"Stripe payment error: {str(e)}") 270 | await query.edit_message_text( 271 | "Sorry, there was an error processing your payment. Please try again later.", 272 | reply_markup=InlineKeyboardMarkup([[ 273 | InlineKeyboardButton("Back to Menu 🔙", callback_data="start") 274 | ]]) 275 | ) 276 | finally: 277 | session.close() 278 | 279 | async def process_paypal_payment(update: Update, context: ContextTypes.DEFAULT_TYPE): 280 | """Handle PayPal payment""" 281 | query = update.callback_query 282 | product_id = int(query.data.split('_')[2]) 283 | session = SessionLocal() 284 | 285 | product = session.query(Product).filter_by(id=product_id).first() 286 | customer = session.query(Customer).filter_by(telegram_id=update.effective_user.id).first() 287 | 288 | try: 289 | payment = paypalrestsdk.Payment({ 290 | "intent": "sale", 291 | "payer": {"payment_method": "paypal"}, 292 | "transactions": [{ 293 | "amount": { 294 | "total": f"{product.price:.2f}", 295 | "currency": "USD" 296 | }, 297 | "description": f"Purchase of {product.name}" 298 | }], 299 | "redirect_urls": { 300 | "return_url": "https://t.me/your_bot_username", 301 | "cancel_url": "https://t.me/your_bot_username" 302 | } 303 | }) 304 | 305 | if payment.create(): 306 | # Create pending order 307 | order = Order( 308 | customer_id=customer.id, 309 | product_id=product.id, 310 | payment_method=PaymentMethod.PAYPAL, 311 | payment_status=PaymentStatus.PENDING, 312 | amount=product.price, 313 | transaction_id=payment.id 314 | ) 315 | session.add(order) 316 | session.commit() 317 | 318 | # Get approval URL 319 | approval_url = next(link.href for link in payment.links if link.rel == "approval_url") 320 | 321 | await query.edit_message_text( 322 | f"Please complete your payment using this link:\n{approval_url}\n\n" 323 | "After payment, you'll receive your digital product.", 324 | reply_markup=InlineKeyboardMarkup([[ 325 | InlineKeyboardButton("Back to Menu 🔙", callback_data="start") 326 | ]]) 327 | ) 328 | else: 329 | raise Exception(payment.error) 330 | 331 | except Exception as e: 332 | logger.error(f"PayPal payment error: {str(e)}") 333 | await query.edit_message_text( 334 | "Sorry, there was an error processing your payment. Please try again later.", 335 | reply_markup=InlineKeyboardMarkup([[ 336 | InlineKeyboardButton("Back to Menu 🔙", callback_data="start") 337 | ]]) 338 | ) 339 | finally: 340 | session.close() 341 | 342 | async def process_crypto_payment(update: Update, context: ContextTypes.DEFAULT_TYPE): 343 | """Handle Cryptocurrency payment""" 344 | query = update.callback_query 345 | product_id = int(query.data.split('_')[2]) 346 | session = SessionLocal() 347 | 348 | product = session.query(Product).filter_by(id=product_id).first() 349 | customer = session.query(Customer).filter_by(telegram_id=update.effective_user.id).first() 350 | 351 | try: 352 | # Create Coinbase Commerce charge 353 | charge = coinbase_client.charge.create( 354 | name=product.name, 355 | description=product.description, 356 | pricing_type="fixed_price", 357 | local_price={ 358 | "amount": str(product.price), 359 | "currency": "USD" 360 | } 361 | ) 362 | 363 | # Create pending order 364 | order = Order( 365 | customer_id=customer.id, 366 | product_id=product.id, 367 | payment_method=PaymentMethod.CRYPTOCURRENCY, 368 | payment_status=PaymentStatus.PENDING, 369 | amount=product.price, 370 | transaction_id=charge.id 371 | ) 372 | session.add(order) 373 | session.commit() 374 | 375 | await query.edit_message_text( 376 | f"Please complete your crypto payment using this link:\n{charge.hosted_url}\n\n" 377 | "After payment, you'll receive your digital product.", 378 | reply_markup=InlineKeyboardMarkup([[ 379 | InlineKeyboardButton("Back to Menu 🔙", callback_data="start") 380 | ]]) 381 | ) 382 | 383 | except Exception as e: 384 | logger.error(f"Crypto payment error: {str(e)}") 385 | await query.edit_message_text( 386 | "Sorry, there was an error processing your payment. Please try again later.", 387 | reply_markup=InlineKeyboardMarkup([[ 388 | InlineKeyboardButton("Back to Menu 🔙", callback_data="start") 389 | ]]) 390 | ) 391 | finally: 392 | session.close() 393 | 394 | async def handle_successful_payment(update: Update, context: ContextTypes.DEFAULT_TYPE): 395 | """Handle successful payment webhook""" 396 | session = SessionLocal() 397 | data = json.loads(update.webhook_data) 398 | 399 | try: 400 | # Find the order based on transaction ID 401 | order = session.query(Order).filter_by(transaction_id=data['id']).first() 402 | if order: 403 | order.payment_status = PaymentStatus.COMPLETED 404 | session.commit() 405 | 406 | # Send digital product to customer 407 | await context.bot.send_message( 408 | chat_id=order.customer.telegram_id, 409 | text=f"Thank you for your purchase! Here's your digital product:\n{order.product.digital_content_url}" 410 | ) 411 | except Exception as e: 412 | logger.error(f"Payment webhook error: {str(e)}") 413 | finally: 414 | session.close() 415 | 416 | def main(): 417 | """Start the bot""" 418 | application = Application.builder().token(TELEGRAM_TOKEN).build() 419 | 420 | # Add conversation handler for product management 421 | conv_handler = ConversationHandler( 422 | entry_points=[CommandHandler('add_product', add_product)], 423 | states={ 424 | PRODUCT_NAME: [MessageHandler(filters.TEXT & ~filters.COMMAND, product_name)], 425 | PRODUCT_DESCRIPTION: [MessageHandler(filters.TEXT & ~filters.COMMAND, product_description)], 426 | PRODUCT_PRICE: [MessageHandler(filters.TEXT & ~filters.COMMAND, product_price)], 427 | PRODUCT_URL: [MessageHandler(filters.TEXT & ~filters.COMMAND, product_url)], 428 | }, 429 | fallbacks=[CommandHandler('cancel', cancel)], 430 | ) 431 | 432 | # Add handlers 433 | application.add_handler(conv_handler) 434 | application.add_handler(CommandHandler("start", start)) 435 | application.add_handler(CallbackQueryHandler(view_products, pattern="^view_products$")) 436 | application.add_handler(CallbackQueryHandler(start, pattern="^start$")) 437 | application.add_handler(CallbackQueryHandler(handle_product_selection, pattern="^product_")) 438 | application.add_handler(CallbackQueryHandler(my_orders, pattern="^my_orders$")) 439 | application.add_handler(CallbackQueryHandler(process_stripe_payment, pattern="^pay_cc_")) 440 | application.add_handler(CallbackQueryHandler(process_paypal_payment, pattern="^pay_pp_")) 441 | application.add_handler(CallbackQueryHandler(process_crypto_payment, pattern="^pay_crypto_")) 442 | 443 | # Start the bot 444 | application.run_polling(allowed_updates=Update.ALL_TYPES) 445 | 446 | if __name__ == '__main__': 447 | main() --------------------------------------------------------------------------------