PayTechUZ is a unified payment library for integrating with popular payment systems in Uzbekistan. It provides a simple and consistent interface for working with Payme, Click, and Atmos payment gateways.
π Complete Documentation | π Quick Start Guide
- π API: Consistent interface for multiple payment providers
- π‘οΈ Secure: Built-in security features for payment processing
- π Framework Integration: Native support for Django and FastAPI
- π Webhook Handling: Easy-to-use webhook handlers for payment notifications
- π Transaction Management: Automatic transaction tracking and management
- π§© Extensible: Easy to add new payment providers
pip install paytechuz
# For Django
pip install paytechuz[django]
# For FastAPI
pip install paytechuz[fastapi]
π‘ Need help? Check out our complete documentation for detailed guides and examples.
from paytechuz.gateways.payme import PaymeGateway
from paytechuz.gateways.click import ClickGateway
from paytechuz.gateways.atmos import AtmosGateway
# Initialize Payme gateway
payme = PaymeGateway(
payme_id="your_payme_id",
payme_key="your_payme_key",
is_test_mode=True # Set to False in production environment
)
# Initialize Click gateway
click = ClickGateway(
service_id="your_service_id",
merchant_id="your_merchant_id",
merchant_user_id="your_merchant_user_id",
secret_key="your_secret_key",
is_test_mode=True # Set to False in production environment
)
# Initialize Atmos gateway
atmos = AtmosGateway(
consumer_key="your_consumer_key",
consumer_secret="your_consumer_secret",
store_id="your_store_id",
terminal_id="your_terminal_id", # optional
is_test_mode=True # Set to False in production environment
)
# Generate payment links
payme_link = payme.create_payment(
id="order_123",
amount=150000, # amount in UZS
return_url="https://example.com/return"
)
click_link = click.create_payment(
id="order_123",
amount=150000, # amount in UZS
description="Test payment",
return_url="https://example.com/return"
)
atmos_payment = atmos.create_payment(
account_id="order_123",
amount=150000 # amount in UZS
)
atmos_link = atmos_payment['payment_url']
# Check payment status
status = atmos.check_payment(atmos_payment['transaction_id'])
print(f"Payment status: {status['status']}")
# Cancel payment if needed
if status['status'] == 'pending':
cancel_result = atmos.cancel_payment(
transaction_id=atmos_payment['transaction_id'],
reason="Customer request"
)
print(f"Cancellation status: {cancel_result['status']}")
- Create Order model:
# models.py
from django.db import models
from django.utils import timezone
class Order(models.Model):
STATUS_CHOICES = (
('pending', 'Pending'),
('paid', 'Paid'),
('cancelled', 'Cancelled'),
('delivered', 'Delivered'),
)
product_name = models.CharField(max_length=255)
amount = models.DecimalField(max_digits=12, decimal_places=2)
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='pending')
created_at = models.DateTimeField(default=timezone.now)
def __str__(self):
return f"{self.id} - {self.product_name} ({self.amount})"
- Add to
INSTALLED_APPS
and configure settings:
# settings.py
INSTALLED_APPS = [
# ...
'paytechuz.integrations.django',
]
PAYTECHUZ = {
'PAYME': {
'PAYME_ID': 'your_payme_id',
'PAYME_KEY': 'your_payme_key',
'ACCOUNT_MODEL': 'your_app.models.Order', # For example: 'orders.models.Order'
'ACCOUNT_FIELD': 'id',
'AMOUNT_FIELD': 'amount',
'ONE_TIME_PAYMENT': True,
'IS_TEST_MODE': True, # Set to False in production
},
'CLICK': {
'SERVICE_ID': 'your_service_id',
'MERCHANT_ID': 'your_merchant_id',
'MERCHANT_USER_ID': 'your_merchant_user_id',
'SECRET_KEY': 'your_secret_key',
'ACCOUNT_MODEL': 'your_app.models.Order',
'COMMISSION_PERCENT': 0.0,
'IS_TEST_MODE': True, # Set to False in production
},
'ATMOS': {
'CONSUMER_KEY': 'your_atmos_consumer_key',
'CONSUMER_SECRET': 'your_atmos_consumer_secret',
'STORE_ID': 'your_atmos_store_id',
'TERMINAL_ID': 'your_atmos_terminal_id', # Optional
'API_KEY': 'your_atmos_api_key'
'ACCOUNT_MODEL': 'your_app.models.Order',
'ACCOUNT_FIELD': 'id',
'IS_TEST_MODE': True, # Set to False in production
}
}
- Create webhook handlers:
# views.py
from paytechuz.integrations.django.views import (
BasePaymeWebhookView,
BaseClickWebhookView,
BaseAtmosWebhookView
)
from .models import Order
class PaymeWebhookView(BasePaymeWebhookView):
def successfully_payment(self, params, transaction):
order = Order.objects.get(id=transaction.account_id)
order.status = 'paid'
order.save()
def cancelled_payment(self, params, transaction):
order = Order.objects.get(id=transaction.account_id)
order.status = 'cancelled'
order.save()
class ClickWebhookView(BaseClickWebhookView):
def successfully_payment(self, params, transaction):
order = Order.objects.get(id=transaction.account_id)
order.status = 'paid'
order.save()
def cancelled_payment(self, params, transaction):
order = Order.objects.get(id=transaction.account_id)
order.status = 'cancelled'
order.save()
class AtmosWebhookView(BaseAtmosWebhookView):
def successfully_payment(self, params, transaction):
order = Order.objects.get(id=transaction.account_id)
order.status = 'paid'
order.save()
def cancelled_payment(self, params, transaction):
order = Order.objects.get(id=transaction.account_id)
order.status = 'cancelled'
order.save()
- Add webhook URLs to
urls.py
:
# urls.py
from django.urls import path
from django.views.decorators.csrf import csrf_exempt
from .views import PaymeWebhookView, ClickWebhookView, AtmosWebhookView
urlpatterns = [
# ...
path('payments/webhook/payme/', csrf_exempt(PaymeWebhookView.as_view()), name='payme_webhook'),
path('payments/webhook/click/', csrf_exempt(ClickWebhookView.as_view()), name='click_webhook'),
path('payments/webhook/atmos/', csrf_exempt(AtmosWebhookView.as_view()), name='atmos_webhook'),
]
- Set up database models:
from datetime import datetime, timezone
from sqlalchemy.orm import sessionmaker
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime
from paytechuz.integrations.fastapi import Base as PaymentsBase
from paytechuz.integrations.fastapi.models import run_migrations
# Create database engine
SQLALCHEMY_DATABASE_URL = "sqlite:///./payments.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL)
# Create base declarative class
Base = declarative_base()
# Create Order model
class Order(Base):
__tablename__ = "orders"
id = Column(Integer, primary_key=True, index=True)
product_name = Column(String, index=True)
amount = Column(Float)
status = Column(String, default="pending")
created_at = Column(DateTime, default=lambda: datetime.now(timezone.utc))
# Create payment tables using run_migrations
run_migrations(engine)
# Create Order table
Base.metadata.create_all(bind=engine)
# Create session
SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)
- Create webhook handlers:
from fastapi import FastAPI, Request, Depends
from sqlalchemy.orm import Session
from paytechuz.integrations.fastapi import PaymeWebhookHandler, ClickWebhookHandler
from paytechuz.gateways.atmos.webhook import AtmosWebhookHandler
app = FastAPI()
# Dependency to get the database session
def get_db():
db = SessionLocal()
try:
yield db
finally:
db.close()
class CustomPaymeWebhookHandler(PaymeWebhookHandler):
def successfully_payment(self, params, transaction):
# Handle successful payment
order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
order.status = "paid"
self.db.commit()
def cancelled_payment(self, params, transaction):
# Handle cancelled payment
order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
order.status = "cancelled"
self.db.commit()
class CustomClickWebhookHandler(ClickWebhookHandler):
def successfully_payment(self, params, transaction):
# Handle successful payment
order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
order.status = "paid"
self.db.commit()
def cancelled_payment(self, params, transaction):
# Handle cancelled payment
order = self.db.query(Order).filter(Order.id == transaction.account_id).first()
order.status = "cancelled"
self.db.commit()
@app.post("/payments/payme/webhook")
async def payme_webhook(request: Request, db: Session = Depends(get_db)):
handler = CustomPaymeWebhookHandler(
db=db,
payme_id="your_merchant_id",
payme_key="your_merchant_key",
account_model=Order,
account_field='id',
amount_field='amount'
)
return await handler.handle_webhook(request)
@app.post("/payments/click/webhook")
async def click_webhook(request: Request, db: Session = Depends(get_db)):
handler = CustomClickWebhookHandler(
db=db,
service_id="your_service_id",
secret_key="your_secret_key",
account_model=Order
)
return await handler.handle_webhook(request)
@app.post("/payments/atmos/webhook")
async def atmos_webhook(request: Request, db: Session = Depends(get_db)):
import json
# Atmos webhook handler
atmos_handler = AtmosWebhookHandler(api_key="your_atmos_api_key")
try:
# Get request body
body = await request.body()
webhook_data = json.loads(body.decode('utf-8'))
# Process webhook
response = atmos_handler.handle_webhook(webhook_data)
if response['status'] == 1:
# Payment successful
invoice = webhook_data.get('invoice')
# Update order status
order = db.query(Order).filter(Order.id == invoice).first()
if order:
order.status = "paid"
db.commit()
return response
except Exception as e:
return {
'status': 0,
'message': f'Error: {str(e)}'
}
Detailed documentation is available in multiple languages:
- Django Integration Guide | Django integratsiyasi bo'yicha qo'llanma
- FastAPI Integration Guide | FastAPI integratsiyasi bo'yicha qo'llanma
- Atmos Integration Guide | Atmos integratsiyasi bo'yicha qo'llanma
- Payme - Official Website
- Click - Official Website
- Atmos - Official Website
Contributions are welcome! Please feel free to submit a Pull Request.
π Documentation: pay-tech.uz
π Issues: GitHub Issues
π¬ Support: Telegram
This project is licensed under the MIT License - see the LICENSE file for details.