Production-oriented Django integration for the Click.uz payment gateway
Project description
django-click-uz
Django 5+ integration for the Click.uz Shop API: payment URLs, prepare/complete webhooks, MD5 signatures, optional audit log, replay protection, HTTPS and optional IP checks on callbacks.
| O‘zbekcha (batafsil) | README_UZ.md |
| Changelog | CHANGELOG.md |
| Repository | github.com/Matnazar-Matnazarov/django-click-uz |
| Extra docs (Markdown) | docs/ |
What’s in the package
| Part | Role |
|---|---|
click_uz |
Django app: add to INSTALLED_APPS, run migrations, include urls. Endpoints: prepare/, complete/, callback/, webhook/. Includes webhook_guard, ModelOrderHandler, signals, Uzbek locale/uz. |
click_up |
Compatibility imports only: ClickUp, ClickWebhook, unique_transaction_param. Do not add to INSTALLED_APPS. |
| Config | CLICK dict or flat CLICK_*; optional WEBHOOK_ALLOWED_CIDRS, WEBHOOK_REQUIRE_HTTPS, WEBHOOK_STRICT_IN_DEBUG. |
Requirements
- Python 3.12+
- Django 5.0+
Installation
pip install django-click-uz
# settings.py
INSTALLED_APPS = [
# ...
"django.contrib.contenttypes",
"django.contrib.auth",
"click_uz",
"orders", # your app with Order model
]
Configuration
Use either the CLICK dict or flat CLICK_* variables. If both are set, CLICK wins.
Option A — CLICK dict (recommended)
import os
CLICK = {
"SERVICE_ID": int(os.environ["CLICK_SERVICE_ID"]),
"MERCHANT_ID": int(os.environ["CLICK_MERCHANT_ID"]),
"SECRET_KEY": os.environ["CLICK_SECRET_KEY"],
# Optional Click user id for Merchant API; defaults to MERCHANT_ID if omitted
# "USER_ID": 12345,
"ACCOUNT_MODEL": "orders.Order",
"AMOUNT_FIELD": "amount",
"STATUS_FIELD": "status",
"STATUS_PENDING": "pending",
"STATUS_WAITING": "waiting_payment",
"STATUS_PAID": "paid",
"STATUS_CANCELLED": "cancelled",
"MERCHANT_TRANS_FIELD": "transaction_param",
"COMMISSION_PERCENT": 0,
"DISABLE_ADMIN": False,
"ENABLE_AUDIT": True,
# Production hardening (optional):
# "WEBHOOK_ALLOWED_CIDRS": ["203.0.113.0/24"],
# "WEBHOOK_STRICT_IN_DEBUG": True,
}
Option B — flat settings (legacy / click-pkg style)
CLICK_SERVICE_ID = 12345
CLICK_MERCHANT_ID = 67890
CLICK_SECRET_KEY = "your-secret-key"
CLICK_ACCOUNT_MODEL = "orders.Order"
CLICK_AMOUNT_FIELD = "amount"
CLICK_STATUS_FIELD = "status"
CLICK_MERCHANT_TRANS_FIELD = "transaction_param"
CLICK_COMMISSION_PERCENT = 0
CLICK_DISABLE_ADMIN = False
Webhooks require HANDLER_CLASS or ACCOUNT_MODEL + AMOUNT_FIELD + STATUS_FIELD.
Example: Order model
After prepare, the default handler sets status to waiting_payment; on success complete → paid; on rejection → cancelled. Align STATUS_* in CLICK with your choices.
# orders/models.py
from django.conf import settings
from django.db import models
class Order(models.Model):
user = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
null=True,
blank=True,
)
amount = models.DecimalField(max_digits=12, decimal_places=2)
status = models.CharField(
max_length=32,
choices=[
("pending", "Pending"),
("waiting_payment", "Waiting payment"),
("paid", "Paid"),
("cancelled", "Cancelled"),
],
default="pending",
)
transaction_param = models.CharField(max_length=255, blank=True, default="")
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self) -> str:
return f"Order {self.pk} — {self.amount}"
python manage.py makemigrations
python manage.py migrate
URLs
A) Include package routes (single webhook URL for the Click cabinet):
from django.urls import include, path
urlpatterns = [
path("payment/click/", include("click_uz.urls")),
]
Webhook example: https://your-domain.example/payment/click/webhook/
(same prefix: prepare/, complete/, callback/).
B) Custom path with your ClickWebhook subclass:
from django.urls import path
from orders.views import ClickWebhookAPIView
urlpatterns = [
path("payment/click/update/", ClickWebhookAPIView.as_view(), name="click-webhook"),
]
Register the full HTTPS URL in the Click merchant cabinet.
Views: webhook + pay link
Webhook subclass
params contains snapshot fields (id, merchant_trans_id, amount, state, …) and a nested payload with Click fields.
# orders/views.py
from click_up.views import ClickWebhook
from .models import Order
class ClickWebhookAPIView(ClickWebhook):
def successfully_payment(self, params):
order_id = params.get("id")
try:
order = Order.objects.get(pk=order_id)
# Model handler already set status to paid; add email, analytics, etc.
except Order.DoesNotExist:
pass
def cancelled_payment(self, params):
pass
def prepare_accepted(self, params):
"""Optional: runs after prepare succeeds."""
pass
Create order + payment link (simple — order PK as transaction_param)
import json
from django.http import JsonResponse
from django.utils.decorators import method_decorator
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from click_up import ClickUp
from .models import Order
@method_decorator(csrf_exempt, name="dispatch")
class CreateOrderView(View):
def post(self, request):
body = json.loads(request.body or "{}")
amount = body.get("amount")
order = Order.objects.create(
user=request.user if getattr(request, "user", None) and request.user.is_authenticated else None,
amount=amount,
)
paylink = ClickUp().initializer.generate_pay_link(
id=order.pk,
amount=order.amount,
return_url="https://example.com/orders/done/",
unique_transaction_id=False,
)
return JsonResponse({"order_id": order.pk, "payment_link": paylink})
Recommended: unique transaction_param per checkout
from click_up import ClickUp, unique_transaction_param
from .models import Order
tid = unique_transaction_param(order.pk)
order.transaction_param = tid
order.save(update_fields=["transaction_param"])
paylink = ClickUp().initializer.generate_pay_link(
id=order.pk,
amount=order.amount,
return_url="https://example.com/orders/done/",
transaction_param=tid,
)
Requires MERCHANT_TRANS_FIELD / CLICK_MERCHANT_TRANS_FIELD pointing at transaction_param (see configuration above).
Django REST Framework: same logic inside APIView.post, using request.data instead of json.loads.
Security & operations
- Callback JSON to Click stays in English; Django admin / config messages can use
click_uztranslations (locale/uz/). - MD5
sign_stringverification is the main authenticity check. click_uz.webhook_guard: enforce HTTPS in production; optionalWEBHOOK_ALLOWED_CIDRS. Behind a TLS-terminating proxy, setSECURE_PROXY_SSL_HEADER.
Documentation (local)
No hosted doc site is provided. To build the MkDocs site locally:
pip install -e ".[dev]"
# or: uv sync --all-extras
mkdocs serve
Open the URL printed in the terminal (usually http://127.0.0.1:8000).
Development
pip install -e ".[dev]"
pytest
Releases: bump version in pyproject.toml, update CHANGELOG.md, commit, then tag and push vX.Y.Z (e.g. v0.1.2) to trigger publish.yml. Each PyPI upload needs a new version.
vs older click-pkg tutorials
| Old tutorial | This package |
|---|---|
pip install click-pkg |
pip install django-click-uz |
INSTALLED_APPS: click_up |
Only click_uz |
is_test_mode |
Use Click test credentials / PAY_URL from Click docs if applicable |
License
MIT — see LICENSE.
Click API reference: docs.click.uz.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_click_uz-0.1.2.tar.gz.
File metadata
- Download URL: django_click_uz-0.1.2.tar.gz
- Upload date:
- Size: 27.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
088b8506f4e82184128acf638fc630ac88cd4c61e65ed39037e2511b29e52b4a
|
|
| MD5 |
48f6ad0c920e22d72ee6113bddb45831
|
|
| BLAKE2b-256 |
d0be79a934edfadd4069cacbb299c5263d560c4f882d4e1ea414f865a4354142
|
Provenance
The following attestation bundles were made for django_click_uz-0.1.2.tar.gz:
Publisher:
publish.yml on Matnazar-Matnazarov/django-click-uz
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_click_uz-0.1.2.tar.gz -
Subject digest:
088b8506f4e82184128acf638fc630ac88cd4c61e65ed39037e2511b29e52b4a - Sigstore transparency entry: 1239437991
- Sigstore integration time:
-
Permalink:
Matnazar-Matnazarov/django-click-uz@b33edd0fddbea254f929f2a84680e9b6791b43aa -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/Matnazar-Matnazarov
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b33edd0fddbea254f929f2a84680e9b6791b43aa -
Trigger Event:
push
-
Statement type:
File details
Details for the file django_click_uz-0.1.2-py3-none-any.whl.
File metadata
- Download URL: django_click_uz-0.1.2-py3-none-any.whl
- Upload date:
- Size: 29.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0fccc6ce14f4d4bb7ba5b4d587398459b7b0f3fb721266a63a8b8c882d07bb2d
|
|
| MD5 |
3ae5add72c91d5d1767f03e0048f9114
|
|
| BLAKE2b-256 |
cbdf56c61e3fa81c930daac6e898e51e32a12e03442328a74e08e4f8388d777d
|
Provenance
The following attestation bundles were made for django_click_uz-0.1.2-py3-none-any.whl:
Publisher:
publish.yml on Matnazar-Matnazarov/django-click-uz
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
django_click_uz-0.1.2-py3-none-any.whl -
Subject digest:
0fccc6ce14f4d4bb7ba5b4d587398459b7b0f3fb721266a63a8b8c882d07bb2d - Sigstore transparency entry: 1239437992
- Sigstore integration time:
-
Permalink:
Matnazar-Matnazarov/django-click-uz@b33edd0fddbea254f929f2a84680e9b6791b43aa -
Branch / Tag:
refs/tags/v0.1.2 - Owner: https://github.com/Matnazar-Matnazarov
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b33edd0fddbea254f929f2a84680e9b6791b43aa -
Trigger Event:
push
-
Statement type: