Cart + checkout
Build buyer flows that add items, apply discounts, set shipping, and hand off to checkout.
Buyer-side state — create cart, add items, apply coupons, set address, initiate Stripe checkout.
Carts are the buyer's in-progress checkout state. The REST cart API mirrors what the hosted storefront does — create a cart, add items, apply a coupon, set the shipping address, initiate Stripe checkout. No auth required.
Endpoints
| Method + path | Purpose |
|---|---|
POST /api/storefront/v1/carts | Create a cart. Returns a token. |
GET /api/storefront/v1/carts/{token} | Fetch the current cart. |
PUT /api/storefront/v1/carts/{token} | Update shipping address, selected option, buyer. |
DELETE /api/storefront/v1/carts/{token} | Cancel the cart. |
POST /api/storefront/v1/carts/{token}/items | Add a line item. |
POST /api/storefront/v1/carts/{token}/coupon | Apply a coupon code. |
POST /api/storefront/v1/carts/{token}/checkout | Initiate Stripe checkout. Returns a redirect URL. |
Create
bash
curl -X POST https://aly.store/api/storefront/v1/carts \ -H "Content-Type: application/json" \ -d '{ "site_slug": "acme", "buyer": { "email": "buyer@example.com" } }'json
{ "token": "cart_8f3a...", "status": "active", "site_slug": "acme", "items": [], "totals": { "subtotal": 0, "shipping": 0, "tax": 0, "discount": 0, "total": 0 }, "buyer": { "email": "buyer@example.com" }, "expires_at": "..."}Add a line item
bash
curl -X POST https://aly.store/api/storefront/v1/carts/cart_8f3a.../items \ -H "Idempotency-Key: $(uuidgen)" \ -H "Content-Type: application/json" \ -d '{ "product_id": "prod_abc", "variant_options": { "color": "natural" }, "quantity": 2 }'Apply a coupon
bash
curl -X POST https://aly.store/api/storefront/v1/carts/cart_8f3a.../coupon \ -H "Content-Type: application/json" \ -d '{ "code": "WELCOME10" }'Set the shipping address
bash
curl -X PUT https://aly.store/api/storefront/v1/carts/cart_8f3a... \ -H "Content-Type: application/json" \ -d '{ "shipping_address": { "country": "US", "state": "CA", "postcode": "94110" }, "selected_shipping_option_id": "ship_std" }'Initiate checkout
bash
curl -X POST https://aly.store/api/storefront/v1/carts/cart_8f3a.../checkout \ -H "Content-Type: application/json" \ -d '{ "return_url": "https://my-app.example/thanks" }'json
{ "redirect_url": "https://checkout.stripe.com/c/pay/cs_test_...", "session_id": "cs_stripe_...", "expires_at": "..."}Redirect the buyer there. On success they return to your return_url; the cart status moves to completed when the Stripe webhook confirms.
REST cart vs UCP checkout
The REST cart drives Stripe-hosted checkout — best for buyer-facing UIs. UCP's checkout sessions are the agent-shaped equivalent — better when an agent needs the server-authoritative price breakdown without redirecting to a hosted page. Both write the same underlying cart rows in Convex.
Cart shape
json
{ "token": "cart_8f3a...", "status": "active" | "abandoned" | "completed", "site_slug": "acme", "items": [ { "id": "li_1", "product_id": "prod_abc", "variant_id": "var_1", "name": "Linen Tote — natural", "quantity": 2, "unit_price": 4200, "subtotal": 8400, "image_url": "..." } ], "shipping_address": { "country": "US", "state": "CA", "postcode": "94110" }, "shipping_options": [ { "id": "ship_std", "label": "Standard", "amount": 500 } ], "selected_shipping_option_id": "ship_std", "coupon": { "code": "WELCOME10", "amount_off": 840 }, "totals": { "subtotal": 8400, "shipping": 500, "tax": 720, "discount": 840, "total": 8780 }, "buyer": { "email": "buyer@example.com" }, "expires_at": "..."}Was this page helpful?