Add to Cart
Add a product to the shopping cart. The request body depends on the product type — simple and virtual need only productId + quantity, while configurable, bundle, grouped, and downloadable products require their option selections.
Endpoint
POST /api/shop/add-product-in-cartAuthentication
This endpoint operates on a specific cart, so every request needs a cart token (Bearer), in addition to the storefront key:
| Header | Required | Description |
|---|---|---|
X-STOREFRONT-KEY | Yes | Your storefront API key |
Authorization | Yes | Bearer <token> — a guest cart token or a logged-in customer token |
Content-Type | Yes | application/json |
Get a guest cart token first with Create Cart (POST /api/shop/cart-tokens) — its cartToken is the Bearer value. For a logged-in customer, use the token from Customer Login.
Request body by product type
All types take productId and quantity. Add the fields for the product's type:
| Field | Type | Applies to | Description |
|---|---|---|---|
productId | integer | all | The product ID being added |
quantity | integer | all | Quantity (minimum 1) |
selectedConfigurableOption | integer | configurable | Required. The chosen variant product ID. |
superAttribute | object | configurable | { "<attributeId>": <optionId> }. Accepted but not used by add-to-cart — the cart resolves the variant from selectedConfigurableOption, so always send that. |
bundleOptions | object | bundle | { "<optionId>": [<bundleOptionProductId>, …] } — the bundle-option-product IDs (from the product detail), not raw product IDs. |
bundleOptionQty | object | bundle | { "<optionId>": <qty> } — quantity per bundle option |
groupedQty | object | grouped | { "<associatedProductId>": <qty> } — include every associated product |
links | array | downloadable | [<linkId>, …] — selected download-link IDs |
customizableOptions | object | simple / virtual / downloadable | { "<optionId>": [<valueId>, …] } — chosen customizable-option values. See below. |
The option IDs (variant product IDs, bundle-option-product IDs, associated product IDs, link IDs) come from the product detail response — fetch the product first to discover them. The product, variant, and bundle-option products must be active and in stock, or the item is rejected.
Customizable options
Customizable options are extra inputs an admin attaches to a product (a weight dropdown, a flavour picker, an engraving text field). They are not limited to configurable products — a simple or virtual product can carry them. Read them from the product's customizableOptions (Get Product): each option has an id and a prices array whose entries each have an id (the value id), and isRequired marks the mandatory ones.
Send the selections as customizableOptions — a map of option id → an array of chosen value ids:
"customizableOptions": { "9": [9], "10": [12] }Option 9 (Weight) → value 9 (1kg); option 10 (Flavour) → value 12 (Pineapple). The array form supports multi-select; for a text/textarea option the array holds the entered string. Include every option whose isRequired is true, or the request returns 422. The chosen values come back on the cart item's options so you can show them on the cart page.
File-type customizable options
A file-type option needs a file upload, which cannot travel in a JSON body. Upload the file first at Upload Customizable File (a separate REST call that returns a token), then send the token here as that option's value:
"customizableOptions": { "9": [9], "10": [12], "11": ["<upload-token>"] }The full flow, endpoint, and rules are on the Upload Customizable File page.
Use the example dropdown (top-right) to see the exact body for each product type.
Response
On success the endpoint returns the full updated cart (HTTP 200), not just the added line. Key fields:
| Field | Type | Description |
|---|---|---|
id | integer | Cart ID |
itemsCount | integer | Number of line items |
items | array | Cart line items (each with productId, name, quantity, type, options, formattedTotal, …) |
subtotal / grandTotal | decimal | Cart totals (raw) |
formattedSubtotal / formattedGrandTotal | string | Localised, currency-formatted totals |
couponCode | string|null | Applied coupon, if any |
success | boolean | Whether the add succeeded |
message | string | Human-readable result |
Behavior
- If the same product (same options) is already in the cart, its quantity is increased.
- Stock and saleability are validated; an inactive/out-of-stock item is rejected.
- Booking products are added through the booking-specific flow, not this endpoint.
Related Resources
- Create Cart — get a guest cart token first
- Get Cart
- Update Cart Item
- Remove Cart Item
- Upload Customizable File — stage a file-option file, then reference the token here
- Get Product — read a product's customizable options and supported file extensions

