Create Carts

Learn how to programmatically create a customer's first Cart within Composable Commerce.

After completing this page, you should be able to:

  • Determine the optimal trigger and required data for creating a new Cart within a user journey.
  • Write code using the SDK to efficiently create a new CartDraft that includes Line Items and shipping details in a single request.

As a best practice, a Cart should only be created when a user performs an action that requires one, such as adding their first item. Creating Carts for every visitor who lands on your site leads to unnecessary data and can impact performance.

Therefore, the standard workflow is:

  1. When a user tries to add an item, first check for an existing Active or Frozen Cart.
  2. If the query returns no results, proceed to create a new Cart. Alternatively, you can check for an existing Cart after login or at another stage prior to attempting to create a new Cart.

To provide practical examples, we'll use the scenario of Zen Electron, a company that operates two distinct brands from a single Project, using Stores for separation:

BrandStore KeyDescription
Electronics High Techelectronics-high-tech-storeA budget-friendly electronics retailer.
Zenith Livingzenith-living-storeA high-end home appliance brand focused on service.

This multi-store setup will inform how we construct our API requests.

The CartDraft: your Cart's blueprint

To create a new Cart, you must first construct a CartDraft object. This object serves as a template, defining the initial properties of the Cart. Properly configuring the CartDraft is essential for ensuring correct price selection, tax calculation, and user association.
FieldRequirementPurpose and usage
currencyMandatoryDefines the currency for all prices in the Cart (for example, USD, EUR). This is a primary factor in Price Selection.
customerId or anonymousIdMandatoryAssociates the Cart with a user. Use customerId for logged-in customers and anonymousId (a client-side generated UUID) for guest users.
countryRecommendedA two-letter country code (for example, US, DE). It influences price selection, tax calculation, and available shipping methods.
storeRecommended (if using Stores)A ResourceIdentifier to a Store. Associates the Cart with a specific Store, inheriting its product assortment, pricing, and other contextual settings.
lineItemsOptionalAn array of LineItemDraft objects to add products from your catalog to the Cart upon creation. You must provide a sku or a productId and variantId.
localeRecommendedA language tag (for example, en-US). Ensures that localized fields like product names (LineItem.name) are returned in the customer's preferred language in the API response.
customerGroupOptionalA ResourceIdentifier to a Customer Group. If the logged-in customer belongs to a Customer Group, then this value will be automatically set by the system. You may also set this Cart value for guests
shippingAddressOptionalThe initial shipping address for the Cart. Can be set later with an update action.
taxModeOptionalDefines how taxes are handled. Defaults to Platform. Set to External or ExternalAmount to integrate with an external tax service.
customOptionalExtends the Cart with custom business logic using a Custom Type (for example, to flag a Cart as a "gift order" or store an internal identifier).
keyOptionalA user-defined unique identifier. Useful for integrations with external systems that need a stable, human-readable key to reference the Cart. This field supports idempotency

Best practice: optimize Cart creation for performance

The CartDraft is designed to be comprehensive, allowing you to set multiple Cart properties in a single API request. For optimal performance, you should bundle as much information as possible into the initial creation call.
For instance, instead of creating an empty Cart and then making separate calls to add a Line Item and set the shipping address, include the lineItems and shippingAddress directly in the CartDraft. This approach reduces the number of API requests, leading to a faster and more efficient user experience.

Create a Cart with the SDK

The following functions demonstrate how to create a new Cart for anonymous and logged-in customers, including the first Line Item.

import { apiRoot } from "../ctp-root";
import {
  CartDraft,
  Cart,
  LineItemDraft,
} from "@Composable Commerce/platform-sdk";

/**
 * Creates a new Cart for an anonymous user within a specific Store, adding an initial Line Item.
 * @param storeKey The key of the Store the Cart should belong to.
 * @param anonymousId The anonymous ID to associate with the Cart.
 * @param currency The currency for the Cart (for example, "AUD", "NZD").
 * @param country The country for the Cart (for example, "AU", "NZ").
 * @param sku SKU of the product variant to add.
 * @param quantity Quantity of the product variant to add.
 * @returns A Promise resolving to the newly created Cart.
 */
async function createAnonymousCart(
  storeKey: string,
  anonymousId: string,
  currency: string,
  country: string,
  sku: string,
  quantity: number
): Promise<Cart> {
  const cartDraft: CartDraft = {
    currency,
    country,
    anonymousId, // Link the cart to the guest session
    lineItems: [
      { sku, quantity }, // Add the initial item
    ],
  };

  const { body } = await apiRoot
    .inStoreKeyWithStoreKeyValue({ storeKey }) // Use the Store-scoped endpoint
    .carts()
    .post({
      body: cartDraft,
    })
    .execute();

  return body;
}

/**
 * Creates a new Cart for a signed-in Customer within a specific Store, adding an initial Line Item.
 * @param storeKey The key of the Store the Cart should belong to.
 * @param customerId The ID of the customer to associate with the Cart.
 * @param currency The currency for the Cart.
 * @param country The country for the Cart.
 * @param sku SKU of the product variant to add.
 * @param quantity Quantity of the product variant to add.
 * @returns A Promise resolving to the newly created Cart.
 */
async function createCustomerCart(
  storeKey: string,
  customerId: string,
  currency: string,
  country: string,
  sku: string,
  quantity: number
): Promise<Cart> {
  const cartDraft: CartDraft = {
    currency,
    country,
    customerId, // Link the cart to the customer account
    lineItems: [{ sku, quantity }],
  };

  const { body } = await apiRoot
    .inStoreKeyWithStoreKeyValue({ storeKey })
    .carts()
    .post({
      body: cartDraft,
    })
    .execute();

  return body;
}
In these examples, the CartDraft includes the mandatory currency and country fields, which are critical for price selection. The Cart is linked to a customer using either their anonymousId or customerId, and the request is sent to the appropriate Store-scoped endpoint.
Handle pricing errors: if you attempt to create a Cart or add a Line Item where a price cannot be found for the given combination of currency, country, customerGroup, and channel, the API will return a 400 Bad Request error with the code MatchingPriceNotFound. Ensure your product data includes prices that match the contexts your customers will be shopping in.

Test your knowledge