Stripe Billing
The boilerplate includes a subscription module that maps Stripe prices to Django user groups. That gives you a ready billing foundation for pricing pages, checkout, subscription updates, cancellations, and self-service billing.
How the billing module is structured
The subscription app centers on two models:
Plan: stores the Stripe Price ID, display name, ranking, and the DjangoUserGrouptied to that planStripeCustomer: stores the Stripe customer ID, subscription ID, user, and active plan
By default, the webhook handles these event types:
checkout.session.completedcustomer.subscription.updatedcustomer.subscription.deleted
1. Create the Stripe products and prices
In Stripe:
- open Products
- create each subscription product
- add at least one recurring price for each product
- copy the resulting Stripe Price ID for each plan
You will paste those Price IDs into the Django admin in the next step.
2. Create the user groups first
Before you add plans, create the Django groups you want billing to control:
free- one group for each paid tier, such as
basicorpremium
The default cancellation logic moves a user back to the free group when Stripe sends a deletion event, so make sure that group exists.
3. Create the Plan records in Django admin
In Django admin:
- create a
Planfor each Stripe price - paste the Stripe
price_...value intostripe_price_id - set the display
name - set the
rankingused to sort plans on the pricing page - attach the matching
UserGroup
The pricing page reads these Plan objects directly and orders them by ranking.
4. Know the important routes
The subscription app exposes these routes:
/subscription/pricing//subscription/config//subscription/create-checkout-session//subscription/webhook//subscription/create-customer-portal-session/
If a user is not signed in when they try to check out, the boilerplate sends them through the normal authentication flow first.
5. Set the Stripe environment variables
For local development, the local settings expect these values from your shell or .env file:
export STRIPE_PUBLISHABLE_KEY=pk_test_...
export STRIPE_SECRET_KEY=sk_test_...
export STRIPE_ENDPOINT_SECRET=whsec_...
For Heroku production:
heroku config:set STRIPE_PUBLISHABLE_KEY=pk_live_...
heroku config:set STRIPE_SECRET_KEY=sk_live_...
heroku config:set STRIPE_ENDPOINT_SECRET=whsec_...
In new projects, the production Stripe settings are commented out at the
bottom of config/settings/production.py. Uncomment them before you expect
Stripe to work in production.
6. Test webhooks locally
Use the Stripe CLI to forward events to the local webhook endpoint:
stripe listen --forward-to localhost:8000/subscription/webhook/
Stripe will print a signing secret such as whsec_.... Use that value for STRIPE_ENDPOINT_SECRET.
7. Configure the production webhook
In the Stripe dashboard:
- open Developers -> Webhooks
- add an endpoint for
https://interviewdb.com/subscription/webhook/ - subscribe it to:
checkout.session.completedcustomer.subscription.updatedcustomer.subscription.deleted
- copy the production signing secret and set it in Heroku
8. Enable the customer portal
If you want users to manage payment methods and cancel on their own, turn on the Stripe customer portal in Stripe:
Settings -> Billing -> Customer portal
The boilerplate already includes a view for creating a customer portal session.
Notes on permissions
The user model exposes an is_paid property based on whether the user has a group. That is enough for the default implementation, but many production products eventually replace it with more explicit entitlement logic.