Skip to main content

Billing (Stripe)

The billing module handles Stripe Checkout sessions, subscription lifecycle management, the customer billing portal, and webhook processing with idempotency.

Endpoints

MethodPathAuthDescription
GET/billing/configNoGet publishable key and price IDs
POST/billing/checkoutYesCreate a Stripe Checkout session
POST/billing/portalYesCreate a Stripe billing portal session
GET/billing/subscriptionYesGet the current user's subscription
POST/billing/webhookNoStripe webhook handler (signature-verified)

Checkout Flow

  1. The frontend calls GET /billing/config to retrieve the Stripe publishable key and price ID.
  2. When the user clicks a pricing CTA the frontend calls POST /billing/checkout with the priceId.
  3. The API creates a Stripe Checkout Session and returns the session URL.
  4. The user completes payment on Stripe's hosted page.
  5. Stripe sends a webhook to POST /billing/webhook confirming 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:

  1. The user has a subscription record.
  2. The subscription status is active (not cancelled or past due).
  3. The subscription's price ID maps to one of the required plans.

Stripe Setup

  1. Create a product and price in the Stripe Dashboard.
  2. Copy the price ID (e.g., price_1Abc...).
  3. Create a webhook endpoint pointing to https://your-domain.com/billing/webhook.
  4. Subscribe to the events your billing service handles (e.g., checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, invoice.payment_failed).
  5. Set environment variables:
STRIPE_SECRET_KEY=sk_test_...
STRIPE_PUBLISHABLE_KEY=pk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...
STRIPE_PRICE=price_...