CommerceOS docsmenu

Storefront API

Cart & checkout

Carts are server-side and cheap. Checkout reserves stock atomically, creates a pending order, and hands you a payment clientSecret for the provider’s hosted fields — card data never touches CommerceOS or your code.

POST/storefront/v1/cartsrate tier: public-write
BodyTypeDescription
itemsreq{ variantId, quantity }[]Initial lines. Quantities are validated against live stock at checkout, not here.
wire · create a cart
▸ POST /storefront/v1/carts▸ X-Publishable-Key: pk_live_9f2…{ "items": [ { "variantId": "be970bc3-…", "quantity": 1 } ] }◂ 201 Created{ "id": "b0079de2-…", "items": [ … ],  "subtotal": { "amount": 79900, "currency": "INR" } }
GET/storefront/v1/carts/:idrate tier: public-read

Carts are addressed by UUID — persist the id in a cookie or local storage. The SDKs ship a small cart store that does this for you.

PUT/storefront/v1/carts/:id/itemsrate tier: public-write

Replaces the full line set — send the complete desired state rather than deltas, and concurrent tabs cannot corrupt each other.

Checkout

POST/storefront/v1/checkoutrate tier: public-write
BodyTypeDescription
cartIdrequuidThe cart to convert.
emailreqstringBuyer email — receives order lifecycle mail.
countrystringISO country for tax/shipping calculation.
discountCodestringApplied and validated server-side.
wire · checkout — reserve, then pay
▸ POST /storefront/v1/checkout▸ X-Publishable-Key: pk_live_9f2…▸ Idempotency-Key: 0d1f37a2-5f…        # required — retries are safe{ "cartId": "b0079de2-…", "email": "buyer@example.com" }◂ 201 Created{  "order": { "id": "4593eb78-…", "number": 32, "status": "pending",             "total": { "amount": 100182, "currency": "INR" }, … },  "payment": { "provider": "stripe", "ref": "pi_3Qx…",               "status": "pending", "clientSecret": "pi_3Qx…_secret_…" }}# order stays "pending" until the provider webhook confirms payment

Idempotency is required here. Send a UUID in Idempotency-Key; retrying the identical request replays the original response instead of double-reserving. Stock is reserved with an atomic conditional update — overselling the last unit is structurally impossible, and expired pending orders release their reservation automatically.

Never collect card numbers. Confirm payment with the provider’s hosted fields/elements using payment.clientSecret. The order flips to paid only via the provider’s signed webhook — poll the order or listen to the order.paid event.