Vibe Code a Pricing Page (With Working Plan Logic)

Build a pricing page with AI that connects to real plans — including the upgrade, downgrade, and proration cases nobody asks for.

C
CodeIllusion Team
#vibe-coding #pricing #saas #stripe #tutorial
Vibe Code a Pricing Page (With Working Plan Logic)

Pricing pages are easy to make look right and easy to get wrong underneath. The visual output will be excellent on the first try. The logic — what happens when an existing customer clicks a different plan — will be missing entirely.

This assumes you’ve read vibe code Stripe checkout, which covers the payment plumbing.

Get the Prices From Stripe

Hardcoded prices drift. You run a promotion, change a tier, adjust for a currency — and now the page says one number while the customer is charged another.

Fetch the pricing plans from the Stripe API rather than hardcoding them. Read active products and their prices, cache the result for one hour, and render from that. Include both monthly and annual price IDs per tier.

This also means adding a plan in the Stripe dashboard makes it appear on your site with no deploy.

The Display

Build a pricing page with three tiers side by side. Each shows: name, price, billing period, a short description, a feature list with check icons, and a CTA button. Highlight the middle tier as recommended.

Add a monthly/annual toggle. When annual is selected, show the monthly equivalent with “billed annually at $X” underneath, plus the percentage saved.

Below the tiers: a feature comparison table and an FAQ with 6 questions. Responsive — tiers stack on mobile with the recommended one first.

That mobile detail matters. Stacked tiers default to the cheapest first, which buries the plan you want people to pick.

The Part That’s Always Missing

Ask for the display and you’ll get a page where every button says “Get Started” — including for someone who already subscribes.

The CTA on each tier must depend on the viewer’s state:

  • Logged out → “Start free trial”, goes to signup
  • Logged in, no subscription → “Subscribe”, starts checkout
  • Logged in, on this plan → “Current plan”, disabled
  • Logged in, on a cheaper plan → “Upgrade”
  • Logged in, on a more expensive plan → “Downgrade”

Read the current plan server-side from our database, not from client state.

This is the difference between a picture of a pricing page and a working one.

Upgrades and Downgrades

Two different behaviours, and AI usually implements neither — it just creates a second subscription, so the customer pays twice.

Upgrades take effect immediately using Stripe’s subscription update with proration_behavior set to ‘create_prorations’. Charge the prorated difference now.

Downgrades take effect at period end using a scheduled subscription update. Do not refund the current period. Show the user when the change will apply.

Never create a second subscription. Always modify the existing one.

Then show the pending state:

If a downgrade is scheduled, show a banner: “Your plan changes to X on [date]” with an option to cancel the change.

Feature Gating

The pricing page promises limits. Something has to enforce them.

Create a server-side canAccess(userId, feature) helper that reads the user’s plan from the database and checks it against a plan-limits config. Use it on every gated route and API endpoint — not just to hide UI.

When a limit is hit, return a clear error naming the limit and linking to upgrade.

Gating that only hides buttons is not gating. The endpoint still works.

For usage-based limits:

Track usage counters per user per billing period. Reset them on the subscription renewal webhook, not on a calendar month boundary.

Calendar-month resets don’t line up with billing periods, and the mismatch produces customers who lose access days before renewal.

Trials and Cancellation

Support a 14-day trial with no card required. Track trial_ends_at. Send reminder emails at 7 days, 3 days, and 1 day remaining. On expiry without payment, downgrade to a read-only free tier rather than deleting anything.

Add cancellation in account settings. Cancel at period end, not immediately. Show the exact date access ends. Offer a downgrade to free as an alternative before confirming.

Deleting data at trial end generates furious support tickets. Read-only is the humane default.

The Checklist

  • Prices read from Stripe, cached
  • CTA reflects the viewer’s actual subscription state
  • Upgrade prorates immediately
  • Downgrade schedules for period end
  • Never creates a second subscription
  • Pending plan changes shown with a cancel option
  • Feature gating enforced server-side, not just in UI
  • Usage counters reset on the billing webhook
  • Annual pricing states the billed total clearly
  • Cancellation at period end with the date shown
  • Mobile stacks with the recommended tier first

Test the Awkward Paths

The happy path always works. These are the ones that break:

  1. Subscribe monthly, upgrade to annual mid-period — is the proration right?
  2. Downgrade, then cancel the downgrade before it applies
  3. Cancel, then resubscribe before period end
  4. Let a trial expire without paying — is it read-only, not deleted?
  5. Hit a plan limit — is the error clear and the upgrade link correct?

Walk all five in Stripe test mode before launch.

Next: Vibe code a SaaS MVP puts this in context, or revisit Stripe checkout for the webhook that makes any of it real.

Related reading:

Frequently Asked Questions

Should pricing be hardcoded or pulled from Stripe? +

Pull it from Stripe and cache it. Hardcoded prices drift the moment you run a promotion or change a tier, and the mismatch between what the page shows and what the customer is charged is a support and trust problem.

How do I handle plan upgrades and downgrades? +

Upgrades should take effect immediately with proration. Downgrades should take effect at the end of the current period, since the customer already paid for it. AI implementations typically handle neither and just create a second subscription.

What does AI get wrong on pricing pages? +

It builds the display beautifully and the logic barely at all. Common gaps: no current-plan indicator, no upgrade or downgrade path, prices hardcoded, and no handling of users who already subscribe.

Should I show annual pricing as monthly? +

Showing the monthly equivalent with the billed-annually total underneath is standard and not misleading, as long as both numbers appear. Showing only the discounted monthly figure without stating that it's billed yearly generates chargebacks.

Tagged:

#vibe-coding #pricing #saas #stripe #tutorial

Enjoyed this article?

Get more AI tool picks, coding tutorials, and no-code automation guides every week. No spam, ever.

Found this useful? Share it:

More in AI Coding Tools