# Build a Subscription System in Lovable

- Tool: Lovable Prompts
- Last updated: June 2026

## TL;DR

Paste the starter prompt into Lovable Build mode and get a full recurring billing layer: plans table, Stripe Checkout, customer portal, JWT-based TierGate component, and webhook-driven subscription state with raw-body verification and idempotency. Wire this onto any existing Lovable app. Expect 1–2 days and ~150–250 credits on Pro $25/mo.

## Frequently asked questions

### Does this work on the Free Lovable plan?

Not for the full build. The Free plan caps at approximately 30 credits per month, which is exhausted during the starter prompt alone. You need Pro $25/mo to complete the full chain. That said, you can run the starter prompt on Free to see the schema and UI scaffold, then upgrade to Pro for the webhook follow-up. One developer (tomokat) shipped a full Stripe + Supabase credit-topup system in under 10 credits in a single session with the right prompts — so the cost varies widely based on how much iteration you need.

### Why must Stripe be tested only after deploy, not in preview?

Lovable's in-editor preview runs in a sandboxed iframe that does not expose your Edge Functions to the internet. Stripe's webhook delivery requires a publicly reachable URL to POST events to. The preview URL is not reachable by Stripe. Click Publish in the top-right toolbar to deploy to the temporary lovable.app URL, then configure your Stripe webhook endpoint in the Stripe Dashboard to point to that URL. All Stripe testing — Checkout, portal, webhook events — must be done on the deployed URL.

### What is the difference between cancel_at_period_end and immediate cancel?

When a user cancels via the Stripe Customer Portal, Stripe's default behavior is cancel_at_period_end = true. This means the subscription stays active until the end of the current billing period, then customer.subscription.deleted fires. Your webhook should NOT downgrade the user's tier when cancel_at_period_end becomes true — only when subscription.deleted fires. Immediate cancellation (cancel_at_period_end = false) happens only if you call stripe.subscriptions.cancel() with invoice_now=true, or if Stripe cancels due to repeated payment failures. The CurrentPlanCard component shows 'Cancels on [date]' to communicate the pending cancellation to the user.

### How do I handle EU VAT or US sales tax?

The easiest path is to use Stripe Tax — enable it in your Stripe Dashboard under Settings → Tax, add your business address, and set automatic_tax: {enabled: true} in your create-checkout-session Edge Function. Stripe calculates and collects the correct tax for each customer's location automatically. For more complex international compliance (OSS registration in the EU, marketplace facilitator rules in the US), consider Paddle as an alternative to Stripe — Paddle acts as Merchant of Record and handles all tax obligations for you at 5% + 50¢ per transaction.

### Should I store subscription state in Supabase or just query Stripe each time?

Store it in Supabase. Querying Stripe on every page load has three problems: latency (100–500ms per API call vs microseconds for a local DB query), rate limits (Stripe has per-second rate limits that you will hit under load), and dependency (if Stripe has an outage, your app breaks). The subscriptions table in this kit mirrors Stripe's subscription object, and the webhook keeps it in sync in real time. The one case to query Stripe directly is the sync-subscription-from-stripe utility function, which you call on the /account/billing page as a safety net if the webhook and DB get out of sync.

### How do I migrate existing Stripe customers from another platform?

Export your customer and subscription data from Stripe (Stripe Dashboard → Customers → Export or use the Stripe API). For each customer, create a row in your subscriptions table with their stripe_customer_id, stripe_subscription_id, plan_id (map from their current Stripe price to your plan IDs), status, and current_period_end. Then call supabaseAdmin.auth.admin.updateUserById for each user to set their app_metadata.tier to match. You can do this as a one-time migration script run via the sync-subscription-from-stripe Edge Function — prompt Lovable with 'Add a /admin/migration route that reads all users from Stripe and syncs their subscription state to our subscriptions table.'

### When does Paddle's 5% Merchant of Record fee become cheaper than handling tax myself?

Stripe Tax costs 0.5% of tax-collected transactions on top of the standard 2.9% + 30¢. For most founders, Stripe Tax is cheaper than Paddle (5% + 50¢) until you have significant international revenue with complex multi-jurisdiction VAT requirements — roughly above $50K MRR with 30%+ of revenue from the EU. Below that threshold, use Stripe Tax and handle quarterly VAT returns yourself or via an accountant. Above $100K MRR with heavy EU/UK/Canada traffic, Paddle's Merchant of Record model starts to pay for itself in saved accounting and compliance hours.

### Can RapidDev build this subscription system for me end-to-end?

If your build outgrows this prompt kit and you need custom architecture, RapidDev builds production-grade Lovable apps at $13K-$25K — book a free 30-minute consultation at rapidevelopers.com.

---

Source: https://www.rapidevelopers.com/lovable-prompts/lovable-prompts-for-building-subscription-system
© RapidDev — https://www.rapidevelopers.com/lovable-prompts/lovable-prompts-for-building-subscription-system
