payments#

Stripe-based subscription management with a tier system (data, reader, premium), invoice generation, Lexoffice bookkeeping sync, guest subscriptions with access tokens, identity event tracking, and webhook idempotency.

Models#

Model

Description

SubscriptionTier

Tier definitions with dual Stripe price IDs (test/live) and feature flags

Invoice

Generated PDF invoices with email sending + Lexoffice upload tracking

Customer

Stripe customer → Django user one-to-one link

Subscription

Active or historical Stripe subscription for a registered user

GuestSubscription

Subscription for non-registered users (email + access token)

StripeCheckoutEvent

Idempotency log preventing duplicate webhook processing

IdentityEvent

Audit log for auth events (login, signup, email claim, etc.)

URL Routes#

Path

View

Description

/payments/config/

stripe_config

Returns Stripe publishable key

/payments/checkout/session/

checkout_session_view

Legacy subscription checkout

/payments/checkout/webhook/

checkout_webhook_view

Stripe webhook receiver

/payments/checkout/success/

success

Post-checkout success page

/payments/checkout/canceled/

cancel

Cancellation page

/payments/stripe_customer_portal/

portal redirect

Redirect to Stripe billing portal

/payments/tier/pricing/

tier_pricing

GET available tiers with pricing

/payments/tier/checkout/

tier_checkout_session

POST create tier checkout session

/payments/manage-tier/

manage_tier_subscription

Manage subscription (token or auth)

Management Commands#

Command

Description

backfill_user_links

Link guest purchases/subscriptions to users by matching email

identity_overview

Report on identity system events and counts

Subscription Tiers#

graph LR DATA[data tier] -->|includes_data| DP[Data Products] READER[reader tier] -->|includes_reading| BLOG[Blog Posts] READER -->|includes_data| DP PREMIUM[premium tier] -->|includes_reading| BLOG PREMIUM -->|includes_data| DP PREMIUM -->|includes_ebooks| EBOOKS[eBook Downloads]

Webhook Flow#

sequenceDiagram participant Stripe participant Webhook as checkout_webhook_view participant Events as StripeCheckoutEvent participant Invoice as Invoice Generator Stripe->>Webhook: POST event Webhook->>Events: Check event_id exists? alt Already processed Events-->>Webhook: 200 OK (skip) else New event Webhook->>Events: Create idempotency record Webhook->>Invoice: Generate PDF, email, Lexoffice Events-->>Webhook: 200 OK end

Key Design Decisions#

  • Dual Stripe price IDs (stripe_price_id_test / stripe_price_id_live) on SubscriptionTier allow seamless switching between Stripe test and live mode via a settings flag.

  • Guest subscriptions use email + access_token for access without requiring registration.

  • StripeCheckoutEvent provides webhook idempotency — every event is checked by event_id before processing to prevent duplicate invoice generation.

  • IdentityEvent is append-only, capturing the full identity lifecycle (signup → email claim → account link → login).

  • Webhook URL is mounted outside i18n_patterns at a fixed path so Stripe can always reach it regardless of language prefix.