dj-paypal-checkout
A modern, REST-first PayPal integration for Django: Orders v2 checkout, refunds and verified webhooks, with models, signals and admin.
Status: 0.4.0. One-off payments are covered end to end: configuration, OAuth2 auth with token caching, sync/async HTTP clients, amount handling, models with persisted idempotency keys, the Orders v2 create/authorize/capture flows, refunds and voids, verified webhooks, a reconciliation command, signals, a read-only admin and a runnable demo. A refund whose call was interrupted is resolved rather than guessed: its exact request body and idempotency key are persisted before the call and replayed on an explicit retry, and while the outcome is in doubt the amount stays reserved, so the same money cannot be refunded twice. Subscriptions add the products/plans catalog, create/revise and lifecycle operations, verified lifecycle/payment webhooks and recurring-payment records. Payment Method Tokens v3 adds setup/payment tokens, verified Vault webhooks and local audit records. Browser-side Card Fields still requires merchant enablement and application UI.
It has not been run against live PayPal traffic yet, and the API may still change on minor versions before 1.0.
Why another PayPal library?
The established django-paypal package is built on Payments Standard with
IPN/PDT, i.e. PayPal's Classic stack. PayPal now recommends webhooks for all
new integrations and IPN is not fired by newer payment products. Meanwhile
PayPal's own paypal-server-sdk is sync-only and ships neither webhook
signature verification nor the subscription plans/products catalog.
This library targets the current REST APIs and fills those gaps:
| Area | API / implementation |
|---|---|
| Checkout | Orders v2 (create → approve → capture) |
| Captures/refunds | Payments v2, with a local guard against over-refunding |
| Notifications | Webhooks with RSA-SHA256 signature verification — no IPN |
| Client side | JS SDK v6 loader; checkout UI remains application policy |
| Subscriptions | Subscriptions v1 + plans/products catalog and lifecycle webhooks |
| Saved methods | Payment Method Tokens v3 (setup tokens → permanent vault tokens) |
| Async | sync and async client, same surface |
Design principles
- The server owns the amount. It is computed from your own order; the browser only ever receives a PayPal order id.
- Webhooks are the source of truth for money having moved, and handlers are idempotent — PayPal retries, and events can arrive more than once.
- Writes are idempotent, via
PayPal-Request-Id, so a retry cannot double-charge. Decimalend to end, with currency-correct scale (never float).- One config entry point: a single
PAYPALsettings dict, read only bypaypal_checkout.config. - The DB is a local cache of PayPal state — concrete models plus a generic FK to your own order object, so admin, audit and re-sync work out of the box.
Requirements
- Python 3.11+
- Django 5.2 LTS or 6.0
Try it
example/ is a runnable sandbox checkout — two endpoints, signals, and a
read-only admin:
cp example/.env.example example/.env
# Edit example/.env with the client id and secret of a PayPal sandbox REST app.
./run_demo.sh # http://127.0.0.1:8000/
run_demo.sh loads example/.env automatically. The file is ignored by Git
and must never contain live credentials. PAYPAL_WEBHOOK_ID is optional for
the synchronous checkout and is only needed to test verified webhook delivery.
The demo also sets Django's SECURE_CROSS_ORIGIN_OPENER_POLICY to
"same-origin-allow-popups", as required for the cross-origin PayPal popup to
communicate with its opener.
Development
# Run the test suite (custom runner, uses tests/test_settings.py)
python tests/runtests.py
# Coverage (what CI runs; fails below 100% via .coveragerc)
coverage run tests/runtests.py && coverage report -m
# Docs the way CI and Read the Docs build them (warnings are errors)
sphinx-build -W --keep-going -b html docs/source docs/build/html
Invoke tasks are available too: invoke test, invoke coverage,
invoke docs, invoke clean.
License
MIT — see LICENSE.
Metadata
Release files for dj-paypal-checkout 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| dj_paypal_checkout-0.4.0.tar.gz | 105.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| dj_paypal_checkout-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 178.1 kB
Release files / dj_paypal_checkout-0.4.0.tar.gz
| Download URL | dj_paypal_checkout-0.4.0.tar.gz |
|---|---|
| Size | 105.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
34880cfb4c5b0bef75924883820cde16d901ec8e337ad2e44a1fdf0aa4109405
|
|
BLAKE2b-256 checksum How to use checksums |
d100f0d04599c64618ba0b762669db1187745ae4a450251af59c7001b0bdced2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency logRelease files / dj_paypal_checkout-0.4.0-py3-none-any.whl
| Download URL | dj_paypal_checkout-0.4.0-py3-none-any.whl |
|---|---|
| Size | 72.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
7de8ee6f8ed1c904551ead60ab02877a32a866a863632237956906cbb1728669
|
|
BLAKE2b-256 checksum How to use checksums |
be1357005ff7dd3848e061b22fd31ee1714b4e94b7d4eee550ba7d32b69d8355
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
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.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 31, 2026.
Transparency log