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"
}
typeis always"product"variationKeyis 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:
| Code | What to show |
|---|---|
INVALID_COUPON | "This coupon code is not valid or conditions not met" |
COUPONS_DISABLED | Hide 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:
| Code | What 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.