Skip to content
Flows
App Builder Intermediate · 60-120 minutes

Stripe Checkout Flow

Add real Stripe payments with checkout, webhooks, and payment status - not a button that pretends to charge.

Start Route · 7 steps

The route

7 steps to Done

  1. 01

    Define the payment spec

    Lock what is being sold, prices, and payment states before touching Stripe.

    Preview prompt + verify gate ▾

    Define the payment spec for this app. Specify: what is being sold (one-time purchase or subscription plans with exact prices and currency), the payment states we must track (pending, paid, failed, canceled), what a user gets when paid, and where payment records are stored. State explicitly that all amounts live on the server and that payment success is only confirmed server-side. Do not implement yet.

    • Products and exact prices are listed
    • One-time vs subscription is decided
    • Payment states are enumerated
    • Server-side confirmation is stated as a rule
  2. 02

    Set up Stripe keys and packages securely

    Wire Stripe credentials the right way so keys never leak to the client.

    Preview prompt + verify gate ▾

    Set up the Stripe integration foundation. Install the official Stripe server library, put STRIPE_SECRET_KEY (test mode) in backend environment variables only, and expose nothing secret to the frontend. Create a config check that fails loudly at startup if the key is missing. Show me exactly which files changed and confirm the secret key appears in zero frontend files.

    • Secret key is only in backend environment config
    • No secret appears in any frontend file
    • Missing key produces a clear startup error
  3. 03

    Create the checkout session endpoint

    Payments start server-side: build the endpoint that creates a real Stripe Checkout session.

    Preview prompt + verify gate ▾

    Implement a backend endpoint that creates a Stripe Checkout session. Requirements: the endpoint receives only a product/plan identifier from the client and looks up the amount server-side; it creates a session with success and cancel URLs pointing back to our app; it stores a pending payment record (id, user/session, product, amount, status=pending, created_at) in the database before returning the checkout URL; it returns the session URL for redirect. Reject unknown product identifiers.

    • Amounts are looked up server-side, never sent by the client
    • A pending payment record is created in the database
    • The endpoint returns a live checkout URL
    • Unknown products are rejected with a clear error
  4. 04

    Build the pay button and redirect

    Connect the UI to the real session endpoint with proper loading and error states.

    Preview prompt + verify gate ▾

    Wire the frontend payment trigger. Requirements: the pay/upgrade button calls our checkout endpoint, shows a loading state while the session is created, redirects the browser to the returned Stripe URL, and shows a visible error message if session creation fails. Do not build any fake success behavior in this step - the user must land on real Stripe checkout.

    • Button shows loading while the session is created
    • Browser lands on checkout.stripe.com
    • Endpoint failure shows a visible UI error
  5. 05

    Confirm payment server-side

    The success redirect proves nothing - verify payment status with Stripe before granting anything.

    Preview prompt + verify gate ▾

    Implement server-side payment confirmation. Requirements: build the success page to call a backend verification endpoint with the session id; the backend retrieves the session from Stripe and checks payment_status; only then update the payment record to paid and grant the purchased value; handle the cancel URL by marking the record canceled and showing a clear 'payment not completed' state with a retry option. If webhooks are feasible in this environment, also implement the checkout.session.completed webhook as the authoritative confirmation.

    • Success page triggers backend verification, not a local status change
    • Payment record flips to paid only after Stripe confirms
    • Cancel path shows a non-success state with retry
    • Refreshing the success page does not double-grant
  6. 06

    Reflect paid state in the UI

    Users must see what they paid for - surface payment status everywhere it matters.

    Preview prompt + verify gate ▾

    Surface payment state in the product. Requirements: show the user's plan/purchase status in the UI (badge, settings row, or dashboard banner); gate paid features on the server-verified paid state; show payment history (date, product, amount, status) from our database records; add empty state for no payments and a clear pending state while verification is running.

    • Paid status is visible in the UI after purchase
    • Paid features check the server-verified state
    • Payment history lists real database records
    • Pending and empty states exist
  7. 07

    Test with Stripe test cards

    Prove the whole loop with real test-mode payments including failure paths.

    Preview prompt + verify gate ▾

    Run an end-to-end payment test in Stripe test mode and report PASS/FAIL with evidence for: successful payment with card 4242 4242 4242 4242; declined payment with card 4000 0000 0000 0002; user cancels on the Stripe page and returns; refresh of the success page (no double grant); and payment record status transitions in the database for each case. Fix every failure and re-run.

    • 4242 test card completes and unlocks paid state
    • Declined card shows a visible failure state
    • Cancel returns cleanly without fake success
    • Database records show correct status transitions