# Create Shopping Lists Create a new Shopping List only in response to a meaningful user action, rather than preemptively. Recommended scenarios: - When a user adds their first item to a new wishlist or shopping list. - When a user explicitly requests to create a new list (for example, setting up a new gift registry). It's crucial to avoid unnecessary Shopping List creation to prevent database clutter and potential performance issues. Best practice dictates checking if a suitable list already exists for the user before creating a new one. If no suitable list exists, you create one using a `ShoppingListDraft` object. ## The ShoppingListDraft object This object contains all the initial information required for the new Shopping List. Start with a small `ShoppingListDraft`: provide a `name`, then add fields such as `customer` or `anonymousId` (not both), `lineItems`, or `textLineItems` only when your use case depends on them. You must provide at least one initial item when creating the list. Add fields such as `key`, `store`, `slug`, `description`, `deleteDaysAfterLastModification`, `custom`, or `businessUnit` only when needed. When you use the in-store endpoint, omit the `store` field from the draft because the endpoint already supplies that context. Refer to the [ShoppingListDraft Documentation](/api/projects/shoppingLists.md#shoppinglistdraft) for the complete list of fields and details. ### TypeScript example: Building the ShoppingListDraft This example demonstrates constructing a `ShoppingListDraft` for a logged-in customer, including various optional fields. ```typescript import { ShoppingListDraft, LocalizedString, StoreResourceIdentifier, // Corrected import assumption ShoppingListLineItemDraft, TextLineItemDraft, CustomFieldsDraft, TypeResourceIdentifier, CustomerResourceIdentifier, } from '@commercetools/platform-sdk'; // Assuming imports are handled correctly /** * Draft object containing the data for the new shopping list. * @type {ShoppingListDraft} */ const shoppingListDraft: ShoppingListDraft = { /** * The name of the shopping list (required). * Provide translations for different locales as needed. * @type {LocalizedString} */ name: { 'en': "My 100th Birthday Wishlist", }, /** * Optional: A user-defined unique key for this shopping list. * Useful for retrieving the list later without knowing its ID. * @type {string | undefined} */ key: 'birthday-wishlist-2025-john-doe', /** * Link this shopping list to a specific customer (required if no anonymousId). * Use either 'id' or 'key' to identify the customer. * Cannot be used simultaneously with 'anonymousId'. * @type {CustomerResourceIdentifier | undefined} */ customer: { typeId: 'customer', id: 'eaf18adc-c61e-4f2c-9d04-b6b8ad51d998', // Replace with actual customer ID }, /** * Optional: Link this shopping list to a specific store (used for general endpoint). * Use either 'id' or 'key' to identify the store. * Omit this field when using the in-store creation endpoint. * @type {StoreResourceIdentifier | undefined} */ store: { typeId: 'store', key: 'dach', // <-- Replace with actual Store Key }, /** * Optional: A description for the shopping list. * @type {LocalizedString | undefined} */ description: { 'en': 'Things I would love to receive for my birthday!', }, /** * Optional: Add initial product line items (required if no textLineItems). * Identify products by 'productId' or 'sku'. * @type {ShoppingListLineItemDraft[] | undefined} */ lineItems: [ { productId: 'cc93fbab-d329-4000-93a0-cf6757ff89ea', // Replace with actual Product ID quantity: 1, variantId: 1, // Specify product variant }, { sku: 'M0E20000000EG1V', // Replace with actual SKU quantity: 2, }, ], /** * Optional: Add initial text line items, such as notes (required if no lineItems). * @type {TextLineItemDraft[] | undefined} */ textLineItems: [ { name: { 'en': 'Gift wrapping needed for item 1' }, quantity: 1, // description: { 'en': 'Use the blue wrapping paper.' }, // Optional description }, ], /** * Optional: If this list is for an anonymous user instead of a logged-in customer. * Provide this *instead* of the 'customer' field. * Cannot be used simultaneously with 'customer'. * @type {string | undefined} */ // anonymousId: "replace-with-anonymous-session-id", // <-- Use this OR customer, not both /** * Optional: Set days until auto-deletion after last modification. * @type {number | undefined} */ // deleteDaysAfterLastModification: 30, /** * Optional: Add Custom Fields if configured for ShoppingLists. * @type {CustomFieldsDraft | undefined} */ // custom: { // type: { // typeId: "type", // key: "my-shopping-list-custom-type-key" // <-- Replace with your custom type key // }, // fields: { // myCustomTextField: "Custom value example", // <-- Replace with your field names/values // myCustomBooleanField: true // } // } }; ``` ## Creating the Shopping List via API You can create the Shopping List using either the general API endpoint or a store-specific endpoint. ### TypeScript example: Creating the Shopping List via general endpoint Use this method when you're not using a store-specific context, or when explicitly setting the `store` field in the draft. ```typescript // Assuming 'apiRoot' is your configured API client instance // Assuming 'shoppingListDraft' holds the draft object from the previous step apiRoot .shoppingLists() .post({ /** * The data for the new shopping list. * @type {ShoppingListDraft} */ body: shoppingListDraft, }) .execute() .then((response) => { // On success, the response body contains the newly created ShoppingList object console.log('Successfully created shopping list:'); console.log(JSON.stringify(response.body, null, 2)); // Pretty print the result }) .catch((error) => { // Handle potential errors (for example, validation errors, duplicate key) console.error('Error creating shopping list:'); // The error object often contains detailed information in error.body.errors console.error(JSON.stringify(error, null, 2)); }); ``` ### TypeScript example: Creating via in-store endpoint Using the `/in-store/key={storeKey}/shopping-lists` endpoint automatically associates the list with the specified store. - **Modification**: Remove the `store` field from the `ShoppingListDraft` object itself, as the store context is provided in the endpoint path. - **API Call**: Use the `.inStoreKeyWithStoreKeyValue()` method in your SDK call. First, ensure the `store` field is not present in your `shoppingListDraft` if you intend to use this endpoint. ```typescript // Remove or comment out the 'store' field in your shoppingListDraft: /* store: { typeId: 'store', key: 'dach', }, */ // Assuming 'apiRoot' is your configured API client instance // Assuming 'shoppingListDraft' holds the draft object (without the 'store' field) const storeKey = 'dach'; // Replace with the actual Store Key apiRoot .inStoreKeyWithStoreKeyValue({ storeKey: storeKey }) // Specify the store context here .shoppingLists() .post({ /** * The data for the new shopping list (without the 'store' field). * @type {ShoppingListDraft} */ body: shoppingListDraft, }) .execute() .then((response) => { console.log( `Successfully created shopping list in store '${storeKey}':`, ); // The response body contains the created ShoppingList, now associated with the store. console.log(JSON.stringify(response.body, null, 2)); }) .catch((error) => { console.error( `Error creating shopping list in store '${storeKey}':`, ); console.error(JSON.stringify(error, null, 2)); }); ``` ### Main steps for creation (using in-store endpoint) 1. **Input Validation**: Ensure `shoppingListDraft` and `storeKey` are provided. 2. **Build `ShoppingListDraft`**: Construct the draft object, omitting the `store` field but including either `customerId` or `anonymousId`. 3. **Perform API Call (In-Store)**: Send a `POST` request using `.inStoreKeyWithStoreKeyValue({ storeKey: storeKey })` and the draft in the body. 4. **Process Response**: Parse the API response to get the created `ShoppingList` object. 5. **Error Handling**: Implement `try...catch` to manage potential API errors. ### Creating a Shopping List for an anonymous user When a user is not logged in, you can still create a Shopping List for them by providing an `anonymousId` instead of a `customerId` in the `ShoppingListDraft`. The `anonymousId` should be a unique identifier for the user's session (for example, generated using a UUID library and potentially stored in local storage or a cookie). The creation process using the API (either general or in-store endpoint) remains the same as shown above; just ensure the `shoppingListDraft` contains the `anonymousId` field and not the `customer` field. ### Example response: Created Shopping List (JSON) Upon successful creation, the API returns the complete `ShoppingList` object. Here's an example structure: ```json { "id": "generated-shopping-list-id", "version": 1, "name": { "en": "My 100th Birthday Wishlist" }, "customer": { // Or "anonymousId": "session-id" if created anonymously "typeId": "customer", "id": "eaf18adc-c61e-4f2c-9d04-b6b8ad51d998" }, "store": { // Present if created via general endpoint with store, or via in-store endpoint "typeId": "store", "key": "dach" }, "key": "birthday-wishlist-2025-john-doe", "slug": { /* ... */ }, "description": { "en": "Things I would love to receive for my birthday!" }, "lineItems": [ { "id": "generated-line-item-id-1", "productId": "cc93fbab-d329-4000-93a0-cf6757ff89ea", "name": { "en": "Product Name A" }, "variantId": 1, "quantity": 1, "addedAt": "2025-05-01T10:35:58.000Z", "productType": { "typeId": "product-type", "id": "..." }, "variant": { /* ... variant details ... */ } // ... other line item fields }, { "id": "generated-line-item-id-2", "productId": "...", // Inferred from SKU during creation "name": { "en": "Product Name B" }, "productSlug": { "en": "product-name-b" }, "variantId": 1, // Inferred from SKU during creation "quantity": 2, "addedAt": "2025-05-01T10:35:58.000Z", "productType": { "typeId": "product-type", "id": "..." }, "variant": { "id": 1, "sku": "M0E20000000EG1V", /* ... */ } // ... other line item fields } ], "textLineItems": [ { "id": "generated-text-line-item-id", "name": { "en": "Gift wrapping needed for item 1" }, "quantity": 1, "addedAt": "2025-05-01T10:35:58.000Z" // ... other text line item fields } ], "deleteDaysAfterLastModification": null, // Or the number set "custom": null, // Or custom fields object "createdAt": "2025-05-01T10:35:58.123Z", "lastModifiedAt": "2025-05-01T10:35:58.123Z" } ``` ## Related pages - [Area overview page with navigation](/learning-implement-carts-and-shopping-lists.md) - [Previous page: Find and manage existing Shopping Lists](/learning-implement-carts-and-shopping-lists/implement-shopping-lists/find-and-manage-existing-shopping-lists.md) - [Next page: Update Shopping Lists](/learning-implement-carts-and-shopping-lists/implement-shopping-lists/update-shopping-lists.md) - [Search documentation and API specs](/search.md)