TutorialsCart to checkout to order

Cart to checkout to order

Take a shopper from “add to cart” to a paid order using hosted Stripe Checkout. You never handle card data — Stripe does. The minimal path is a single call; carts are optional persistence on top.

The model

  1. Your app collects what the shopper wants to buy (in memory, or in an Orchard cart).
  2. You create a checkout session — Orchard prices it against the tenant’s catalog and returns a hosted Stripe Checkout URL.
  3. You redirect the shopper to that URL. They pay on Stripe.
  4. Stripe notifies Orchard; the order is recorded and order.paid fires.

1. Create the checkout session

Requires a key with the checkout:write scope (a pk_* key may hold it, so this can run from a server route or, if you accept the exposure, the client).

curl -X POST https://api-test.theorchard.dev/api/v1/checkout/sessions \
  -H "Authorization: Bearer sk_test_your_key" \
  -H "Content-Type: application/json" \
  -d '{
    "items": [
      { "product_slug": "coldbrew-concentrate", "quantity": 2 },
      { "product_slug": "tote-bag", "quantity": 1, "variant_id": "0191...v3" }
    ],
    "return_url": "https://your-store.com/checkout/success",
    "cancel_url": "https://your-store.com/cart",
    "customer_email": "shopper@example.com"
  }'

Each item is { product_slug, quantity, variant_id? }variant_id is only needed for multi-variant products. customer_email is optional (it links the order to an existing customer and prefills Stripe). The response:

{
  "checkout_url": "https://checkout.stripe.com/c/pay/cs_test_...",
  "order": { "id": "0191...o9", "status": "pending", ... }
}

2. Redirect to Stripe

const res = await fetch(`${API}/checkout/sessions`, {
  method: 'POST',
  headers: { Authorization: `Bearer ${SK}`, 'Content-Type': 'application/json' },
  body: JSON.stringify({ items, return_url, cancel_url, customer_email }),
});
const { checkout_url, order } = await res.json();
// remember order.id so the success page can confirm it
window.location.href = checkout_url;

In test mode, pay with Stripe’s test card 4242 4242 4242 4242, any future expiry, any CVC.

3. Confirm the order

When the shopper returns to your return_url, poll the order’s status (the order flips to paid once Stripe settles and Orchard records it):

curl https://api-test.theorchard.dev/api/v1/checkout/<order_id>/status \
  -H "Authorization: Bearer sk_test_your_key"

Trust the webhook, not the redirect. A shopper can close the tab before the redirect. The authoritative “this order is paid” signal is the order.paid webhook — drive fulfillment from that, and use the status poll only to render a nice confirmation page.

Optional: server-side carts

If you want a cart that persists across devices or feeds abandoned-cart recovery, use the cart endpoints instead of an in-memory list:

StepEndpoint
Create a cartPOST /api/v1/cart
Add / update / remove itemsPOST / PATCH / DELETE /api/v1/cart/{id}/items
Apply a promo codePOST /api/v1/cart/apply-promo
Apply a gift cardPOST /api/v1/cart/apply-gift-card
Save / restorePOST /api/v1/cart/save · POST /api/v1/cart/restore

Then create the checkout session from the cart’s contents. See the API Reference for each cart endpoint’s shape.

Next