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
- Your app collects what the shopper wants to buy (in memory, or in an Orchard cart).
- You create a checkout session — Orchard prices it against the tenant’s catalog and returns a hosted Stripe Checkout URL.
- You redirect the shopper to that URL. They pay on Stripe.
- Stripe notifies Orchard; the order is recorded and
order.paidfires.
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.paidwebhook — 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:
| Step | Endpoint |
|---|---|
| Create a cart | POST /api/v1/cart |
| Add / update / remove items | POST / PATCH / DELETE /api/v1/cart/{id}/items |
| Apply a promo code | POST /api/v1/cart/apply-promo |
| Apply a gift card | POST /api/v1/cart/apply-gift-card |
| Save / restore | POST /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
- Receive webhooks — react to
order.paidreliably. - Customer sign-in — let shoppers see their orders.