Once a Cart exists, you modify it by sending a
POST request containing an array of update actions. Every update request must include the Cart's current version to ensure optimistic concurrency control, preventing race conditions and accidental overwrites.Manage Line Items
Add a Product to the Cart (addLineItem)
Use this action when the customer adds another catalog item to the Cart. For the full request shape and edge cases, see Add LineItem.
import { apiRoot } from "../ctp-root";
import { Cart, CartUpdateAction } from "@commercetools/platform-sdk";
/**
* Adds a product (Line Item) to an existing Cart.
* @param storeKey The key of the Store where the cart exists.
* @param cartId The ID of the cart to update.
* @param version The current version of the Cart for optimistic locking.
* @param sku The SKU of the Product Variant to add.
* @param quantity The number of items to add.
* @returns A Promise resolving to the updated Cart.
*/
async function addLineItemToCart(
storeKey: string,
cartId: string,
version: number,
sku: string,
quantity: number
): Promise<Cart> {
const addLineItemAction: CartUpdateAction = {
action: "addLineItem",
sku, // The SKU of the Product Variant
quantity,
};
const { body } = await apiRoot
.inStoreKeyWithStoreKeyValue({ storeKey })
.carts()
.withId({ ID: cartId })
.post({
body: {
version: version,
actions: [addLineItemAction],
},
})
.execute();
return body;
}
If the added item matches an existing Line Item across the merge-relevant attributes, the existing quantity increases instead of creating a second Line Item. For the complete merge rules, see Merge rules.
For more information about how
inventoryMode affects inventory updates after Order creation, see Manage inventory with the Cart.Remove a Product from the Cart (removeLineItem)
Use this action when the customer reduces quantity or removes a product entirely. If you omit
quantity, the whole Line Item is removed. For the complete behavior, see Remove LineItem./**
* Removes a specific quantity of a Line Item from an existing Cart.
* @param lineItemId The ID of the Line Item to remove from.
* @param quantity The number of items to remove. If omitted, removes the entire Line Item.
*/
async function removeLineItemFromCart(
storeKey: string,
cartId: string,
version: number,
lineItemId: string,
quantity?: number
): Promise<Cart> {
const removeLineItemAction: CartUpdateAction = {
action: "removeLineItem",
lineItemId,
quantity, // Omit this property to remove the full quantity
};
// ... execute post request
}
Add an external Line Item (addCustomLineItem)
Use
addCustomLineItem when you need to charge for something that is not represented as a Product Variant, such as installation fees or partner-provided services. For the complete behavior, see Add CustomLineItem.import {
Cart,
CartUpdateAction,
TypedMoneyDraft,
} from "@commercetools/platform-sdk";
/**
* Adds an external item (as a Custom Line Item) to an existing Cart.
* @param name Localized name of the external item, for example, { "en-US": "Installation Fee" }.
* @param quantity The quantity of the external item.
* @param money The price of the external item.
* @param slug A unique, URL-friendly identifier for the custom Line Item.
*/
async function addExternalLineItem(
storeKey: string,
cartId: string,
version: number,
name: { [key: string]: string },
quantity: number,
money: TypedMoneyDraft,
slug: string
): Promise<Cart> {
const addCustomLineItemAction: CartUpdateAction = {
action: "addCustomLineItem",
name,
quantity,
money,
slug,
};
// ... execute post request
}
Manage Addresses
Set Shipping (setShippingAddress)
Use this action when the Cart needs a shipping destination for taxes, shipping method selection, or final review. For the endpoint behavior, see Set Shipping Address.
import { Cart, CartUpdateAction } from '@commercetools/platform-sdk';
// Define a type for the address data for better type-safety and readability
type CartAddress = {
id: string;
firstName: string;
lastName: string;
streetName: string;
streetNumber: string;
postalCode: string;
city: string;
mobile?: string;
country: string;
};
/**
* Sets the shipping on a cart by providing the full address details.
* @param storeKey The key of the Store.
* @param cartId The ID of the Cart to update.
* @param version The current version of the Cart.
* @param shippingAddress The full address object for shipping.
*/
async function setAddressWithDetails(
storeKey: string,
cartId: string,
version: number,
shippingAddress: CartAddress,
): Promise<Cart> {
const actions: CartUpdateAction[] = [
{
action: 'setShippingAddress',
address: {
id: shippingAddress.id,
firstName: shippingAddress.firstName,
lastName: shippingAddress.lastName,
streetName: shippingAddress.streetName,
streetNumber: shippingAddress.streetNumber,
postalCode: shippingAddress.postalCode,
city: shippingAddress.city,
mobile: shippingAddress.mobile,
country: shippingAddress.country,
},
},
];
// The body of your API request would be:
const requestBody = {
version,
actions,
};
// This is a placeholder return for the example
return {} as Cart;
}
// --- How to use the function ---
// 1. Define your address data based on the customer record
const myAddress: CartAddress = {
id: 'ZKCtEGyo',
firstName: 'Example',
lastName: 'Person',
streetName: 'Down Under st',
streetNumber: '360',
postalCode: '3000',
city: 'Melbourne',
mobile: '+61434126439',
country: 'AU',
};
// 2. Call the function (assuming shipping and billing addresses are the same)
setAddressWithDetails(
'my-store',
'zen-electron-us',
5, // The current cart version
myAddress,
);
Advanced Cart features
Add a Shopping List to the Cart (addShoppingList)
Use this action when the customer wants to convert a saved Shopping List into purchasable Cart items in one step. For the full behavior, see Add Shopping List.
/**
* Adds all items from a Shopping List to an existing Cart.
* @param shoppingListId The ID of the Shopping List to add.
*/
async function addShoppingListToCart(
storeKey: string,
cartId: string,
version: number,
shoppingListId: string
): Promise<Cart> {
const addShoppingListAction: CartUpdateAction = {
action: "addShoppingList",
shoppingList: {
typeId: "shopping-list",
id: shoppingListId,
},
};
// ... execute post request
}
Handle external tax calculations
To use an external tax service, you must first change the Cart's tax mode. The example below uses the
ExternalAmount mode, where your tax service provides the exact tax amounts for the Cart. For a full guide on integrating third-party tax providers, see Integrate tax.Step 1: Change the Tax Mode: this is a prerequisite for all external tax actions.
const changeTaxModeAction: CartUpdateAction = {
action: "changeTaxMode",
taxMode: "ExternalAmount", // or 'External'
};
Step 2: Set the external tax: after changing the mode, apply the tax data from your external service.
import {
Cart,
CartUpdateAction,
Money,
TaxPortionDraft,
ExternalTaxRateDraft,
CartSetCartTotalTaxAction,
CartSetLineItemTaxAmountAction,
} from "@commercetools/platform-sdk";
// --- Helper Interface for clarity ---
/**
* Defines the data needed to set the external tax for a single Line Item.
*/
export interface LineItemTaxDetails {
lineItemId: string;
totalGross: Money;
taxRate: ExternalTaxRateDraft;
}
/**
* Sets an external tax amount for the entire cart and for each Line Item.
* This is used when the Cart's taxMode is 'ExternalAmount'.
*
* @param storeKey The key of the store.
* @param cartId The ID of the Cart to update.
* @param version The current version of the Cart.
* @param externalTotalGross The total gross amount of the Cart (including all taxes) from the external service.
* @param lineItemTaxDetails An array containing the tax details for each Line Item.
* @param externalTaxPortions An optional breakdown of the total Cart tax into different portions (for example, state or federal).
*/
async function setExternalTaxForCart(
storeKey: string,
cartId: string,
version: number,
externalTotalGross: Money,
lineItemTaxDetails: LineItemTaxDetails[],
externalTaxPortions?: TaxPortionDraft[]
): Promise<Cart> {
// This function will generate multiple update actions
const updateActions: CartUpdateAction[] = [];
// 1. Action to set the total tax for the entire cart
const setCartTotalTaxAction: CartSetCartTotalTaxAction = {
action: "setCartTotalTax",
externalTotalGross,
externalTaxPortions,
};
updateActions.push(setCartTotalTaxAction);
// 2. Actions to set the tax for each individual Line Item
for (const item of lineItemTaxDetails) {
const setLineItemTaxAction: CartSetLineItemTaxAmountAction = {
action: "setLineItemTaxAmount",
lineItemId: item.lineItemId,
externalTaxAmount: {
totalGross: item.totalGross,
taxRate: item.taxRate,
},
};
updateActions.push(setLineItemTaxAction);
}
/*
// Example of executing the request with the Composable Commerce SDK client
const updatedCart = await apiRoot
.inStore({ storeKey })
.carts()
.withId({ ID: cartId })
.post({
body: {
version,
actions: updateActions,
},
})
.execute();
return updatedCart.body;
*/
// For demonstration purposes, we'll return a mock Cart.
// Replace this with the actual API call above.
}
async function runExample() {
// --- Cart & Tax Service Data (Example) ---
const cartId = "c7a3b1e0-f9d5-4a2c-8e1d-9b4c0f8a7b6d";
const cartVersion = 5;
const storeKey = "zen-electron-us";
// Imagine your external tax service returned the following calculations for a Cart
// with two Line Items.
// Item 1: T-Shirt ($25.00) -> Gross Price: $26.88 (with 7.5% tax)
// Item 2: Jeans ($70.00) -> Gross Price: $75.25 (with 7.5% tax)
// Total Gross: $26.88 + $75.25 = $102.13
// Total gross price for the entire Cart
const cartTotalGross: Money = {
currencyCode: "USD",
centAmount: 10213, // $102.13
};
// Tax details for each Line Item
const lineItemsToTax: LineItemTaxDetails[] = [
{
lineItemId: "6f9f5a83-808c-49f9-a3ef-5e32cd377042",
totalGross: {
currencyCode: "USD",
centAmount: 2688, // $26.88
},
taxRate: {
name: "CA Sales Tax",
amount: 0.075, // 7.5%
country: "US",
state: "CA", // It's good practice to include the state for US taxes
},
},
{
lineItemId: "7f9f5a83-808c-49f9-a3ef-5e32cd377042",
totalGross: {
currencyCode: "USD",
centAmount: 7525, // $75.25
},
taxRate: {
name: "CA Sales Tax",
amount: 0.075, // 7.5%
country: "US",
state: "CA",
},
},
];
// Call the updated function with all the necessary data
await setExternalTaxForCart(
storeKey,
cartId,
cartVersion,
cartTotalGross,
lineItemsToTax
);
}
runExample();