How to Add Stripe Payments to a Lovable App: Complete Supabase SaaS Billing Setup

Why Stripe + Lovable + Supabase Is the Fastest Path to SaaS Revenue

Lovable generates full-stack applications with Supabase backend. But the moment you want to charge customers, you hit a complexity wall: payment processing requires server-side logic, webhook handling, subscription state management, and secure credential handling. This is where most Lovable prototypes stall.

This guide walks through the complete integration — from creating Stripe products to handling webhooks to gating features by plan. By the end, you will have working subscription billing in your Lovable app.

Prerequisites

Before starting, you need:

  • A Lovable app with Supabase authentication already working
  • A Stripe account (test mode is fine for development)
  • Stripe API keys (publishable and secret)

Step 1: Set Up Stripe Products and Prices

In the Stripe Dashboard

  1. Go to Products in the Stripe Dashboard
  2. Create a product for each subscription tier:
Product: Starter
Price: $29/month (recurring)
Metadata: plan_tier = "starter"

Product: Professional
Price: $79/month (recurring)
Metadata: plan_tier = "professional"

Product: Enterprise
Price: $199/month (recurring)
Metadata: plan_tier = "enterprise"
  1. Note each Price ID (starts with price_) — you will need these in the next step

Add a Trial Period (Optional)

For each price, set a free trial period:

  • Starter: 7-day trial
  • Professional: 14-day trial
  • Enterprise: 14-day trial with no credit card required

Step 2: Create the Pricing Page in Lovable

Prompt Lovable to generate the pricing UI:

"Create a pricing page at /pricing with three subscription tiers:

Starter ($29/month):
- Up to 5 team members
- 100 projects
- Basic analytics
- Email support

Professional ($79/month) — MOST POPULAR badge:
- Up to 25 team members
- Unlimited projects
- Advanced analytics
- Priority support
- API access

Enterprise ($199/month):
- Unlimited team members
- Unlimited everything
- Custom integrations
- Dedicated account manager
- SSO/SAML

Each tier has a 'Start Free Trial' button.
The current user's plan should be highlighted with a
'Current Plan' badge instead of the button.
Use shadcn/ui Card components. Make the Professional
tier visually prominent (slightly larger, colored border)."

Step 3: Create Stripe Checkout Session

Supabase Edge Function

Prompt Lovable to create the checkout flow:

"Create a Supabase Edge Function at /functions/create-checkout
that:

1. Receives: { priceId: string, userId: string }
2. Checks if the user already has a Stripe customer ID in
   the users table. If not, creates a new Stripe customer
   and saves the customer_id.
3. Creates a Stripe Checkout Session with:
   - mode: 'subscription'
   - The selected price ID
   - customer: the user's Stripe customer ID
   - success_url: /dashboard?checkout=success
   - cancel_url: /pricing?checkout=cancelled
   - subscription_data.trial_period_days: 14
   - metadata: { supabase_user_id: userId }
4. Returns the checkout session URL

Store the Stripe secret key as a Supabase secret (not in code).
The Edge Function should verify the user is authenticated."

Frontend Checkout Button

"When a user clicks 'Start Free Trial' on the pricing page:
1. Call the create-checkout Edge Function with the selected priceId
2. Show a loading spinner on the button
3. Redirect the user to the Stripe Checkout URL
4. Handle errors: if the function fails, show a toast with
   'Unable to start checkout. Please try again.'

The user must be logged in to start checkout. If not logged in,
redirect to /login with a return URL to /pricing."

Step 4: Handle Stripe Webhooks

This is the most critical step — webhooks tell your app when payments succeed, fail, or change.

"Create a Supabase Edge Function at /functions/stripe-webhook
that:

1. Verifies the Stripe webhook signature (using the webhook
   signing secret from Supabase secrets)
2. Handles these events:

   checkout.session.completed:
   - Find the user by metadata.supabase_user_id
   - Update users table: subscription_status = 'active',
     plan_tier = [from subscription metadata],
     stripe_subscription_id = subscription ID
   - Set subscription_period_end from the subscription

   invoice.paid:
   - Update subscription_period_end to the new period end
   - Ensure subscription_status = 'active'

   invoice.payment_failed:
   - Update subscription_status = 'past_due'
   - Optional: send a notification to the user

   customer.subscription.updated:
   - Update plan_tier if the plan changed (upgrade/downgrade)
   - Update subscription_period_end

   customer.subscription.deleted:
   - Update subscription_status = 'cancelled'
   - Set plan_tier = 'free'

3. Returns 200 for all events (even unhandled ones)
4. Logs all events for debugging

Add these columns to the users table if they do not exist:
- stripe_customer_id (text)
- stripe_subscription_id (text)
- subscription_status (text: 'free', 'trialing', 'active', 'past_due', 'cancelled')
- plan_tier (text: 'free', 'starter', 'professional', 'enterprise')
- subscription_period_end (timestamp)"

Configure Webhook in Stripe

  1. Go to Stripe Dashboard > Developers > Webhooks
  2. Add endpoint: https://your-project.supabase.co/functions/v1/stripe-webhook
  3. Select events: checkout.session.completed, invoice.paid, invoice.payment_failed, customer.subscription.updated, customer.subscription.deleted
  4. Copy the signing secret and add to Supabase secrets

Step 5: Gate Features by Plan

"Add plan-based access control to the app:

1. Create a helper function isPlanAllowed(userPlan, requiredPlan)
   that checks plan hierarchy: enterprise > professional > starter > free

2. On the dashboard, show/hide features based on plan:
   - Free: basic dashboard only
   - Starter: + team management, basic analytics
   - Professional: + advanced analytics, API access
   - Enterprise: + custom integrations, SSO

3. When a user tries to access a feature above their plan:
   - Show a modal: 'This feature requires the [Plan] plan'
   - Include an 'Upgrade Now' button that goes to /pricing
   - Do NOT hide the feature entirely — show it grayed out
     so users know it exists (drives upgrades)

4. Add a RLS policy: API endpoints check the user's plan_tier
   before returning data for plan-gated features"

Step 6: Add Customer Portal

Stripe Customer Portal lets users manage their own billing without you building UI for it.

"Add a billing management page at /settings/billing that shows:

1. Current plan name and price
2. Next billing date
3. Payment method (last 4 digits of card)
4. 'Manage Billing' button that opens Stripe Customer Portal

Create a Supabase Edge Function at /functions/create-portal-session:
1. Receives: { userId: string }
2. Looks up the user's stripe_customer_id
3. Creates a Stripe Billing Portal Session with
   return_url: /settings/billing
4. Returns the portal URL

The portal lets users:
- Update payment method
- View invoice history
- Upgrade or downgrade plan
- Cancel subscription"

Testing the Complete Flow

Test Mode Checklist

Use Stripe’s test card numbers:

  • Successful payment: 4242 4242 4242 4242
  • Declined card: 4000 0000 0000 0002
  • Requires authentication: 4000 0025 0000 3155

Test each scenario:

  1. New user signs up and starts a trial
  2. Trial converts to paid subscription
  3. User upgrades from Starter to Professional
  4. User downgrades from Professional to Starter
  5. Payment fails (declined card)
  6. User cancels subscription
  7. Cancelled user re-subscribes

For each scenario, verify:

  • Stripe events are received by the webhook
  • Supabase user record is updated correctly
  • Feature access changes appropriately
  • UI reflects the correct plan status

Common Integration Issues

Webhook Not Receiving Events

  • Verify the webhook URL is correct and publicly accessible
  • Check Stripe webhook logs (Dashboard > Developers > Webhooks > select endpoint)
  • Ensure the Edge Function is deployed and running
  • Verify the signing secret matches

Subscription Status Not Updating

  • Check the webhook function logs in Supabase
  • Verify the user lookup matches (metadata.supabase_user_id)
  • Ensure RLS policies allow the webhook function to update the users table

Checkout Session Fails

  • Verify the Stripe secret key is correctly stored in Supabase secrets
  • Check that the price ID is valid and active in Stripe
  • Ensure the user is authenticated before creating a checkout session

Frequently Asked Questions

Can I use Stripe in test mode with Lovable?

Yes. Use Stripe test API keys during development. Switch to live keys when you are ready to accept real payments. Never use live keys during development.

Do I need a Supabase paid plan for Edge Functions?

Supabase Edge Functions are available on the free tier with limited invocations. For production billing, a paid Supabase plan is recommended for reliability and higher invocation limits.

How do I handle plan downgrades?

Stripe handles prorated billing automatically. When a user downgrades, they keep the current plan until the end of the billing period, then switch to the lower plan. Your webhook handles the customer.subscription.updated event to update the plan_tier.

Can I offer annual billing at a discount?

Yes. Create additional Stripe Prices with yearly interval (e.g., $290/year for Starter instead of $348/year at monthly). Add a toggle on the pricing page to switch between monthly and annual views.

What about one-time payments instead of subscriptions?

Use mode: 'payment' instead of mode: 'subscription' in the checkout session. The webhook flow is similar but uses checkout.session.completed with a one-time payment intent instead of a subscription.

Explore More Tools

Grok Best Practices for Academic Research and Literature Discovery: Leveraging X/Twitter for Scholarly Intelligence Best Practices Grok Best Practices for Content Strategy: Identify Trending Topics Before They Peak and Create Content That Captures Demand Best Practices Grok Case Study: How a DTC Beauty Brand Used Real-Time Social Listening to Save Their Product Launch Case Study Grok Case Study: How a Pharma Company Tracked Patient Sentiment During a Drug Launch and Caught a Safety Signal 48 Hours Before the FDA Case Study Grok Case Study: How a Disaster Relief Nonprofit Used Real-Time X/Twitter Monitoring to Coordinate Emergency Response 3x Faster Case Study Grok Case Study: How a Political Campaign Used X/Twitter Sentiment Analysis to Reshape Messaging and Win a Swing District Case Study How to Use Grok for Competitive Intelligence: Track Product Launches, Pricing Changes, and Market Positioning in Real Time How-To Grok vs Perplexity vs ChatGPT Search for Real-Time Information: Which AI Search Tool Is Most Accurate in 2026? Comparison How to Use Grok for Crisis Communication Monitoring: Detect, Assess, and Respond to PR Emergencies in Real Time How-To How to Use Grok for Product Improvement: Extract Customer Feedback Signals from X/Twitter That Your Support Team Misses How-To How to Use Grok for Conference Live Monitoring: Extract Event Insights and Identify Networking Opportunities in Real Time How-To How to Use Grok for Influencer Marketing: Discover, Vet, and Track Influencer Partnerships Using Real X/Twitter Data How-To How to Use Grok for Job Market Analysis: Track Industry Hiring Trends, Layoff Signals, and Salary Discussions on X/Twitter How-To How to Use Grok for Investor Relations: Track Earnings Sentiment, Analyst Reactions, and Shareholder Concerns in Real Time How-To How to Use Grok for Recruitment and Talent Intelligence: Identifying Hiring Signals from X/Twitter Data How-To How to Use Grok for Startup Fundraising Intelligence: Track Investor Sentiment, VC Activity, and Funding Trends on X/Twitter How-To How to Use Grok for Regulatory Compliance Monitoring: Real-Time Policy Tracking Across Industries How-To NotebookLM Best Practices for Financial Analysts: Due Diligence, Investment Research & Risk Factor Analysis Across SEC Filings Best Practices NotebookLM Best Practices for Teachers: Build Curriculum-Aligned Lesson Plans, Study Guides, and Assessment Materials from Your Own Resources Best Practices NotebookLM Case Study: How an Insurance Company Built a Claims Processing Training System That Cut Errors by 35% Case Study