Learn how to construct and create new Shopping Lists via the API, both for registered customers or anonymous users.
After completing this page, you should be able to:
- Determine appropriate scenarios for creating a new Shopping List, following best practices to avoid unnecessary list creation.
- Construct a
ShoppingListDraft
including essential fields (name
, user association viacustomerId
oranonymousId
, an initial item). - Distinguish between using the general and in-store API endpoints for creation and adjust the
ShoppingListDraft
accordingly (specifically regarding the inclusion or omission of thestore
field).
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.
Essential
ShoppingListDraft
Fields:name
(LocalizedString
): A user-friendly name for the list, supporting multiple languages.customerId
(String) ORanonymousId
(String): Crucial for associating the list with either a logged-in customer or an anonymous session. You must provide one, but not both.lineItems
(Array ofShoppingListLineItemDraft
) ORtextLineItems
(Array ofTextLineItemDraft
): You must provide at least one initial item (either a product or a text note) when creating the list.
Optional but Recommended
ShoppingListDraft
Fields:key
(String): Assign a unique, user-defined key for business purposes, allowing retrieval without the list ID.store
(StoreResourceIdentifier
): Associate the list with a specific store. Note: This is used for the general endpoint; it should be omitted when using the in-store endpoint.slug
(LocalizedString
): Define a human-readable, URL-friendly identifier for the list.description
(LocalizedString
): Provide a description for the list.deleteDaysAfterLastModification
(Number): Override the default period (if configured) after which the list is automatically deleted due to inactivity.custom
(CustomFieldsDraft
): Add custom fields for storing additional structured data specific to your project needs.businessUnit
(BusinessUnitResourceIdentifier
): Associate the list with a specific Business Unit.
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 (like 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
store
field from theShoppingListDraft
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. // 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
shoppingListDraft
andstoreKey
are provided. - Build
ShoppingListDraft
: Construct the draft object, omitting thestore
field but including eithercustomerId
oranonymousId
. - Perform API Call (In-Store): Send a
POST
request using.inStoreKeyWithStoreKeyValue({ storeKey: storeKey })
and the draft in the body. - Process Response: Parse the API response to get the created
ShoppingList
object. - 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: {
"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"
}