paylinker-django
Django integration for the paylinker payment SDK.
Provides webhook views, provider transaction tracking, and abstract handler bases for Click and Payme payment providers in Uzbekistan.
Installation
pip install paylinker-django
Quick Start
1. Add to INSTALLED_APPS
INSTALLED_APPS = [
...
"paylinker_django",
]
2. Configure settings
PAYLINKER = {
"PAYME": {
"merchant_id": env("PAYME_MERCHANT_ID"),
"merchant_key": env("PAYME_SECRET_KEY"),
"test_key": env("PAYME_TEST_KEY", default=""),
"is_test": env.bool("PAYME_IS_TEST", default=False),
},
"CLICK": {
"merchant_id": int(env("CLICK_MERCHANT_ID")),
"service_id": int(env("CLICK_SERVICE_ID")),
"secret_key": env("CLICK_SECRET_KEY"),
},
"PAYME_HANDLER": "apps.payments.handlers.MyPaymeHandler",
"CLICK_HANDLER": "apps.payments.handlers.MyClickHandler",
"ACCOUNT_FIELD": "order_id",
}
3. Implement handlers
# apps/payments/handlers.py
from paylinker.providers.click.enums import ClickErrorCode
from paylinker.providers.click.webhook import OrderCheckResult
from paylinker.providers.payme.rpc_handler import PaymeError
from paylinker_django.handlers import DjangoClickOrderValidator, DjangoPaymeTransactionHandler
from .models import Order
class MyPaymeHandler(DjangoPaymeTransactionHandler):
def validate_order(self, order_id, amount_tiyin):
try:
order = Order.objects.get(pk=order_id)
except Order.DoesNotExist:
raise PaymeError(-31050, "Не найден", "Topilmadi", "Not found", "order_id")
if order.is_paid:
raise PaymeError(-31099, "Оплачен", "To'langan", "Already paid")
if int(order.amount * 100) != amount_tiyin:
raise PaymeError(-31001, "Неверная сумма", "Noto'g'ri summa", "Wrong amount")
def on_payment_performed(self, provider_tx):
order = Order.objects.get(pk=provider_tx.order_id)
order.mark_paid()
def on_payment_cancelled(self, provider_tx, reason, was_performed):
if was_performed:
order = Order.objects.get(pk=provider_tx.order_id)
order.refund()
class MyClickValidator(DjangoClickOrderValidator):
def validate_order(self, merchant_trans_id, amount):
try:
order = Order.objects.get(pk=merchant_trans_id)
except Order.DoesNotExist:
return OrderCheckResult.fail(ClickErrorCode.ORDER_NOT_FOUND, "Not found")
if float(order.amount) != amount:
return OrderCheckResult.fail(ClickErrorCode.INCORRECT_AMOUNT, "Bad amount")
return OrderCheckResult.ok()
def on_payment_completed(self, provider_tx):
order = Order.objects.get(pk=provider_tx.order_id)
order.mark_paid()
4. Include URLs
# urls.py
from django.urls import include, path
urlpatterns = [
path("payments/", include("paylinker_django.urls")),
]
This exposes:
POST /payments/webhooks/payme/— Payme JSON-RPC endpointPOST /payments/webhooks/click/— Click SHOP-API endpoint
5. Run migrations
python manage.py migrate paylinker_django
Architecture
paylinker — Core SDK (framework-agnostic)
├── configs, providers, signing, schemas, HTTP clients
└── handler protocols: TransactionHandler (Payme), OrderValidator (Click)
paylinker-django — Django adapter (this package)
├── ProviderTransaction model — tracks provider-specific state
├── DjangoPaymeTransactionHandler — manages Payme lifecycle + model CRUD
├── DjangoClickOrderValidator — manages Click lifecycle + model CRUD
├── Webhook views — parse HTTP → delegate to handlers
└── Settings integration — PAYLINKER dict in Django settings
Your project only implements business-logic hooks:
validate_order()— order existence and amount verificationon_payment_performed()/on_payment_completed()— post-payment actionson_payment_cancelled()— cancellation handling
Generating payment URLs
from paylinker_django.conf import get_payme_config, get_click_config
from paylinker import PaymeProvider, ClickProvider
# Payme
payme = PaymeProvider(get_payme_config())
url = payme.generate_payment_url(
amount=100000, # tiyin
transaction_param=str(order.pk),
account_field="order_id",
)
# Click
click = ClickProvider(get_click_config())
url = click.generate_payment_url(
amount=1000.0, # UZS
transaction_param=str(order.pk),
)
Building & Publishing
This package uses Hatchling with a single source
of truth for the version (src/paylinker_django/__init__.py).
Local build
pip install -e ".[dev]"
python -m build # produces dist/*.whl and dist/*.tar.gz
twine check --strict dist/* # validate PyPI metadata
Release workflow (recommended)
Releases are automated via GitHub Actions using PyPI Trusted Publishing
(no long-lived API tokens). One-time setup on PyPI / TestPyPI:
add this repo as a trusted publisher for the paylinker-django project,
with workflow publish.yml and environments pypi / testpypi.
Then for each release:
# 1. Bump version in src/paylinker_django/__init__.py
# 2. Update CHANGELOG.md
git commit -am "release: v0.2.0"
# 3. Tag & push → triggers TestPyPI publish
git tag v0.2.0
git push origin main --tags
# 4. Create a GitHub Release for the tag → triggers real PyPI publish
gh release create v0.2.0 --notes-from-tag
Manual publish (fallback)
python -m build
twine upload --repository testpypi dist/* # TestPyPI
twine upload dist/* # PyPI
Versioning
Follows SemVer: MAJOR.MINOR.PATCH.
License
MIT
Metadata
Release files for paylinker-django 0.1.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| paylinker_django-0.1.6.tar.gz | 17.3 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| paylinker_django-0.1.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 34.7 kB
Release files / paylinker_django-0.1.6.tar.gz
| Download URL | paylinker_django-0.1.6.tar.gz |
|---|---|
| Size | 17.3 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a8ff7bab2451fc2924507e3f058d616d878d4242176012a65d0b7810beaef883
|
|
BLAKE2b-256 checksum How to use checksums |
cebc59c53f082d73db729a171931c9d6b87ab6e8e1d2dc22169d6ce3be46457d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.11
|
Release files / paylinker_django-0.1.6-py3-none-any.whl
| Download URL | paylinker_django-0.1.6-py3-none-any.whl |
|---|---|
| Size | 17.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
98bceeac4a6a031a4e26bb303bdb04ebafa57c35df612a31045c860bbbe8bf11
|
|
BLAKE2b-256 checksum How to use checksums |
cd69f3aff2cb27fe1a6bbde9d20a9c91e8baeccc6a4a067fb065a50800ff3c20
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.11
|
Security for paylinker-django 0.1.6
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.