Webhooks for syncing Stripe payment data to your Django database.
Project description
Stripe Webhooks for Django
django-stripe-hooks is a Django application that keeps your local database in sync with Stripe by consuming webhook events.
Instead of making manual API calls every time you need Stripe data, this library automatically maintains local, up-to-date copies of Stripe objects in your database.
Incoming webhooks are signature-verified and routed to update_or_create calls on the corresponding Django model.
Your database reflects Stripe's authoritative state; you query it like any other Django model.
The local models are read-only mirrors of Stripe.
Always create or modify Stripe objects through the Stripe SDK (or Dashboard) — the corresponding local model will be updated automatically when the webhook arrives.
If you need the local instance immediately (e.g. in the same request context, without waiting for a webhook), you can call Model.objects.from_stripe() directly on the return value of any SDK method:
stripe_customer = stripe_client.v1.customers.create(params={...})
customer = Customer.objects.from_stripe(stripe_customer) # synced immediately
This library facilitates Stripe integration. Always test thoroughly in Stripe's test mode before deploying to production.
Supported Models
| Stripe Object | Django Model |
|---|---|
| Product | Product |
| Price | Price |
| Coupon | Coupon |
| PromotionCode | PromotionCode |
| Discount | Discount |
| Customer | Customer |
| PaymentMethod | PaymentMethod |
| PaymentIntent | PaymentIntent |
| Subscription | Subscription |
| SubscriptionItem | SubscriptionItem |
| Invoice | Invoice |
| InvoiceLineItem | InvoiceLineItem |
| InvoicePayment | InvoicePayment |
| BalanceTransaction | BalanceTransaction |
| Charge | Charge |
| Refund | Refund |
Installation and Configuration
1. Install the package
pip install django-stripe-hooks
2. Add to INSTALLED_APPS
INSTALLED_APPS = [
# ...
'django_stripe_hooks',
]
3. Add Stripe credentials to settings.py
Retrieve your API keys from the Stripe Dashboard.
STRIPE_PUBLIC_KEY = "pk_live_..."
STRIPE_SECRET_KEY = "sk_live_..."
STRIPE_WEBHOOK_SECRET_KEY = "whsec_..." # filled in after step 5
Security: Never commit API keys to version control. Use environment variables or a secrets manager.
4. Include the webhook URL
In your project's urls.py:
from django.urls import path, include
urlpatterns = [
path('stripe/', include('django_stripe_hooks.urls')),
# ...
]
This exposes https://yourdomain.com/stripe/webhooks/ as the webhook endpoint.
If you prefer to use a custom URL (e.g. because you are subclassing StripeWebhooks), see the Custom URL section below.
5. Run migrations
python manage.py migrate
6. Run the setup management command
python manage.py setup_stripe
This interactive command will allow you to create, update, and manage your Stripe webhook endpoint directly from the command line.
After creation, the command prints two values to add to your settings.py:
STRIPE_WEBHOOK_ENDPOINT_ID = "we_..." # used to update the endpoint later
STRIPE_WEBHOOK_SECRET_KEY = "whsec_..." # used to verify incoming signatures
Important:
STRIPE_WEBHOOK_SECRET_KEYis only returned once by Stripe. Copy it immediately.
Re-run python manage.py setup_stripe any time you need to update the endpoint URL or event subscriptions.
7. Run the import management command (optional)
If you have existing Stripe data that you want to import into your local database, run:
python manage.py import_stripe_data
API Version
This package pins the Stripe Python SDK to version 14.x, which uses API version 2026-02-25.clover.
The setup_stripe management command creates webhook endpoints using the SDK's API version automatically — no manual version selection in the Stripe Dashboard is required.
Author Hooks
To react to specific webhook events (e.g. sending a welcome email when a subscription is created), subclass StripeWebhooks and add a method named after the event type with dots replaced by underscores:
from django_stripe_hooks.views import StripeWebhooks
class MyStripeWebhooks(StripeWebhooks):
def customer_subscription_created(self) -> None:
subscription = self.django_obj
send_mail(
subject="Thanks for subscribing!",
message="...",
from_email="noreply@example.com",
recipient_list=[subscription.customer.email],
)
def invoice_paid(self) -> None:
# self.event — the raw Stripe Event object
# self.stripe_obj — the fetched Stripe object (Invoice in this case)
# self.django_obj — the corresponding Django model instance
...
Hook methods are called after the local database has been updated, so self.django_obj always reflects the latest state.
Hook methods may optionally return an HttpResponse.
If they return None, the default 200 OK response is used.
Note: If the object type is not implemented by this library (e.g. a
KeyErrorduring model resolution), the hook is still called butself.stripe_objandself.django_objwill not be set. Guard accordingly if you handle unimplemented event types.
Custom URL
If you use a subclassed view, remove the django_stripe_hooks.urls include and register your view directly:
# urls.py
from django.urls import path
from myapp.views import MyStripeWebhooks
urlpatterns = [
path('payments/webhooks/', MyStripeWebhooks.as_view(), name='stripe_webhooks'),
]
Keep the name='stripe_webhooks' so the setup_stripe management command can resolve the path automatically.
If you use a different name, the command will prompt you to enter the path manually.
Webhook Delivery Caveats
Stripe delivers webhooks asynchronously and without guaranteed ordering. A few consequences to be aware of:
-
Events may arrive out of order. For example, an
invoice.paidevent may arrive before thecustomer.createdevent for the same customer. The library handles this withdb_constraint=Falseon all foreign keys — Stripe is the authoritative source, and referential integrity is enforced at the application level rather than the database level. -
Events may be retried. If your endpoint returns a non-2xx response, Stripe will retry the event. The library's
update_or_createlogic is idempotent, so retries are safe. -
Events may be delayed. In practice, most webhooks arrive within a few seconds, but network conditions and Stripe processing can delay delivery by minutes. Do not rely on webhooks for time-critical operations where you need an immediate response.
-
Not all objects generate webhooks.
SubscriptionItem,InvoiceLineItem,InvoicePayment, andBalanceTransactiondo not have their own Stripe webhook events. They are populated as nested objects within parent webhook payloads (e.g. acustomer.subscription.updatedevent includes subscription items).
Testing
To install dev dependencies and set up the test environment:
git clone git@github.com:geoffrey-eisenbarth/django-stripe-hooks.git
cd django-stripe-hooks
pip install poetry
poetry install --with dev
The integration test suite requires the Stripe CLI to forward webhook events to your local server.
1. Install the Stripe CLI
curl -L https://github.com/stripe/stripe-cli/releases/download/v1.39.0/stripe_1.39.0_linux_x86_64.tar.gz | sudo tar -xz -C /usr/local/bin stripe
stripe --version
2. Configure test credentials
Copy .env.example to .env and fill in your Stripe test-mode keys:
STRIPE_PUBLIC_KEY=pk_test_...
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET_KEY is set automatically by the test suite via the Stripe CLI tunnel.
3. Run tests
poetry run pytest -s
To generate a coverage report:
poetry run pytest --cov --cov-branch --cov-report=xml
Troubleshooting
OSError: [Errno 98] Address already in use— runpkill stripeto clear any hanging CLI processes.- Detailed webhook forwarding logs are written to
tests/stripe_cli.log.
License
Distributed under the MIT license.
Support
Open an issue for bugs or questions.
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_stripe_hooks-0.2.0.dev1.tar.gz.
File metadata
- Download URL: django_stripe_hooks-0.2.0.dev1.tar.gz
- Upload date:
- Size: 32.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.3.3 CPython/3.14.3 Linux/6.17.0-1008-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
df332817fa3426ac16efa58e5c005471106156e0bc868e21b866ac819ab7fda3
|
|
| MD5 |
0e02168d8e880117546d4e0155ec6e0c
|
|
| BLAKE2b-256 |
8a1ed7ea2d2fd4f76ff3daac25128e9d44e24510c844d1423859e3cd7e723ca6
|
File details
Details for the file django_stripe_hooks-0.2.0.dev1-py3-none-any.whl.
File metadata
- Download URL: django_stripe_hooks-0.2.0.dev1-py3-none-any.whl
- Upload date:
- Size: 34.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: poetry/2.3.3 CPython/3.14.3 Linux/6.17.0-1008-azure
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
681d939799a70c3f4e81245f08aba22a5fce5240ca91a54ee8802799bf75af51
|
|
| MD5 |
a248475de57997ce5c58c426b5f57dc2
|
|
| BLAKE2b-256 |
f2e0b9536aad78b97cfdd06c5e1d11c526387ebbefaa57f46c6d4dd56b994787
|