Developer Guide

Stripe Live Demo Documentation

Learn how this demo combines Next.js, Supabase, and Stripe to power one-time payments and subscriptions safely in both test and live environments.

Key Technologies

Framework
Next.js 15 App Router + TypeScript
Authentication
Supabase email/password auth
Payments
Stripe Checkout Sessions, Products, Prices, Subscriptions
Styling
Tailwind CSS

Demo Goals

  • Show safe plan selection and price resolution on the server.
  • Demonstrate Supabase-to-Stripe customer linking.
  • Preserve app/store separation with Stripe metadata.
  • Illustrate how to flip between test and live modes.

Architecture Overview

Request Flow

  • Supabase guards every API route. If the session is invalid we return 401 Unauthorized.
  • The browser sends only a tier slug (e.g., "basic", "donate"). Prices are never client-controlled.
  • The server resolves that slug to an environment-specific Stripe Price ID, creates or reuses the customer, and launches a Checkout Session.
  • Metadata (app, store, tier) is attached to customers, prices, and subscriptions so multiple apps can share one Stripe account.

Primary Pages

  • /payment: one-time Checkout using the donate price.
  • /subscribe: loads live plan details directly from Stripe and launches subscription Checkout.
  • /subscriptions: lists subscriptions for the logged-in user and allows safe cancellation.
  • /dashboard: protected view with user info and high-level stats (per test/live mode).

Setup Guide

1. Environment Variables

Create .env.local with your Supabase keys, Stripe secret keys, and both sets of price IDs:

NEXT_PUBLIC_SUPABASE_URL=
NEXT_PUBLIC_SUPABASE_ANON_KEY=
SUPABASE_SERVICE_ROLE_KEY=

NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY=
STRIPE_SECRET_KEY=
NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY_LIVE=
STRIPE_SECRET_KEY_LIVE=

STRIPE_TEST_PRICE_DONATE=
STRIPE_TEST_PRICE_SUB_BASIC=
STRIPE_TEST_PRICE_SUB_STANDARD=
STRIPE_TEST_PRICE_SUB_PREMIUM=

STRIPE_LIVE_PRICE_DONATE=
STRIPE_LIVE_PRICE_SUB_BASIC=
STRIPE_LIVE_PRICE_SUB_STANDARD=
STRIPE_LIVE_PRICE_SUB_PREMIUM=

2. Stripe Products & Prices

  • Create one product per demo app (e.g., “Stripe Demo App Product”).
  • Add recurring prices (basic, standard, premium) and a one-time price (donate) in both test and live mode.
  • Assign lookup keys such as stripe-live:subscription:basic and metadata like { app: 'stripe-live', store: 'default', tier: 'basic', environment: 'test' }.
  • Duplicate the setup for live mode with identical metadata but environment=live.

3. Supabase configuration

  • Enable email/password sign-in and configure redirect URLs inside Supabase Auth settings.
  • Set your production URL in Supabase so auth callbacks succeed in production.
  • Optional: configure SMTP (e.g., Resend) if you want to test email confirmations.

Security Highlights

  • Server-owned pricing: Checkout sessions accept only server-resolved price IDs. Client payloads can’t alter amounts.
  • Session-bound subscriptions: Cancellation and listing routes verify that the Stripe customer belongs to the Supabase user.
  • Metadata filtering: Customers, prices, and subscriptions are tagged, letting one Stripe account serve multiple apps safely.
  • API version pinning: Stripe SDK initialises with a supported API version to avoid surprises.

Running the Demo

npm install
npm run dev
  • Visit /payment to test one-time charges in test or live mode.
  • Visit /subscribe to explore subscription tiers fetched directly from Stripe.
  • Manage active plans on /subscriptions and track stats on /dashboard.

Troubleshooting

  • Unexpected checkout total? The Stripe customer may have an outstanding balance. Clear it from the Stripe dashboard or create a new test user.
  • “Invalid price tier” error? Ensure the plan slug matches the configured price IDs and environment variables.
  • Subscriptions list empty? Confirm the Stripe customer’s metadata matches app=stripe-live and the user’s email.