# Update Carts 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](/api/projects/carts.md#add-lineitem). ```typescript 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 { 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](/api/carts-orders-overview.md#merge-rules). For more information about how `inventoryMode` affects inventory updates after Order creation, see [Manage inventory with the Cart](/learning-model-your-product-catalog/inventory-modeling/cart-inventory.md). ### 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](/api/projects/carts.md#remove-lineitem). ```typescript /** * 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 { 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](/api/projects/carts.md#add-customlineitem). ```typescript 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 { 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](/api/projects/carts.md#set-shipping-address). ```typescript 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 { 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](/api/projects/shoppingLists.md) into purchasable Cart items in one step. For the full behavior, see [Add Shopping List](/api/projects/carts.md#add-shopping-list). ```typescript /** * 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 { 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](/api/carts-orders-overview.md#tax-modes). 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](/tutorials/tax-integration.md). **Step 1: Change the Tax Mode:** this is a prerequisite for all external tax actions. ```typescript 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. ```typescript 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 { // 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 commercetools 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(); ``` ## Related pages - [Area overview page with navigation](/learning-implement-carts-and-shopping-lists.md) - [Previous page: Create Carts](/learning-implement-carts-and-shopping-lists/implement-carts/create-carts.md) - [Next page: Manage Cart sessions and merges](/learning-implement-carts-and-shopping-lists/implement-carts/manage-cart-sessions-and-merges.md) - [Search documentation and API specs](/search.md)