Add Stripe Subscription Billing
Cursor prompt to add Stripe Checkout subscriptions to a Next.js SaaS — Customer Portal, webhooks, and entitlement checks that match your AI limits.
Problem this prompt solves
Billing bugs are trust bugs: users pay and never get access, or cancel and keep generating forever. MVP Stripe integrations need Checkout, webhooks as source of truth, a customer portal, and server-side entitlement checks on AI routes — not only a “Upgrade” button that sets is_pro=true in the client.
When to use it
- Your core AI workflow works and you are ready to charge for usage or a Pro plan.
- You need Stripe Checkout + Customer Portal rather than a custom card form.
- You must gate AI generations or seats by plan with webhook-synced status.
- You already have Supabase auth users to attach as Stripe customers.
Cursor prompt
Add Stripe subscription billing to this Next.js App Router + Supabase AI SaaS. Product defaults (adjust if README already defines plans): - Free tier: limited AI runs - Pro tier: higher limits (and optionally stronger model) via Stripe subscription Implement: 1) Stripe SDK server-side only (STRIPE_SECRET_KEY). Use STRIPE_WEBHOOK_SECRET for webhooks. Publishable key only where required for Checkout redirect patterns you choose. 2) Database: store billing state on profiles or a subscriptions table: stripe_customer_id, stripe_subscription_id, plan status (active, canceled, past_due, trialing), plan price id / plan name, current_period_end. RLS: users can read their own billing fields; only service role / webhook updates them. 3) Checkout: authenticated Route Handler creates a Checkout Session in subscription mode with client_reference_id or metadata.user_id = Supabase user id. Success/cancel URLs back to /app/billing. 4) Customer Portal: Route Handler creates a portal session for the logged-in customer. 5) Webhook route: verify signature; handle at least checkout.session.completed, customer.subscription.updated, customer.subscription.deleted, invoice.payment_failed. Sync status to the database with the service role. Make handlers idempotent. 6) Entitlements: server helper getEntitlements(user) used by AI routes to enforce free vs pro limits. Never trust a client-sent “plan” field. 7) UI: /app/billing showing current plan, upgrade button, manage billing button, and plain-language limit explanations. 8) .env.example + README: products/prices to create in Stripe, webhook forwarding with Stripe CLI for local dev. Analytics (if helpers exist): fire billing_checkout_started and billing_subscription_active without card details. Constraints: - Webhook is source of truth for access — do not grant Pro only from the success URL redirect - Do not store full card numbers - Keep to one Pro price for MVP unless plans already exist - Document how AI rate limits differ by plan
Expected result
Working Checkout + Customer Portal, signature-verified webhooks syncing subscription status to Supabase, and AI routes that enforce plan entitlements without trusting the client.
Implementation notes
- Test with Stripe test mode and the Stripe CLI before touching live keys.
- Map Stripe customer ↔ user id in metadata early; recovery is painful later.
- Grant entitlements only after webhook confirmation; the success page can say “processing” if needed.
- Align Pro limits with OpenAI unit economics — a $20 plan with unlimited GPT-4o is a hobby.
- Handle past_due: decide whether to soft-lock AI or allow a grace period; document the choice.
- Customer Portal reduces support load for cancellations and payment method updates — ship it with Checkout.
Testing checklist
- Authenticated user can start Checkout in test mode and complete a subscription.
- Webhook marks the user Pro; AI entitlement helper returns Pro limits.
- Success URL alone (without webhook) does not permanently grant Pro in your design — webhook sync required.
- Customer Portal opens and can cancel; webhook moves status to canceled and limits revert.
- invoice.payment_failed path sets past_due (or your chosen behaviour) and AI gating responds accordingly.
- User B cannot open a portal session for user A’s customer id.
- Replay the same webhook event — no duplicate rows / crashes (idempotent).
- No Stripe secret key in client bundles.
Common mistakes
- Setting is_pro=true in the success redirect handler without webhooks.
- Trusting price id or plan from the request body on AI routes.
- Forgetting webhook signature verification — anyone can POST “access.”
- Creating a new Stripe customer on every Checkout click — duplicates forever.
- No portal — you become human billing support for card updates.
- Unlimited AI on Pro with no rate limit — Stripe revenue becomes OpenAI donate.
Building something real?
If you’ve moved beyond experimenting and need help defining or building your MVP, RemoteGeek can help turn the idea into a focused implementation plan.
Related resources
Related Cursor prompts
Add Analytics
Cursor prompt to add privacy-conscious product analytics for an AI SaaS MVP — signup, activation, and generation events that actually inform decisions.
Add Rate Limiting
Cursor prompt to add practical rate limiting to AI and auth routes on Vercel/Next.js before public traffic hits your OpenAI bill.
Prepare an MVP for Public Beta
Cursor prompt that turns a prototype into a public-beta candidate — auth hardening, limits, errors, observability, and launch blockers.
Reduce OpenAI API Costs
Cursor prompt to audit and cut OpenAI spend — caching, smaller models, token caps, batching, and usage-aware product defaults.
Next recommended guide
Add AnalyticsCursor prompt to add privacy-conscious product analytics for an AI SaaS MVP — signup, activation, and generation events that actually inform decisions.
RemoteGeek Builder Notes
One practical lesson each week. No hype.
AI building, automation, and technology-risk notes for professionals and solo builders. Signing up stores your email for follow-up — automated newsletter delivery may be connected later.