# Find and manage existing Carts Before creating a new Cart, it is a crucial best practice to check if the customer (anonymous or logged-in) already has an active one. This prevents duplicate Carts, reduces data clutter, and allows customers to seamlessly resume their shopping session. Most commerce sites enforce a "one active Cart per customer" rule to simplify the user experience. ## Construct the optimal query To find the correct Cart efficiently, build a precise and performant query. For the full predicate syntax and field catalog, see [Query predicates on Carts](/api/predicates/query.md#on-carts). ### Step 1: Choose the right endpoint | Endpoint | When to use | | --- | --- | | Project-scoped: `/carts` | Use this when your application does not use Stores, or when you need to search across Store contexts, without knowing the exact Store the customer's Cart belongs to. You can optionally filter by store using a `where` [predicate](/api/predicates/query.md#on-carts). | | Store-scoped: `/in-store/key={storeKey}/carts` | Use this when the Store context is already known. This avoids an extra Store predicate and matches Store-restricted API Clients well. | **Recommendation**: when in doubt, start with the Project-scoped `/carts` endpoint. It provides the most flexibility. ### Step 2: Build the where predicate The `where` predicate is the most critical part of your query. For best performance, order the clauses from most to least selective. | Predicate component | Why it matters | | --- | --- | | `customerId=""` or `anonymousId=""` | Identifies the owner of the Cart. This is the primary and most selective filter. | | `cartState in ("Active", "Frozen")` | Restricts the result to Carts that are still relevant to the shopping session. It excludes no longer modifiable Carts (`Ordered`, `Merged`). | | `store(key="")` | Adds Store isolation only when you query the `/carts` endpoint in a multi-Store setup. | The following is an example `where` predicate: `where=customerId="c123-..." AND cartState in ("Active", "Frozen") AND store(key="zen-electron-us")` ### Step 3: Add performance and consistency parameters Use only the query parameters that support your retrieval rule and improve performance. | Parameter | Recommended value | Purpose | | --- | --- | --- | | `sort` | `lastModifiedAt desc` | Makes the selection deterministic when more than one active Cart exists. By combining it with `limit=1`, you are guaranteed to retrieve the most recently updated customer Cart. | | `limit` | `1` | Enforces the common "one active Cart per customer" rule and stops the query after finding the first match, improving thus performance. | | `withTotal` | `false` | Skips unnecessary total-count calculation when you only need the top result. This can significantly speed up the API response and improve performance. | **Working with large or complex Carts?** The query optimization strategies above work well for typical Cart operations. However, if you're building B2B solutions or handling Carts with hundreds of Line Items, extensive Custom Fields, or complex discount rules, consult the [Large Cart performance tips](/api/large-cart-performance-tips.md) guide for advanced data modeling and API usage strategies. ## Complete API request example **Scenario**: find the most recently modified active or frozen Cart for a logged-in customer in the `zen-electron-us` Store: ``` GET /carts?limit=1&withTotal=false&sort=lastModifiedAt desc&where=customerId="c123-..." AND cartState in ("Active", "Frozen") AND store(key="zen-electron-us") ``` Handling the response: - If a Cart is found: the API will return a `results` array with one Cart object. Your application should use this Cart. - If no Cart is found: the API will return an empty `results` array. Your application should proceed to create a new Cart when the user adds their first item. ### Implementation with the SDK Here is how you can implement this optimal query strategy using the TypeScript SDK. For an anonymous user: ```typescript import { apiRoot } from "../../client"; import { Cart } from "@commercetools/platform-sdk"; async function getActiveAnonymousCart( storeKey: string, anonymousId: string ): Promise { try { const { body } = await apiRoot .inStoreKeyWithStoreKeyValue({ storeKey }) .carts() .get({ queryArgs: { limit: 1, withTotal: false, sort: "lastModifiedAt desc", where: [`anonymousId="${anonymousId}"`, `cartState="Active"`], }, }) .execute(); return body.results[0]; // Returns the cart or undefined if not found } catch (error) { console.error("Error fetching anonymous cart:", error); throw error; // Rethrow or handle appropriately } } ``` For a logged-in customer: ```typescript import { apiRoot } from "../../client"; import { Cart } from "@commercetools/platform-sdk"; async function getActiveCustomerCart( storeKey: string, customerId: string ): Promise { try { const { body } = await apiRoot .inStoreKeyWithStoreKeyValue({ storeKey }) .carts() .get({ queryArgs: { limit: 1, withTotal: false, sort: "lastModifiedAt desc", where: [`customerId="${customerId}"`, `cartState="Active"`], }, }) .execute(); return body.results[0]; // Returns the cart or undefined if not found } catch (error) { console.error("Error fetching customer cart:", error); throw error; // Rethrow or handle appropriately } } ``` ## How to enforce a single active Cart The primary way to enforce this is through your application logic. By always performing the optimal query described above (`limit=1`) before creating a new Cart, you ensure that you always reuse an existing active Cart if one is found. ## How to handle multiple Carts While a single active Cart is the most common pattern, some business models might require multiple active Carts per user (for example, a B2B "projects" Cart and a "personal" Cart). If your business logic allows multiple active Carts, modify your query strategy: 1. **Remove `limit=1`**: allow the query to return all active Carts. 2. **Use `sort`**: ensure results are consistently ordered (for example, `lastModifiedAt desc`). 3. **Implement selection logic**: your application must provide a way for the user to view and select which Cart they want to interact with. ```typescript title="Example of getting all active Carts for a customer" async function getAllActiveCustomerCarts( storeKey: string, customerId: string ): Promise { try { const { body } = await apiRoot .inStoreKeyWithStoreKeyValue({ storeKey }) .carts() .get({ queryArgs: { sort: "lastModifiedAt desc", where: [`customerId="${customerId}"`, `cartState="Active"`], }, }) .execute(); return body.results; // Returns an array of all active carts } catch (error) { console.error("Error fetching all customer carts:", error); return []; } } ``` ### Use Custom Fields to differentiate Carts In a multi-Cart scenario, consider [Custom Fields](/api/projects/custom-fields.md) to categorize Carts. In some B2B cases you might allow the customer to give each Cart a unique name, so that they can easily identify what each Cart is for. 1. **Define a Custom Type**: create a Custom Type for Carts (for example, `cart-attributes`) with a field like `cartType` (of type `Enum` or `String`). 2. **Set the Custom Field value on creation**: when creating a Cart, populate the Custom Field. ```typescript title="Example of creating a Cart with a Custom Type" const cartDraft: CartDraft = { customerId: customerId, currency: "USD", country: "US", custom: { type: { key: "cart-attributes", typeId: "type" }, fields: { cartType: "B2B-Project-A", }, }, }; // ... post the cartDraft ``` 3. **Query by Custom Field**: add the custom field to your `where` predicate to find specific types of Carts. ```typescript title="Example of querying for a specific Cart type" const where = [ `customerId="${customerId}"`, `cartState="Active"`, `custom(fields(cartType="B2B-Project-A"))`, ]; ``` ## Related pages - [Area overview page with navigation](/learning-implement-carts-and-shopping-lists.md) - [Previous page: Understand the Carts API](/learning-implement-carts-and-shopping-lists/implement-carts/understand-the-carts-api.md) - [Next page: Create Carts](/learning-implement-carts-and-shopping-lists/implement-carts/create-carts.md) - [Search documentation and API specs](/search.md)