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:
- When a user tries to add an item, first check for an existing
Active
orFrozen
Cart. - 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:
Brand | Store Key | Description |
---|---|---|
Electronics High Tech | electronics-high-tech-store | A budget-friendly electronics retailer. |
Zenith Living | zenith-living-store | A 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
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.Field | Requirement | Purpose and usage |
---|---|---|
currency | Mandatory | Defines the currency for all prices in the Cart (for example, USD , EUR ). This is a primary factor in Price Selection. |
customerId or anonymousId | Mandatory | Associates the Cart with a user. Use customerId for logged-in customers and anonymousId (a client-side generated UUID) for guest users. |
country | Recommended | A two-letter country code (for example, US , DE ). It influences price selection, tax calculation, and available shipping methods. |
store | Recommended (if using Stores) | A ResourceIdentifier to a Store. Associates the Cart with a specific Store, inheriting its product assortment, pricing, and other contextual settings. |
lineItems | Optional | An 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 . |
locale | Recommended | A 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. |
customerGroup | Optional | A 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 |
shippingAddress | Optional | The initial shipping address for the Cart. Can be set later with an update action. |
taxMode | Optional | Defines how taxes are handled. Defaults to Platform . Set to External or ExternalAmount to integrate with an external tax service. |
custom | Optional | Extends 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). |
key | Optional | A 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
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.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;
}
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.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.