Stripe Checkout Flow Setup

Date: 2025-01-04 Status: ✅ Code Complete - Ready for Testing

Overview

The complete checkout flow is now implemented, allowing users to subscribe to Personal, Pro, or Team tiers with 10-day free trials.

Files Created

1. Checkout API Route

File: app/api/stripe/checkout/route.ts

Creates Stripe Checkout sessions with:

  • 10-day free trial for all paid tiers
  • User ID linked via metadata
  • Success/cancel redirects
  • Promotion code support

2. Success Page

File: app/checkout/success/page.tsx

Shows confirmation after successful checkout with:

  • Success message
  • Trial information
  • Next steps
  • Quick links to dashboard and settings

3. Checkout Button Component

File: components/checkout-button.tsx

Reusable button component that:

  • Requires authentication (redirects to sign-in if needed)
  • Shows loading state
  • Calls checkout API
  • Redirects to Stripe Checkout

4. Updated Pricing Page

File: app/(marketing)/pricing/page.tsx

Now uses CheckoutButton component with:

  • Real Stripe price IDs
  • Monthly/yearly toggle support
  • Trial information

Environment Variables Required

Add these to your .env.local file:

# Stripe Keys (already configured)
STRIPE_SECRET_KEY=sk_test_...
STRIPE_WEBHOOK_SECRET=whsec_...

# Public Price IDs (for client-side pricing page)
NEXT_PUBLIC_STRIPE_PERSONAL_MONTHLY_PRICE_ID=price_1SPjo4Aye5brjRffe1sdUwS9
NEXT_PUBLIC_STRIPE_PERSONAL_YEARLY_PRICE_ID=price_1SPjoGAye5brjRff3OxcvQo8
NEXT_PUBLIC_STRIPE_PRO_MONTHLY_PRICE_ID=price_1SPjokAye5brjRffO0iaBf5S
NEXT_PUBLIC_STRIPE_PRO_YEARLY_PRICE_ID=price_1SPjovAye5brjRfftU1yWaqo
NEXT_PUBLIC_STRIPE_TEAM_MONTHLY_PRICE_ID=price_1SPjqmAye5brjRffVAyS9mhe
NEXT_PUBLIC_STRIPE_TEAM_YEARLY_PRICE_ID=price_1SPjqwAye5brjRffqf7Enyuv

# Base URL (optional - auto-detected if not set)
NEXT_PUBLIC_BASE_URL=http://localhost:3017

# Convex (already configured)
NEXT_PUBLIC_CONVEX_URL=https://your-project.convex.cloud

Important: The NEXT_PUBLIC_* prefix makes these variables accessible in client components.

How It Works

User Flow

  1. User visits pricing page (/pricing)
  2. User clicks "Start Free Trial"
  3. System checks authentication:
    • Not signed in → Redirect to /sign-in?redirect_url=/pricing
    • Signed in → Continue to step 4
  4. Frontend calls POST /api/stripe/checkout
  5. API creates checkout session:
    • Links userId in metadata
    • Sets 10-day trial period
    • Returns Stripe Checkout URL
  6. User redirected to Stripe Checkout
  7. User enters payment details (test mode: use test cards)
  8. Stripe creates subscription and sends webhook
  9. Webhook syncs to Convex (creates subscription record)
  10. User redirected to /checkout/success

API Request Format

POST /api/stripe/checkout
Content-Type: application/json

{
  "priceId": "price_1SPjo4Aye5brjRffe1sdUwS9",
  "tier": "personal",
  "interval": "monthly"
}

API Response Format

{
  "url": "https://checkout.stripe.com/c/pay/...",
  "sessionId": "cs_test_..."
}

Testing with Stripe Test Cards

Test Mode Setup

You're currently in test mode (correct for development). Use these test card numbers:

Successful Payment

Card NumberDescription
4242 4242 4242 4242Visa - Always succeeds
5555 5555 5555 4444Mastercard - Always succeeds
3782 822463 10005American Express - Always succeeds

For all test cards:

  • Expiry: Any future date (e.g., 12/25)
  • CVC: Any 3 digits (e.g., 123)
  • ZIP: Any 5 digits (e.g., 12345)

Failed Payments (for testing error handling)

Card NumberDescription
4000 0000 0000 0002Card declined
4000 0000 0000 9995Insufficient funds
4000 0000 0000 0069Expired card

Testing Steps

  1. Add environment variables to .env.local (see above)
  2. Restart dev server: pnpm dev
  3. Ensure ngrok is running (for webhook testing)
  4. Ensure you're signed in to the app
  5. Go to pricing page: http://localhost:3017/pricing
  6. Click "Start Free Trial" on any tier
  7. Use test card: 4242 4242 4242 4242
  8. Complete checkout
  9. Verify:
    • Redirected to /checkout/success
    • Webhook received (check console logs)
    • Subscription created in Convex database

Verifying Subscription Creation

Check Stripe Dashboard

  1. Go to Stripe Dashboard → Test modeCustomers
  2. Find the customer (will have the user's email)
  3. Click on customer → See subscription with 10-day trial

Check Convex Database

  1. Go to Convex Dashboard → Data
  2. Open subscriptions table
  3. Find record with your userId
  4. Verify:
    • tier: "personal", "pro", or "team"
    • status: "trialing"
    • trialEndsAt: ~10 days from now
    • stripeSubscriptionId: starts with "sub_"

Check Console Logs

You should see in your Next.js console:

✅ Received webhook: customer.subscription.created
Subscription created: sub_1234567890 for user user_abc123

Common Issues

"Missing environment variable" Error

Cause: Price ID environment variables not set

Fix:

  1. Add all NEXT_PUBLIC_STRIPE_*_PRICE_ID variables to .env.local
  2. Restart dev server

"Unauthorized" Error

Cause: User not signed in

Expected: User should be redirected to /sign-in

If not redirecting: Check Clerk authentication setup

Webhook Not Received

Cause: ngrok tunnel not configured or webhook not created

Fix: See STRIPE_WEBHOOK_SETUP.md for webhook configuration

"No userId in metadata" Warning

Cause: userId not passed to checkout session

This should NOT happen with the current implementation - the API route includes userId in metadata. If you see this, check:

  1. User is authenticated when calling checkout API
  2. Clerk auth is working correctly

Trial Period Behavior

During Trial (Days 1-10)

  • User has full access to tier features
  • No payment charged
  • status: "trialing"
  • Can cancel anytime without being charged

After Trial Ends (Day 11)

  • Stripe automatically charges the subscription
  • status: changes to "active"
  • Webhook: invoice.payment_succeeded
  • User continues to have access

If Payment Fails After Trial

  • status: changes to "past_due"
  • Webhook: invoice.payment_failed
  • Stripe retries payment (configurable in Stripe settings)
  • Consider showing banner to update payment method

Next Steps

  1. ✅ Checkout flow implemented
  2. ⏳ Test end-to-end with test cards
  3. ⏳ Implement Customer Portal (manage subscription)
  4. ⏳ Add frontend usage indicators
  5. ⏳ Add upgrade prompts when limits hit
  6. ⏳ Test downgrade/upgrade scenarios

Security Notes

  • ✅ Authentication required before checkout
  • ✅ User ID passed securely via Clerk auth
  • ✅ Stripe handles all payment processing
  • ✅ Webhook signatures verified
  • ✅ Price IDs are public (not sensitive)

Reference Documents:

  • docs/STRIPE_PRODUCT_SETUP.md - Product and price IDs
  • docs/STRIPE_WEBHOOK_SETUP.md - Webhook configuration
  • docs/PHASE_1_IMPLEMENTATION_COMPLETE.md - Backend tier enforcement
  • docs/TIER_MANAGEMENT_PLAN.md - Complete implementation roadmap

On this page