Skip to content

Cart AJAX API

The cart API answers on the store’s own domain, so theme JavaScript calls it with relative URLs. Responses are JSON with prices in minor units, the same shape as Shopify’s.

Request Does
GET /cart.js The cart.
POST /cart/add.js Adds one or more variants.
POST /cart/change.js Changes one line’s quantity or properties.
POST /cart/update.js Changes several quantities, the note or attributes.
POST /cart/clear.js Empties the cart.

Requests take JSON (Content-Type: application/json) or form data. Without .js, POST /cart/add is a plain form post that redirects to the cart page: that’s what {% form 'product' %} does when JavaScript is off.

const res = await fetch("/cart/add.js", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: variantId, quantity: 1, properties: { "Gift message": "Eid Mubarak" } }),
});
const item = await res.json(); // the added line

Add several at once with { items: [{ id, quantity }, …] }; the answer is then { items: [...] }.

await fetch("/cart/change.js", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ id: lineKey, quantity: 2 }), // or { line: 1, quantity: 0 } to remove the first line
});

id is the line’s key (or a variant ID when that variant is in the cart once); line is the 1-based position. Quantity 0 removes the line.

await fetch("/cart/update.js", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ updates: { [lineKey]: 3 }, note: "Please call before delivery", attributes: { "Delivery slot": "Evening" } }),
});

updates is an object of line keys (or variant IDs) to quantities, or an array of quantities in line order.

{
"token": "…",
"item_count": 3,
"total_price": 122000,
"items_subtotal_price": 122000,
"original_total_price": 122000,
"total_discount": 0,
"currency": "QAR",
"note": "",
"attributes": {},
"requires_shipping": true,
"items": [
{
"key": "…", "id": "…", "variant_id": "…", "product_id": "…",
"title": "Embroidered linen abaya - M / Sand", "product_title": "Embroidered linen abaya", "variant_title": "M / Sand",
"quantity": 2, "price": 45000, "final_price": 45000, "line_price": 90000, "final_line_price": 90000,
"url": "/products/embroidered-linen-abaya?variant=…", "image": "https://…", "properties": {}
}
],
"cart_level_discount_applications": [],
"discount_codes": []
}

Format prices on the page with the store’s currency: window.Sooquna.currency holds its code.

Problems answer with an HTTP status and:

{ "status": 422, "message": "Cart Error", "description": "Only 2 left in stock." }

Show description to the shopper.

After a change, re-render the cart drawer and the header’s cart count with the section rendering API:

const html = await (await fetch(`${location.pathname}?sections=cart-drawer,sections--header-group__header`)).json();

The product_added_to_cart event is sent for you after a successful add.js.

Was this page helpful?