Billing & Subscriptions

Overview

This feature governs the monetization of Bambu using Stripe (and potentially Lemon Squeezy). It isolates 'Free' users from 'Pro' users, enforcing hard resource limits.

Why it exists

As a robust SaaS, we must limit costly automated actions (like AI Chat Usage, Automated SMS, and unlimited Product Storage) to paying subscribers to maintain business profitability.

User flow

  1. The user goes to app/dashboard/settings/billing.
  2. They see their active 'Free' plan and click 'Upgrade to Pro'.
  3. They are redirected to a Stripe Checkout Session.
  4. Upon successful payment, they hit the success page and the app unlocks Premium toggles seamlessly.

UI walkthrough

![Billing Plans Screen](../../assets/images/billing/plans.png) ![Stripe Checkout](../../assets/images/billing/checkout.png)

Backend logic

Stripe Webhooks are critical here:

  1. The user pays Stripe.
  2. Stripe sends an HTTP POST to app/api/webhooks/stripe/route.ts.
  3. The server authenticates the payload via cryptographically signed hashes.
  4. Prisma updates the public.subscriptions table, attaching the user's businessId.
  5. Next.js triggers a NextCache revalidation, forcing the UI to recognize the Pro status.

Database tables involved

Global public Schema:

  • Subscription: The master object of truth linking a Strip Customer ID to a Business ID.
  • Plan: Defined system configurations (e.g., name, cost, maxUsers limit).

API endpoints

  • POST /api/billing/checkout - Initializes Stripe session.
  • POST /api/webhooks/stripe - Solely for Stripe to report status updates to Bambu.

Permissions / roles

  • Owner: Only the tenant owner can manage billing subscriptions.

Edge cases

  • "Past Due" statuses: If a payment card fails during a renewal, the Webhook downgrades the system status to past_due, which conditionally locks out Pro features with a grace period warning.

Validation rules

  • Webhook signature validation relies on the STRIPE_WEBHOOK_SECRET environment variable. Ensure this matches identically between Stripe and .env.

Error handling

  • If the Webhook fails processing, Stripe will retry up to 3 days. A dead-letter queue log is recommended to monitor failures.

Screenshots placeholders

![Wait for Webhook Spinner](../../assets/images/billing/success-spinner.png)

Troubleshooting

  • User paid but plan didn't upgrade: A mismatch in the webhook secret or a timeout. Check the Stripe Developer Logs and trigger a manual sync script (e.g., verify-entitlements.ts).

Related features