Before you start: make sure your database is set up and Stripe is configured.
Three Paths
- AI Chat (easiest)
- From a template
- Build from scratch
In your project’s AI chat, describe what you want:The AI will scaffold the schema, pages, and checkout endpoint. Review the result and ask for refinements (pricing layout, image sizes, cart vs one-click, etc.).
The Products Table
price_cents(integer) avoids floating-point rounding issues with moneyslug(unique text) is your URL path segmentstripe_price_idlinks the DB row to the Stripe Price objectactivelets you hide products without deleting them
Create Products in Stripe
For each product you want to sell:Add a Price
Stripe lets you have multiple prices per product. For a one-time purchase, pick One-time and enter the amount.
The Listing Page: /shop
Fetch all active products and render them as a grid:
The Detail Page: /shop/[slug]
The Checkout Endpoint
Createapi/checkout.ts:
Buy Now button POSTs to this endpoint and redirects the browser to session.url (Stripe’s hosted checkout page).
Order Confirmation Page: /order-success
Reads session_id from the URL, fetches the session from Stripe, and displays a thank-you message:
The Stripe Webhook
The webhook is where the real work happens — recording orders, decrementing inventory, sending confirmation emails. Stripe calls your endpoint when the payment completes:Create the webhook endpoint
api/stripe-webhook.ts. Verify the signing secret, then handle checkout.session.completed.Decrement inventory
Send a confirmation email
Use your email provider to send the order details. See Send Emails.
Advanced Patterns
Layer these in once the basic single-item checkout works:- Shopping cart — multi-item checkout with a cart state stored in localStorage or a
cartstable - Subscriptions — use Stripe’s subscription mode for recurring plans
- Variants — size/color options with per-variant SKU and stock
- Discount codes — Stripe Coupons applied at checkout
- Abandoned cart recovery — see abandoned cart workflow
- Out-of-stock handling — see low-stock alerts
Verify It Worked
Complete a test checkout
Click Buy Now on a product. On the Stripe checkout page, use test card
4242 4242 4242 4242 with any future expiry and any 3-digit CVC.Confirm order recorded
Check your
orders table — the new row should exist. Stock should have decremented. Confirmation email should be in your inbox.Troubleshooting
'No such price' error
'No such price' error
You’re mixing test and live Stripe keys. Test-mode price IDs don’t work with live-mode keys and vice versa. Keep them consistent — either everything test or everything live.
Checkout loads but won't submit
Checkout loads but won't submit
Usually a missing or incorrect
STRIPE_PUBLISHABLE_KEY env var on the client side, or a mismatch between the publishable key and the secret key’s mode. Check the browser console for Stripe errors.Webhook isn't firing
Webhook isn't firing
In the Stripe Dashboard, go to Developers > Webhooks. Confirm the endpoint URL matches your deployed site. Confirm the signing secret in your env vars matches the one shown in Stripe. Click the webhook’s “Send test event” button to trigger a test delivery and check the response.
Inventory not decrementing after purchase
Inventory not decrementing after purchase
The webhook handler is erroring before it reaches the UPDATE. Check the Stripe webhook attempts log — you’ll see the failed responses with error messages. Then check your server logs via View Logs.
Orders going through but no confirmation email
Orders going through but no confirmation email
Either your email service isn’t configured or the webhook fails after the order insert but before the email send. Use a try/catch around the email call so a mail failure doesn’t break the rest of the order processing.
What’s Next?
Low-Stock Alerts
Get notified before you run out of inventory
Abandoned Cart Recovery
Win back customers who didn’t complete checkout