// private beta · onboarding builders in wavesrequest_access →
← Back to blog

How to monetize a vibe-coded app: pricing and billing that hold up

How to monetize a vibe-coded app: pick the pricing model, wire Stripe so it survives the unhappy paths, and gate features on the server, not in the browser.

To monetize a vibe-coded app, pick a pricing model that matches how the product delivers value, then wire billing so that the server, not the browser, decides who has paid. The first half is strategy. The second is engineering, and it is where AI-built apps most often fail.

There's a case that should hang over every pricing page. In March 2025 a founder announced a SaaS built entirely with Cursor and no hand-written code; two days later he reported users bypassing the subscription and maxing out his API keys. The app worked. The business didn't.

That story is the whole lesson of this guide in miniature. Vibe coding makes the billing half look done when it isn't. Let's do both halves properly.

Half one: pick the model that fits the value

Subscription

The default for a reason: predictable revenue, compounding growth, and customers who stay reachable. It fits when your app delivers value repeatedly (a tool used weekly, data kept current, a service that keeps running). Most SaaS lands at three tiers; more on numbers below.

One-time purchase

Right for utilities: a converter, a generator, a one-shot analysis. Lower friction (no subscription fatigue), but you re-earn revenue every month from strangers instead of renewals. Works best paired with an email list so buyers of product one hear about product two.

Usage-based

If your costs scale per use (AI features especially), charge per use, or sell credit packs. It protects your margin from your heaviest users; a flat $19/month with unlimited AI calls is a standing invitation to lose money on your best customers. Hybrid is common and sensible: a base subscription that includes N credits, then metered beyond.

Freemium

A free tier is a marketing expense, and it should be priced like one. It works when free users cost you pennies and the upgrade wall sits exactly where serious use begins (projects, seats, volume). It fails when the free tier is generous enough to live in forever. Start paid-only if unsure; adding free later is a gift, removing it is a riot.

Numbers to start with

Don't agonize; anchor, launch, adjust. For B2B-ish tools: $9 / $29 / $99. For consumer: $5 to $12. Offer annual at roughly two months free, both for cash flow and because annual customers churn less. Then talk to five paying customers before changing anything. Your pricing page is a hypothesis, not a tattoo.

Half two: plumbing that survives contact

The golden rule: money truth lives on the server

The most common mistake in generated billing code is that the frontend decides who's paid. Feature flags in React state, plan names in localStorage, an isPro boolean the client sends to the API. All of it is theater. The two-day collapse above is what theater costs.

The correct shape is boring and universal:

Stripe (source of truth for payments)
   │  webhooks: checkout.session.completed,
   │  customer.subscription.updated / .deleted,
   │  invoice.payment_failed
   ▼
your database (source of truth for access)
   users.plan, users.status, users.period_end
   ▼
your API (the only place access is decided)
   every protected route checks the database

The client renders what the server already decided. Nothing else touches money.

Webhooks: where billing actually happens

Checkout is a weekend; billing is forever. A subscription's life is dozens of events: renewals, card declines, upgrades, cancellations, refunds. They all arrive as webhooks, which can arrive out of order, arrive twice, or fail delivery, so the webhook handler is your real billing integration. The requirements, each of which generated code routinely skips:

  • Verify signatures. An unverified endpoint lets anyone POST "this user paid."
  • Be idempotent. Stripe retries; processing the same event twice must be harmless.
  • Handle the sad paths. payment_failed and subscription.deleted are where churn and dunning live.
  • Reconcile on a schedule. A daily job comparing Stripe's view against your database catches every missed event before customers do.

Test the flows nobody prompts for

Use Stripe test mode and its clock-advance tooling to simulate a renewal, a decline, and a cancellation before real money moves. Ten minutes of this catches the class of bug that otherwise ships silently and surfaces as "why does my dashboard say 40 subscribers and Stripe say 33."

Taxes: decide, don't drift

Once revenue crosses borders, sales tax and VAT stop being theoretical. Two sane options: Stripe Tax (you stay merchant of record, Stripe calculates and files reports for you to remit) or a merchant-of-record platform that takes the liability wholesale for a bigger cut. Picking either beats the default, which is finding out about EU VAT from an email you don't enjoy.

The launch-week checklist

  • Live keys in environment variables only; test keys nowhere near production. (Your keys are probably in the repo. Check.)
  • Customer portal enabled so people can cancel and update cards without emailing you.
  • Dunning emails on for failed payments; involuntary churn is the most fixable churn.
  • A weekly look at three numbers: new MRR, churned MRR, failed payments recovered.

Monetization is the moment your app becomes a business, and it's also the moment the operational load starts: billing questions in support, revenue metrics to watch, the monthly reconciliation. That layer is part of the production gap, and it recurs forever. Billing is also only one of the systems a SaaS needs; what a business needs beyond the app walks the others with their cost drivers.

Solo wires the second half on day one. Stripe with verified webhooks and server-side entitlement state come with the standard stack, and the operations around them keep running, with your approval on anything that moves money. Join the waitlist →

Keep reading