Skip to main content
Early access — new tools and guides added regularly
🔵 Build Real Projects — Guide 15 of 16
View track
>_ claude codeAdvanced50 min

Build an E-Commerce Store with Stripe

Build a complete online store with a product catalogue, shopping cart, Stripe checkout, webhook processing, and order management — everything needed to sell products online.

What you will build
A production-ready e-commerce store with Stripe payments and order management

E-commerce architecture and Stripe setup

An e-commerce store has five core systems: product catalogue (what you sell), cart (what the customer wants), checkout (collecting payment), order management (tracking purchases), and fulfilment (delivering the product). Stripe handles the checkout system — you build everything else. Ask Claude Code: Create a new Next.js project for an e-commerce store. Set up TypeScript and Tailwind CSS. Create types at src/lib/types.ts for Product (id, name, description, price in pence as integer, images array, category, stock count, slug), CartItem (product id, quantity), Cart (items array, created at), Order (id, customer email, customer name, items with product snapshots and quantities, total in pence, stripe payment intent id, status as pending or paid or shipped or delivered or cancelled, created at, updated at), and Address (line1, line2, city, postcode, country). Install Stripe: npm install stripe @stripe/stripe-js. Create a Stripe account at stripe.com if you do not have one. Copy your test API keys from the Stripe dashboard — you will have a publishable key starting with pk_test_ and a secret key starting with sk_test_. Add both to .env.local: STRIPE_SECRET_KEY and NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEY. Ask Claude Code: Create a Stripe utility at src/lib/stripe.ts that initialises the Stripe SDK with the secret key for server-side use. Create a separate client utility at src/lib/stripe-client.ts that initialises Stripe.js with the publishable key for client-side use. Verify the connection by asking Claude Code to create a quick test script that lists your Stripe account's test balance.

Product catalogue and display

Ask Claude Code: Create a product data file at src/lib/products.ts with 8 sample products across 3 categories. Each product needs a name, description of 2 to 3 sentences, price in pence (like 2999 for 29.99 pounds), two placeholder image URLs, a category (Accessories, Apparel, or Home), stock count, and a URL-friendly slug. Create a product listing page at src/app/shop/page.tsx that displays products in a responsive grid — 1 column on mobile, 2 on tablet, 3 on desktop. Each product card shows the first image, name, price formatted as currency, and category badge. Add category filter buttons above the grid that filter products without a page reload. Add sorting options: price low to high, price high to low, and name A to Z. Create individual product pages at src/app/shop/[slug]/page.tsx with a large image gallery (click to switch between images), product name, price, description, stock availability indicator, quantity selector, and an Add to Cart button. The price formatting is important: always store prices as integers in the smallest currency unit (pence for GBP, cents for USD). Display by dividing by 100 and formatting with Intl.NumberFormat: new Intl.NumberFormat('en-GB', { style: 'currency', currency: 'GBP' }).format(price / 100). This avoids floating-point arithmetic issues that plague currency calculations. Ask Claude Code: Add a related products section below the product details showing 3 other products from the same category. Add breadcrumb navigation showing Shop then Category then Product Name.

Shopping cart with persistence

The cart is the bridge between browsing and buying. Ask Claude Code: Create a cart context at src/contexts/CartContext.tsx using React Context and useReducer. The cart state should include items (array of product ID and quantity pairs), a computed item count, and a computed total in pence. Implement actions for addItem (adds one or increments quantity), removeItem (removes entirely), updateQuantity (sets specific quantity), and clearCart. Persist the cart to localStorage so it survives page refreshes and browser closes. Load from localStorage on first render. When adding an item, check stock availability and do not allow adding more than the available stock. Create a cart page at src/app/cart/page.tsx that shows all cart items in a table with columns for product image, name, unit price, quantity selector with plus and minus buttons, line total, and a remove button. Show the cart total at the bottom with a Proceed to Checkout button. If the cart is empty, show a friendly message with a link back to the shop. Ask Claude Code: Add a cart drawer component at src/components/CartDrawer.tsx that slides in from the right when an item is added. Show a mini version of the cart with item names, quantities, and total. Include a View Cart button and a Checkout button. Auto-close after 5 seconds if the user does not interact. Add a cart icon to the site header with a badge showing the item count. The icon opens the cart drawer on click. Test the complete cart flow: add items from product pages, adjust quantities in the cart, remove items, refresh the page to verify persistence, and verify the total is always correct. Ask Claude Code: Add a stock validation step — when the user opens the cart, re-check product stock levels against cart quantities and show a warning if any product is out of stock or has insufficient stock.

Stripe Checkout integration

Stripe Checkout handles the entire payment UI — card forms, validation, 3D Secure authentication, Apple Pay, and Google Pay. You redirect the customer to Stripe's hosted checkout page and they redirect back when done. Ask Claude Code: Create an API route at src/app/api/checkout/route.ts that creates a Stripe Checkout Session. The endpoint should receive the cart items as a POST body, validate each item exists and has sufficient stock, create line items for Stripe with the product name, price, and quantity, set the success and cancel redirect URLs, and return the session URL. Use the Stripe SDK: const session = await stripe.checkout.sessions.create({ line_items, mode: 'payment', success_url: process.env.NEXT_PUBLIC_URL + '/order/success?session_id={CHECKOUT_SESSION_ID}', cancel_url: process.env.NEXT_PUBLIC_URL + '/cart' }). On the cart page, the Checkout button should call this API endpoint, then redirect to session.url. Ask Claude Code: Create the success page at src/app/order/success/page.tsx. It receives the session_id query parameter, calls Stripe to retrieve the session details, and shows a confirmation page with the order summary, total paid, and a link to continue shopping. Clear the cart on this page since the order is complete. Test the entire flow in Stripe test mode. Use the test card number 4242 4242 4242 4242 with any future expiry date and any CVC. Complete a payment and verify you land on the success page. Check the Stripe dashboard to see the payment. Ask Claude Code: Add error handling for the checkout flow. What if Stripe is down? What if a product price changed between adding to cart and checking out? Validate prices server-side and show a clear error if anything is wrong.

Webhook processing and order creation

The success page redirect is not reliable — users can close their browser before it loads. Webhooks are the reliable way to know a payment succeeded. Stripe sends a POST request to your server when events happen. Ask Claude Code: Create a webhook handler at src/app/api/webhooks/stripe/route.ts. It should verify the webhook signature using the Stripe webhook secret to ensure the request actually came from Stripe and not an attacker. Handle the checkout.session.completed event by creating an order in your database with all the session details: customer email, items purchased, amount paid, and Stripe payment intent ID. Set up the webhook secret: install the Stripe CLI (brew install stripe/stripe-cli/stripe), run stripe login, then run stripe listen --forward-to localhost:3000/api/webhooks/stripe. The CLI gives you a webhook signing secret starting with whsec_ — add it to .env.local as STRIPE_WEBHOOK_SECRET. The signature verification is critical: const event = stripe.webhooks.constructEvent(body, sig, webhookSecret). If verification fails, return a 400 error. Never process unverified webhooks. Ask Claude Code: Add order storage. Create an orders array in a data file initially, then add functions to create an order from a Stripe session and retrieve orders by email. When the webhook fires for checkout.session.completed, fetch the full session with line items from Stripe, create an order record, and decrement product stock for each purchased item. Send a confirmation email to the customer using Resend with the order details. Test by completing a purchase with the test card. Check that the webhook fires in your terminal, the order is created, stock is decremented, and the email arrives. Ask Claude Code: Handle webhook edge cases. What if the webhook fires twice for the same event? Add idempotency — check if an order with that Stripe session ID already exists before creating a duplicate. What if stock hits zero during a webhook? Update the product to show as out of stock.

Order management and customer accounts

Customers need to track their orders and sellers need to manage them. Ask Claude Code: Create an order history page at src/app/orders/page.tsx. Since we do not have authentication yet, use a simple email lookup: the customer enters their email and sees all orders associated with it. Show orders in a table with order ID, date, items summary, total, and status. Click an order to see the full details including each item with its image, name, quantity, and price. Add a status timeline that visually shows the order progress: pending then paid then shipped then delivered, with the current status highlighted. Create an admin order management page at src/app/admin/orders/page.tsx. Show all orders with filtering by status and date range. Add action buttons to update order status — Mark as Shipped should update the status and send a shipping notification email to the customer with an optional tracking number. Ask Claude Code: Add inventory management to the admin area. Show a products table with current stock levels. Highlight products with low stock (under 5 units) in yellow and out of stock in red. Add a restock function that updates the stock count. When a product is out of stock, it should appear on the shop page with a greyed-out Sold Out badge instead of the Add to Cart button. Ask Claude Code: Add basic sales analytics to the admin dashboard. Show total revenue, number of orders, and average order value for the current month. Show a daily revenue chart for the last 30 days. Show the top 5 best-selling products by quantity. These metrics help the store owner understand their business performance at a glance.

Discounts, shipping, and taxes

Real e-commerce needs pricing complexity. Ask Claude Code: Add discount code support. Create a discounts data structure with fields for code string, discount type as percentage or fixed amount, value, minimum order amount, maximum uses, current uses, and expiry date. Add an API endpoint to validate a discount code: check it exists, is not expired, has not exceeded maximum uses, and the order meets the minimum amount. Add a discount code input field on the cart page that validates in real time and shows the discount applied to the total. Pass the discount to the Stripe Checkout Session using the discounts parameter with a Stripe Coupon. Ask Claude Code: Add shipping calculation. Create a shipping rates structure with options like Standard at 3.99 with 3 to 5 day delivery and Express at 7.99 with next day delivery. Free shipping over 50 pounds for standard. On the cart page, show shipping options with radio buttons. Update the total to include shipping. Add free shipping messaging: show a progress bar saying Spend X more for free shipping when the cart is close to the threshold. Pass shipping as a line item in the Stripe Checkout Session. For tax, Stripe Tax can handle calculation automatically, but for a simpler approach: ask Claude Code: Add VAT calculation at 20 percent. Show a price breakdown on the cart page: subtotal, discount if applied, shipping, VAT, and total. VAT should be calculated on the subtotal after discount plus shipping. Display prices as including VAT on product pages to comply with UK consumer law, but show the breakdown at checkout. Ensure all calculations use integer arithmetic in pence to avoid floating-point rounding errors. Test edge cases: discount code that reduces the total below zero should bring it to zero. Free shipping threshold should be calculated before discount is applied.

Production deployment and launch checklist

Before accepting real payments, every detail matters. Ask Claude Code: Create a comprehensive e-commerce launch checklist and walk me through each item. Switch Stripe to live mode: replace test API keys with live keys in your production environment variables. Never put live keys in .env.local — they go in Vercel environment variables only. Set up the production webhook endpoint in the Stripe dashboard pointing to your Vercel URL. Test with a real card for a small amount and immediately refund it to verify the complete flow works in production. Security checks: ensure all API routes validate inputs, the webhook handler verifies signatures, HTTPS is enforced everywhere, no API keys are exposed in client-side code, and CSRF protection is in place for state-changing operations. Ask Claude Code: Run a security audit on all API routes. Check for input validation, authentication where needed, rate limiting on the checkout endpoint, and proper error handling that does not leak internal details to users. SEO and performance: add meta tags and Open Graph images for product pages so they look good when shared on social media. Add structured data (JSON-LD) for products so Google shows rich results with price and availability. Optimise images with Next.js Image component for lazy loading and responsive sizes. Run Lighthouse and address any performance issues. Legal requirements: add a terms of service page, a privacy policy covering data collection and payment processing, a returns and refund policy, and cookie consent. Ask Claude Code: Generate templates for these legal pages tailored to a UK-based e-commerce store. After completing the checklist, you have a production e-commerce store that can accept real payments, manage orders, handle discounts and shipping, and comply with legal requirements. The entire system was built with Claude Code — from product catalogue to Stripe integration to order management.

Related Lesson

Payment Integration

This guide is hands-on and practical. The full curriculum covers the conceptual foundations in depth with structured lessons and quizzes.

Go to lesson