Payment Gates

This is where payments become real and secure. When a user pays, Stripe notifies your app via a webhook; you record their subscription in Neon, and you gate premium features by checking the signed-in user (Clerk) against what they've paid for. It ties together everything from this level.

Payments are a big, risky feature – like auth, you'll build it on a branch and test it on a Vercel preview before merging to main.

Skills carry the hard parts

Payments are unforgiving, so let the skills own the correctness. You've installed the Stripe skill (Payment Provider lesson), and you already have the Clerk skill (auth) and Neon (via the Vercel plugin). If you're unsure the Stripe skill is active, ask Claude to reinstall it and start a new chat – then hand it your context before building.

1. Plan it on a branch

Start a branch for the payment work and plan the flow with Claude in plan mode.

Branch and plan the payment system (in plan mode)
Create a branch for my payment work and switch to it. Then, in plan mode, plan the secure payment system using Stripe + Clerk + Neon:
- a Stripe webhook endpoint that verifies Stripe's signature and handles subscription events,
- a Neon table that records each subscription, linked to the Clerk user (map the Stripe customer to my user),
- server-side feature gating: check the signed-in user (Clerk) and their subscription (Neon) before granting premium access.
Show me the plan before we build. Don't go live yet – we test on the preview first.

Outcome: You're on a payment branch with a clear plan.

I planned the payment system on a branch

2. Build the webhook handler and Neon sync

The webhook is how your app learns who has paid. Build it carefully – verifying Stripe's signature is non-negotiable.

Build the Stripe webhook and Neon subscription sync
Build the payment plumbing with the Stripe skill:
1.A Stripe webhook endpoint (route handler) that **verifies the Stripe signature** on every request before doing anything.
2.Handle the key subscription events (created, updated, canceled). On each, **upsert the subscription** into a Neon table – store the Stripe customer id, the Clerk user id it maps to, the plan, the status, and the current period end.
3.Map the Stripe customer to my Clerk user (e.g. store the Stripe customer id on the user when they first check out).
4.Store the Stripe webhook signing secret in the Vercel vault.
Make it idempotent – so the same Stripe event arriving twice can't grant access twice – and keep it all server-side. Show me how to test it.

Outcome: When a subscription changes in Stripe, your Neon database stays in sync – securely.

Stripe webhooks sync subscriptions into Neon

3. Gate premium features

Now lock premium features to paying users. The check is always server-side: who is the user (Clerk), and are they subscribed (Neon)?

Gate features by Clerk user + Neon subscription
Add feature gating:
1.A server-side helper that, for the signed-in Clerk user, looks up their subscription in Neon and returns whether they have an active paid plan.
2.Use it to lock my premium features – in Server Actions and any protected route handlers, not just in the UI.
3.For free users, show the upgrade prompt (link to the pricing page) instead of the premium feature.
4.Make sure a logged-out or non-paying user can never reach the premium functionality, even by calling the server directly.
Show me how to test free vs paid access.

Outcome: Premium features are locked to paying users, enforced on the server.

Premium features are gated by subscription, server-side

4. Test the whole flow on your preview

Push the branch for a preview, point Stripe's test webhooks at it, and run the full loop.

Test payments end-to-end on the preview
Push my payment branch so Vercel builds a preview, and help me test the full flow there with Stripe in test mode:
1.Point Stripe's webhook at my preview URL.
2.Subscribe as a test user (use card 4242 4242 4242 4242) → confirm the webhook fires, Neon records the subscription, and my premium feature unlocks.
3.Cancel the subscription → confirm Neon updates and the feature locks again.
4.Confirm a non-paying user can't access the premium feature (including by calling the server directly).
Fix anything that's off. Don't merge to main yet – we'll do the production cutover (live keys) in the next lesson.

Outcome: Your full payment system works on the preview in test mode – ready for the production cutover next lesson.

I tested the full payment system on my preview