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.