How to Add a Paywall to Your Vibe-Coded App
Ready to charge for your AI-built app? This beginner guide covers Stripe Checkout, Lemon Squeezy as the simpler alternative, and the Stripe MCP for Claude Code.
Caleb North is a fictional AI persona, not a real person. This article was written by AI and reviewed by a human editor before publishing. How we work →

Some links may be affiliate links. We may earn a commission at no extra cost to you.
Your app works. People are using it. Now you want them to pay for it — and suddenly every guide you find assumes you know what a webhook handler is.
This guide skips the assumed knowledge. You will pick one of two paths based on how much complexity you want to take on, follow the steps, and end up with a real paywall in your real app.
Two ways to charge for your app (pick one before you read further)
Before you touch any code, make a decision. Everything else flows from it.
Path A: Stripe Checkout — more control, works great with the Stripe MCP
is the default payment processor for most web apps. It handles cards, Apple Pay, Google Pay, and a long list of local payment methods. You own the integration, which means more flexibility — and slightly more to configure.
The good news for vibe coders: there is an official Stripe MCP server that plugs directly into or Cursor. It can generate payment links, look up payment status, and manage products without you writing billing logic by hand. If you are already building in Claude Code, this is the path with the least friction.
Path B: Lemon Squeezy — simpler setup, handles tax for you
was acquired by Stripe in July 2024 and continues to operate as a standalone platform. Stripe is building a new product called Stripe Managed Payments — a merchant-of-record successor using Lemon Squeezy's model on Stripe infrastructure — but as of mid-2026, Lemon Squeezy still accepts new signups and runs independently.
Lemon Squeezy acts as the merchant of record for your sales. That means Lemon Squeezy is legally the seller, collects the money, remits sales tax and VAT on your behalf, and pays you out. For total beginners who do not want to think about tax compliance at all, this is the right choice.
The trade-off is less flexibility and a layer between you and your revenue. You also pay slightly higher fees in exchange for the hands-off tax handling.
The honest trade-off in one table
| | Stripe Checkout | Lemon Squeezy | |---|---|---| | Setup complexity | Medium | Low | | Tax / VAT handling | You figure it out | Handled for you | | MCP support in Claude Code | Yes (native) | No | | Fee structure | 2.9% + 30¢ per transaction (US) | 5% + $0.50 per transaction (base rate) | | Who's the seller | You | Lemon Squeezy | | Best for | Apps needing full control | Indie products, digital downloads |
Path A: Adding Stripe Checkout with the Stripe MCP
If you are not familiar with what an MCP is, read the what is MCP explainer first — this section will make more sense.
Step 1: Create a Stripe account and get your API keys
Go to stripe.com and create a free account. You do not need to activate your account to use test mode — you can build and test the entire payment flow before Stripe reviews your business details.
Once you are in the dashboard, go to Developers → API keys. You will see two keys:
- Publishable key — safe to put in your frontend code
- Secret key — never put this in your frontend or in a public repo
Your secret key is exactly the kind of credential covered in the how to keep secrets safe guide. Set it as an environment variable, not a hardcoded string.
STRIPE_SECRET_KEY=sk_test_...
STRIPE_PUBLISHABLE_KEY=pk_test_...
Step 2: Install the Stripe MCP in Claude Code
The Stripe MCP server is an official Stripe product. To add it to Claude Code, open your MCP config file (.claude/settings.json or ~/.claude.json depending on your setup) and add the Stripe server entry.
{
"mcpServers": {
"stripe": {
"command": "npx",
"args": ["-y", "@stripe/mcp", "--tools=all", "--api-key=YOUR_STRIPE_SECRET_KEY"]
}
}
}
Replace YOUR_STRIPE_SECRET_KEY with your actual key — or better, reference the environment variable. Restart Claude Code after saving.
Step 3: Prompt Claude to create a payment link (exact prompts)
With the Stripe MCP active, Claude Code has direct access to Stripe's API. You do not need to write the billing code yourself — you describe what you want and Claude builds it.
One important note: the Stripe MCP creates payment links, not full Checkout Sessions. Payment links are hosted pages Stripe generates for you — functionally similar for most simple use cases, but they do not support custom success/cancel URL injection at creation time the way a Checkout Session does. For a beginner selling a single product, a payment link is all you need.
Try this prompt:
"Using the Stripe MCP, create a payment link for a one-time payment of $9 for a product called 'Pro Access'. Give me the URL so I can add it to my pricing page."
Claude will call the Stripe API through the MCP, create the payment link, and give you back the URL. For a subscription product, adjust the prompt:
"Create a Stripe payment link for a monthly subscription at $12/month. Use the product name 'Pro Plan'."
If you need full Checkout Session functionality (custom redirect URLs, session verification on the server), ask Claude to write the API route code directly rather than using the MCP for that step.
Step 4: Add a "Buy" button that redirects to your payment page
If you used the MCP to generate a payment link in Step 3, the simplest approach is a button that links directly to that URL. Ask Claude to wire this up:
"Add a 'Go Pro' button to my pricing page that links to [your Stripe payment link URL]."
If you want a server-generated Checkout Session instead (so you can verify payment on your own backend), ask Claude to build the API route:
"Add a 'Go Pro' button to my pricing page. When clicked, it should POST to
/api/create-checkout-session, get the Stripe Checkout URL from the response, and redirect the user to that URL."
Claude will write both the button and the API route. The API route is where your Stripe secret key lives — it never touches the browser.
Step 5: Handle the success redirect so users unlock the paid tier
When Stripe redirects the user back to your /success page, that redirect alone is not proof of payment — users could type the URL directly. The correct approach is to verify payment on the server using the session_id Stripe appends to your success URL.
Prompt Claude:
"On the
/successpage, read thesession_idquery parameter. Make a server-side request to Stripe to retrieve the session and confirmpayment_statusispaid. If it is, mark the user as paid in the database."
This connects directly to your database setup — if you have not added a database yet, the Neon database guide covers the quickest way to get one running.
What the Stripe MCP can and can't do for you
The Stripe MCP is genuinely useful but it is not magic. Here is what to expect:
It can:
- Create payment links (hosted Stripe-generated checkout pages)
- Look up payment status and charge history
- Create and manage products and prices
- Initiate refunds
- Manage subscriptions
It can't:
- Create full Checkout Sessions (those require your own API route code)
- Handle webhooks (you still need a webhook endpoint in your app)
- Automatically gate features based on payment status — that logic lives in your app code
- Replace a proper backend billing integration for complex subscription logic
Path B: Adding a paywall with Lemon Squeezy
Why Lemon Squeezy is easier for total beginners
With Stripe, you are the seller. You need to handle tax registration yourself if you cross revenue thresholds in various countries. With Lemon Squeezy, they are the seller on paper — they handle EU VAT, US sales tax, and all the compliance paperwork automatically.
For a first paid product, that trade-off is usually worth it. You give up some control and pay higher fees, and in return you do not have to think about tax law.
Step 1: Create a store and a product in 5 minutes
Go to lemonsqueezy.com and create an account. The onboarding walks you through creating a store. Once your store exists:
- Go to Products → Add product
- Name your product, set the price, choose one-time or subscription
- Publish it
That's the entire product setup. No code yet.
Step 2: Get your Store ID and Variant ID
Every Lemon Squeezy product has a Variant ID — this is what you use to pre-fill the checkout. Find it in the product's URL or in the product settings panel.
You will also need your Store ID from Settings → Store. Write both down.
Step 3: Add the Lemon Squeezy overlay checkout script
Lemon Squeezy supports an overlay checkout — a modal that pops up over your page without redirecting users away from your app. Add this script tag to your HTML <head>:
<script src="https://app.lemonsqueezy.com/js/lemon.js" defer></script>
Step 4: Wire the "Pro" button to your checkout overlay
Any link with the class lemonsqueezy-button pointing to your product's checkout URL will trigger the overlay automatically.
<a
href="https://your-store.lemonsqueezy.com/buy/YOUR_VARIANT_ID"
class="lemonsqueezy-button"
>
Go Pro
</a>
Replace your-store with your store subdomain and YOUR_VARIANT_ID with the variant ID from Step 2. The overlay will open when a user clicks the button — no backend code required for the checkout itself.
How to check if a user has paid (webhook basics, no code required)
Lemon Squeezy sends a webhook to your app when a payment completes. The simplest implementation: ask Claude to write a webhook endpoint that listens for the order_created event and sets a paid = true flag on the user record.
"Write a webhook handler at
/api/lemon-squeezy/webhookthat listens fororder_createdevents. When one arrives, find the user by the email in the payload and mark them as paid in the database."
Claude can write this endpoint. You then paste the endpoint URL into Lemon Squeezy's webhook settings under Settings → Webhooks.
Gating content: how to actually show or hide features after payment
Both paths end at the same place: your app needs to know whether the current user has paid, and show or hide features based on that.
The simplest approach: a "paid" flag in your database
The most beginner-friendly implementation is a single boolean column — is_pro, paid, or has_access — on your users table. Set it to true when payment is confirmed (via the Stripe session check or the Lemon Squeezy webhook). Check it on every page load or API call that serves gated content.
If you have not set up a database yet, start with the Neon database guide. If you do not have user accounts yet, add those first — the user login guide covers the full auth setup. You cannot reliably gate paid features without knowing who is logged in.
Connecting payment status to your app's UI (prompt-driven)
Once the flag exists in your database, prompt Claude to apply it:
"On any page that shows Pro features, check if the current user's
is_profield is true. If it is false, replace the feature with an upgrade prompt that links to the pricing page."
This is prompt-driven — Claude will read your existing components and insert the gate in the right place. You are not writing conditional logic from scratch; you are describing the behavior.
Things to sort out before you go live
Assume your app is already deployed. If it is not, the Vercel deployment guide covers getting it live.
Test mode vs live mode — don't skip this
Both Stripe and Lemon Squeezy have test modes that simulate payments without charging real cards. Use test mode for your entire development and QA phase. In Stripe, use the test card 4242 4242 4242 4242 with any future expiry and any CVV.
When you are ready to go live, swap your test API keys for live keys and toggle your Stripe account to live mode. Do not flip this switch until you have completed at least two end-to-end test purchases.
Refunds, disputes, and what happens when a payment fails
Failed payments in Stripe are handled automatically — Stripe retries subscription payments and sends dunning emails. For one-time payments, a failed charge is a failed sale. You do not need to do anything.
Refunds on Stripe: you issue them from the Stripe dashboard or via the MCP. On Lemon Squeezy: you issue them from the Lemon Squeezy dashboard. Neither requires code changes in your app.
Disputes (chargebacks) are rarer but more painful. Lemon Squeezy handles dispute responses on your behalf as the merchant of record. With Stripe, you respond to disputes yourself through the Stripe dashboard.
Do you need to collect tax? (Stripe vs Lemon Squeezy answer differs)
With Stripe: it depends on where you sell and how much you earn. Stripe Tax is an add-on that automates tax calculation and collection, but you still need to register in the jurisdictions where you have nexus. This is a real compliance question — get accountant advice before hitting meaningful revenue.
With Lemon Squeezy: because they are the merchant of record, they handle all of this. You receive payouts net of any taxes they collect. You still need to report your net income as business income, but you are not responsible for remitting sales tax or VAT yourself.
This single difference is why total beginners should default to Lemon Squeezy for their first paid product. The complexity gap is real.
The StackBrief weekly
New reviews and the AI-coding-tool news worth knowing — with our take. One email a week, unsubscribe anytime.
Keep reading

How to Add a Database to Your AI-Built App With Neon
Learn how to add a real database to your AI-built app using Neon's free serverless Postgres — no SQL experience needed. Works with Lovable, Bolt, and Cursor.
May 12, 2026
Build a Landing Page With AI Tools in Under an Hour
A timed, step-by-step walkthrough to build and deploy a landing page with AI tools — use v0 for the UI and Vercel to ship it live. No code experience needed.
May 10, 2026
Lovable vs Emergent: Which AI App Builder for Beginners?
Lovable vs Emergent compared for total beginners: ease of use, what each builds best, pricing, code export, and a clear pick for your first AI-built app.
June 3, 2026