examples/storefront Public
id: checkout
type: concept
owner: justin
component: storefront-api
describes:
- src/checkout.ts
- src/orders.ts
- src/payments.ts
- migrations/0003_orders.sql
reviewed: 2026-10-02
Checkout
POST /carts/:id/checkout with an email and a shipping address turns an open cart into an order and returns what the browser needs to take the payment. The steps are in the checkout flow on the Architecture tab.
Taking stock
Stock is taken here and nowhere else ([[0004-take-stock-at-checkout]]). The order, its lines, one UPDATE products SET stock = stock - n per line and closing the cart go to D1 as one batch. products.stock has CHECK (stock >= 0), so when two shoppers race for the last pair of socks, the second batch fails as a whole and that shopper gets 409 out_of_stock with what is left of each item. A first pass checks stock before the batch so the common case gets the same answer without a failed write.
Lines keep the price that was in the cart. The shopper pays what the cart showed them.
Charging
After the batch, checkout asks the payment provider for a PaymentIntent for the order total ([[0005-stripe-payment-intents]]) and stores its id on the order. The response has the order and the intent's client_secret; the browser confirms the payment with Stripe directly, so card details never reach the Worker.
If Stripe fails or times out, nothing has been charged, so the checkout is undone in one batch: the stock goes back, the order is deleted and the cart opens again. The shopper gets 502 payments_unavailable and can retry.
Retries
Checking out the same cart again while its order is waiting for payment returns that order and the same client secret: the intent is created with the idempotency key order-<id>, so Stripe returns the existing one. Once the order is paid or cancelled, the cart answers 409 cart_closed.
Order states
| Status | Meaning |
|---|---|
pending_payment |
Created at checkout; stock is held for it |
paid |
Stripe reported the payment succeeded |
cancelled |
Not paid; the stock went back |
fulfilled |
Handed to the warehouse |
GET /orders/:id returns the order. The id is a random UUID that only the shopper who checked out has.