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 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. 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. // 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
storefield from theShoppingListDraftobject 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. // 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)
- Input Validation: Ensure
shoppingListDraftandstoreKeyare provided. - Build
ShoppingListDraft: Construct the draft object, omitting thestorefield but including eithercustomerIdoranonymousId. - Perform API Call (In-Store): Send a
POSTrequest using.inStoreKeyWithStoreKeyValue({ storeKey: storeKey })and the draft in the body. - Process Response: Parse the API response to get the created
ShoppingListobject. - Error Handling: Implement
try...catchto 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: {
"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"
}