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 Django UserGroup tied to that plan
  • StripeCustomer: stores the Stripe customer ID, subscription ID, user, and active plan

By default, the webhook handles these event types:

  • checkout.session.completed
  • customer.subscription.updated
  • customer.subscription.deleted

1. Create the Stripe products and prices

In Stripe:

  1. open Products
  2. create each subscription product
  3. add at least one recurring price for each product
  4. 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 basic or premium

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:

  1. create a Plan for each Stripe price
  2. paste the Stripe price_... value into stripe_price_id
  3. set the display name
  4. set the ranking used to sort plans on the pricing page
  5. 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_...

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:

  1. open Developers -> Webhooks
  2. add an endpoint for https://interviewdb.com/subscription/webhook/
  3. subscribe it to:
    • checkout.session.completed
    • customer.subscription.updated
    • customer.subscription.deleted
  4. 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.