django-gocardless-billing
A reusable Django app for GoCardless Direct Debit billing. Handles webhook intake, idempotency, async Celery processing, Billing Request flows, subscriptions, and Django signals — so each of your SaaS projects gets UK Direct Debit billing in minutes, not days.
Companion package to django-stripe-billing.
Full configuration guide (env vars, Dashboard, production, Celery): see CONFIGURATION.md.
Features
- Billing Request + Flow —
create_billing_request_flow()(instant first payment + BACS mandate) - Subscriptions —
create_subscription_for_mandate()after mandate activation - Webhook receiver — signature verification, idempotency, audit trail
- Async processing — optional Celery task with exponential backoff
- Django signals — connect custom logic per event type without touching the package
- Outgoing webhooks — Zapier / Make / n8n integration per event type
- Admin —
GoCardlessWebhookEventwith status badges - Python 3.10+, Django 4.2+
Quick Start
1. Install
pip install django-gocardless-billing
# Optional: async webhook processing
pip install django-gocardless-billing[celery]
2. Add to INSTALLED_APPS
INSTALLED_APPS = [
...
'django_gocardless_billing',
]
3. Configure
GOCARDLESS_BILLING = {
'GOCARDLESS_ACCESS_TOKEN': env('GOCARDLESS_ACCESS_TOKEN_SANDBOX'),
'GOCARDLESS_WEBHOOK_SECRET': env('GOCARDLESS_WEBHOOK_SECRET_SANDBOX'),
'GOCARDLESS_MODE': 'sandbox', # 'sandbox' or 'live'
'ENVIRONMENT': env('ENVIRONMENT', default='production'),
'SUCCESS_URL': 'https://myapp.com/gocardless/success/',
'EXIT_URL': 'https://myapp.com/subscribe/',
'PROJECT_SLUG': 'my_saas',
'PLAN_RESOLVER': 'myapp.billing.resolve_gocardless_plan',
'OUTGOING_WEBHOOK_URLS': {
'gocardless.payments.confirmed': env('WEBHOOK_GC_PAYMENT_CONFIRMED', ''),
'gocardless.payments.failed': env('WEBHOOK_GC_PAYMENT_FAILED', ''),
},
}
Zero-config migration: If you already have top-level
GOCARDLESS_ACCESS_TOKEN,GOCARDLESS_WEBHOOK_SECRET,GOCARDLESS_MODE, orREDIRECT_DOMAIN, the package reads them automatically.
4. Implement PLAN_RESOLVER
# myapp/billing.py
def resolve_gocardless_plan(plan_id: str) -> dict:
return {
'amount': 1999, # pence
'currency': 'GBP',
'interval_unit': 'monthly', # or 'yearly'
'name': 'Pro Monthly',
'description': 'Pro Monthly — first payment',
}
5. Add URL
urlpatterns = [
path('webhooks/', include('django_gocardless_billing.urls')),
# Exposes: POST /webhooks/gocardless/
]
6. Run migrations
python manage.py migrate
Creating a Billing Request Flow
from django_gocardless_billing.checkout import create_billing_request_flow
billing_request, flow = create_billing_request_flow(
user=request.user,
plan_id='pro_monthly',
customer_id=profile.gocardless_customer_id or None,
on_customer_created=lambda cid: save_customer_id(profile, cid),
)
return redirect(flow.authorisation_url, code=303)
Connecting Business Logic via Signals
from django.dispatch import receiver
from django_gocardless_billing.signals import payment_confirmed, payment_failed
@receiver(payment_confirmed)
def on_payment_confirmed(sender, event, **kwargs):
metadata = event.get('metadata') or {}
plan_id = metadata.get('plan_id')
# Update UserProfile, grant access, send emails, etc.
@receiver(payment_failed)
def on_payment_failed(sender, event, **kwargs):
...
Register receivers in your app's AppConfig.ready().
Available Signals
| Signal | GoCardless event |
|---|---|
billing_request_fulfilled |
billing_requests.fulfilled |
mandate_active |
mandates.active |
payment_confirmed |
payments.confirmed |
payment_failed |
payments.failed |
subscription_created |
subscriptions.created |
subscription_cancelled |
subscriptions.cancelled / finished |
Each signal receives event (a plain dict) in kwargs.
Architecture
django_gocardless_billing/
├── conf.py # GOCARDLESS_BILLING settings + legacy fallback
├── client.py # GoCardless Pro SDK client
├── models.py # GoCardlessWebhookEvent
├── signals.py # Django signals
├── webhooks.py # HandlerRegistry + built-in handlers
├── checkout.py # create_billing_request_flow()
├── subscriptions.py # create_subscription_for_mandate()
├── plans.py # PLAN_RESOLVER integration
├── profile.py # Direct Debit profile readiness
├── tasks.py # Celery / sync processing
├── views.py # HTTP webhook receiver
└── urls.py # path('gocardless/', ...)
See CONFIGURATION.md for full setup (sandbox/live, webhooks, production). See INTEGRATION.md for migration paths from in-app GoCardless code.
Development
cd django-gocardless-billing
pip install -e ".[dev]"
pytest
License
MIT
Metadata
Release files for django-gocardless-billing 0.1.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 | |
|---|---|---|---|
| django_gocardless_billing-0.1.0.tar.gz | 19.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| django_gocardless_billing-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 41.1 kB
Release files / django_gocardless_billing-0.1.0.tar.gz
| Download URL | django_gocardless_billing-0.1.0.tar.gz |
|---|---|
| Size | 19.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
06153d4447972c16084b507e3038752d3c001bc4de10eb1acd1d154028776930
|
|
BLAKE2b-256 checksum How to use checksums |
a3d72168f804a6852054fdf8b705012eec09a0a54649dc1e9c32192787ab0d67
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|
Release files / django_gocardless_billing-0.1.0-py3-none-any.whl
| Download URL | django_gocardless_billing-0.1.0-py3-none-any.whl |
|---|---|
| Size | 21.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5b416af4e788f7e5c5ec64c4d971c48f7df6fad689aae01da0fd0112cc4cba87
|
|
BLAKE2b-256 checksum How to use checksums |
de5f80b0f2070cd52386e065ef73405229ff1b6868737e0c8f4ab3abd9c855d0
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.13
|