Skip to main content

Cart and Checkout

Cart state

The cart lives entirely on the client. There is no server-side cart. Store items in localStorage or your state manager of choice.

Cart item shape:

{
"productId": "69bc36fda53000e2ede23dca",
"quantity": 1,
"type": "product",
"variationKey": "6925a18b3ca2e25fa94c29dd-6925a18b3ca2e25fa94c29d5"
}
  • type is always "product"
  • variationKey is required for products with variations — it is the dash-joined string of option value IDs returned by the variants endpoint. Omit or pass "" for products without variations.

Hydrating the cart

Before showing the cart page or proceeding to checkout, fetch current data for every item:

POST /access/api/v1/products/cart

Body:

{
"cart": [
{
"productId": "69bc36fda53000e2ede23dca",
"quantity": 2,
"type": "product",
"variationKey": ""
}
]
}

Response:

{
"status": "success",
"total": 1,
"data": [
{
"_id": "69bc36fda53000e2ede23dca",
"title": "main product",
"featured": false,
"slug": "main-product",
"primaryImage": null,
"secondaryImage": null,
"hasVariantions": false,
"primaryCategory": {
"_id": "69bc3612a53000e2ede23cff",
"name": "child 2",
"slug": "child-2"
},
"media": [],
"price": 5,
"salePrice": null,
"onSale": false,
"actualPrice": 5,
"minPrice": null,
"maxPrice": null,
"sku": "SKU-B7WI956J7T",
"trackStock": false,
"status": "in-stock",
"sellable": null,
"variationKey": null
}
]
}

Use actualPrice as the authoritative price for totals. Items that are no longer available will be absent from the response — remove them from local cart state and optionally notify the customer.

Validating coupons

POST /access/api/v1/coupons

Body:

{
"coupons": ["SAVE10"],
"cart": [
{ "productId": "69ac75f878a9512e92b56fb5", "quantity": 1, "type": "product" }
]
}

Pass the raw cart items, same shape as the cart hydration request.

Response:

{
"status": "success",
"data": {
"_id": "69e89e523ffcea9688dcf375",
"code": "one-more",
"amount": 10
}
}

Use amount as the discount value to subtract from the order total. Show the discount in the order summary.

Possible errors:

CodeWhat to show
INVALID_COUPON"This coupon code is not valid or conditions not met"
COUPONS_DISABLEDHide the coupon input entirely
COUPON_ZERO_TOTAL"Coupons cannot be applied to a zero-total order"

Placing an order

POST /access/api/v1/orders

Body:

{
"cart": [
{ "productId": "...", "quantity": 1, "type": "product", "variationKey": "" }
],
"name": "Jane Doe",
"email": "customer@example.com",
"phone": "0712345678",
"town": "Nairobi",
"city": "",
"apartment": "",
"room": "",
"note": "",
"coupons": [],
"shippingId": null,
"pickupLocationId": null,
"cartUserId": "customer_id_if_logged_in"
}

name, email, phone, and town are required. The customer does not need to be logged in to place an order. Pass cartUserId only if the customer is logged in — use their customer ID.

Response when payments are enabled:

{
"status": "success",
"data": {
"action": "CHECKOUT-LINK",
"link": "https://..."
}
}

Check for action === "CHECKOUT-LINK" and redirect the customer to link. The payment provider handles the transaction and redirects back to your theme when done. That is why the payment callback pages are required — see Payment Callbacks.

const { data } = await placeOrder(payload);

if (data.action === 'CHECKOUT-LINK') {
window.location.href = data.link;
} else {
// show order confirmation from data
}

Response when no payments are activated:

{
"status": "success",
"data": {
"_id": "69e93be95c08152c63f2b8ef",
"orderNumber": "dels-4584--main",
"products": [
{ "_id": "69bc36fda53000e2ede23dca", "title": "main product", "quantity": 1 }
],
"shippingTotal": 0,
"productsTotal": 5,
"cartTotal": 6,
"taxTotal": 1
}
}

Show the order confirmation directly using this response — no redirect needed.

Possible errors:

CodeWhat to show
ORDER_VALIDATION_FAILED"Could not place your order, please review your cart"
INVALID_SHIPPING_ID"Selected shipping method is no longer available"
PAYMENTS_NOT_ENABLED"Online payments are not available for this store"

Stock validation

Stock is validated at order creation, not before. If a product goes out of stock between cart hydration and order placement, the order will fail. Show an inline error on the affected item and let the customer remove it manually.