Billing (Stripe)
The billing module handles Stripe Checkout sessions, subscription lifecycle management, the customer billing portal, and webhook processing with idempotency.
Endpoints
| Method | Path | Auth | Description |
|---|---|---|---|
| GET | /billing/config | No | Get publishable key and price IDs |
| POST | /billing/checkout | Yes | Create a Stripe Checkout session |
| POST | /billing/portal | Yes | Create a Stripe billing portal session |
| GET | /billing/subscription | Yes | Get the current user's subscription |
| POST | /billing/webhook | No | Stripe webhook handler (signature-verified) |
Checkout Flow
- The frontend calls
GET /billing/configto retrieve the Stripe publishable key and price ID. - When the user clicks a pricing CTA the frontend calls
POST /billing/checkoutwith thepriceId. - The API creates a Stripe Checkout Session and returns the session URL.
- The user completes payment on Stripe's hosted page.
- Stripe sends a webhook to
POST /billing/webhookconfirming the subscription.
Webhook Handling
The webhook controller receives raw request bodies and validates the stripe-signature header against STRIPE_WEBHOOK_SECRET. Events are processed by BillingService.handleWebhookEvent.
Webhook idempotency is enforced via a WebhookEvent database table. Each event ID from Stripe is recorded; duplicate deliveries are silently skipped.
Billing Portal
POST /billing/portal returns a Stripe billing portal URL where the customer can update payment methods, view invoices, and cancel their subscription.
Subscription Guard
The SubscriptionGuard gates routes behind an active subscription. Pair it with the @RequiresPlan() decorator to restrict access to specific plan tiers.
@RequiresPlan('PRO')
@UseGuards(JwtAuthGuard, SubscriptionGuard)
@Get('premium-feature')
getPremiumFeature() {
// Only accessible to users on the PRO plan
}
The guard checks that:
- The user has a subscription record.
- The subscription status is active (not cancelled or past due).
- The subscription's price ID maps to one of the required plans.
Stripe Setup
- Create a product and price in the Stripe Dashboard.
- Copy the price ID (e.g.,
price_1Abc...). - Create a webhook endpoint pointing to
https://your-domain.com/billing/webhook. - Subscribe to the events your billing service handles (e.g.,
checkout.session.completed,customer.subscription.updated,customer.subscription.deleted,invoice.payment_failed). - Set environment variables:
STRIPE_SECRET_KEY=sk_test_...
STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRICE=price_...