Import your products into SCAYLE
Introduction and preparation
- Product Data Management
- Tech
Robert Merten
VP Tech
Products are the central data structure for category listings and product detail pages.
Product is an entity defined by attribute values such as color. You can set the attributes groups and attribute values to suit your needs.
Product data can be configured and customized at different entity levels. The system differentiates between three entity levels: master, product, and variant.
The user can specify which product information correlates to which entity level. Prices are determined by the variant because that is the specific entity to be sold.
In general, product information relates to three different data types:
SCAYLE Panel users can customize all of these data types according to their needs.
In addition to product-specific information, SCAYLE stores the following information for each product and each variant:
Retrieving Product details is a primary use case in shop management. /products endpoint supports all the required use cases:
Learn how to create products displayed in the store with their respective variants, prices, images, and attributes.
let response = await adminApi.apis.Products.createProduct({}, {requestBody: newProduct});
let createdProduct = response.body;
During state evaluation, one of the problems you could encounter is system: mandatory attributes are missing
. In this case you should check that the payload provides attributes for all the attributes groups configured as mandatory.
The attribute groups referenced by the provided attributes must be created in advance.
When creating or updating a product that has attributes cross-mapped with the product master, the attributes will be synchronized on product master regardless of theignoreMasterIfExist
flag. See details about Product Attributes.
Product creation can be used with optional parameters - called options:
Parameter | Type | Details |
---|---|---|
ignoreMasterIfExist | boolean | Ignore master data from the request, if master exists. If set to When creating a new product ( |
updateIfExists | boolean | When set to true, a lookup is done for the product with the given reference key and if it exists then the product will be updated, otherwise the product will get created. |
ignoreAttributeLocks | boolean | Force an update of categories even if they might be locked |
ignoreCategoryLocks | boolean | Force an update of categories even if they might be locked. |
Use with
parameter to include following nested resources:
Providing the master as part of the product hierarchy is mandatory.
master.referenceKey
is provided, the product will inherit all attributes and categories of the existing master.When creating a new product you can specify if you want to create the product as a draft
, meaning it will not be available in the storefront, or live
to publish it. You can change the state later using the Update Product State Method.
Setting the state to live
will trigger the state evaluation. The product might end up in the problem
state and not go live
.
If there is more than one merchant in the system, you might want to define merchants that sell the product. This can be done by listing merchant reference keys in the merchantReferenceKeys
field.
Prices and stocks provided along with the product information can be also merchant-specific. The relation to a merchant is established via the merchantReferenceKey
field, which must be within the range of merchants defined for the product.
If you send stocks and prices by specifying a merchantReferenceKey
for which no product variant exists, you will receive the error message MERCHANT_REFERENCE_KEY_OUT_OF_RANGE
.
It is possible to specify a set of attributes, which will be either linked to the product if they already exist or created and subsequently linked to the product. The attribute's name
must refer to an attribute group of the product
level. If you want to get more detailed information, please use the Product Attributes Section.
Attributes of new
and category
attribute groups will not be handled, as they are created/updated by internal processes only. This is applicable for both product and product master attributes.
It is possible to specify a set of product variants, which will be either linked to the product if they already exist or created and subsequently linked to the product. If you want to get more detailed information, please use the Variants Section.
It is possible to specify a set of product images, either by providing a source
from which the resource can be downloaded or a CDN URL.
let newProduct = {
referenceKey: "myReferenceKey",
master: {
referenceKey: "myMasterReferenceKey",
categories: {
paths: [
[
"Fashion",
"Women",
"Shirts"
]
]
}
},
name: {
de_DE: "Mein Produkt",
en_GB: "My Product"
},
state: "draft"
};
let response = await adminApi.apis.Products.createProduct({}, {requestBody: newProduct});
let createdProduct = response.body;
Create a product with variant, image and merchant data.
let newProduct = {
referenceKey: "myReferenceKey",
name: {
"de_DE": "Mein Produkt",
"en_GB": "My Product"
},
state: "live",
master: {
referenceKey: "myMasterReferenceKey",
categories: {
paths: [
[
"Fashion",
"Women",
"Shirts"
]
]
}
},
attributes: [
{
name: "color",
type: "localizedStringList",
value: [
{
de_DE: "rot",
en_GB: "red"
},
{
de_DE: "blau",
en_GB: "blue"
}
]
}
],
variants: [
{
referenceKey: "myVariantKey",
attributes: [
{
name: "size",
type: "simple",
value: "M"
}
],
prices: [
{
price: 2499,
tax: 19,
currencyCode: "EUR",
countryCode: "DE",
}
],
stocks: [
{
quantity: 17,
warehouseReferenceKey: "default",
changedAt: "2024-01-23T12:34:56Z",
sellableWithoutStock: false,
merchantReferenceKey: "merchant-1"
}
]
},
{
referenceKey: "mySecondVariantKey",
attributes: [
{
name: "size",
type: "simple",
value: "S"
}
],
prices: [
{
price: 2499,
tax: 19,
currencyCode: "EUR",
countryCode: "DE",
}
],
stocks: [
{
quantity: 10,
warehouseReferenceKey: "default",
changedAt: "2024-01-23T12:34:56Z",
sellableWithoutStock: false,
merchantReferenceKey: "merchant-1"
}
]
}
],
images: [
{
source: {
url: "https://example.com/image.jpg"
}
}
],
customData: {
"additionalDetails": "details"
},
merchantReferenceKeys: ["merchant-1", "merchant-2"]
};
let response = await adminApi.apis.Products.createProduct({}, {requestBody: newProduct});
let createdProduct = response.body;
When you retrieve a product, you can add additional parameters. Unless specified, the response will include defaults.
This method can be used to get an existing product either by using SCAYLE's internal product ID or the user defined reference key.
This method allows including nested resources using the with
parameter.
let response = await adminApi.apis.Products.getProduct({productIdentifier: productIdentifier});
let product = response.body;
This method can be used to get a collection of existing products. It is possible to refine the search by applying filters in the options.
let response = await adminApi.apis.Products.getProducts();
let products = response.body.entities;
Parameter | Details |
---|---|
filters[id] | Int[] Comma-separated list of IDs of entities that should be used for filtering. |
filters[minId] | Integer Minimum (inclusive) ID of entities that should be returned. |
filters[maxId] | String Maximum (inclusive) ID of entities that should be returned. |
filters[minCreatedAt] | String Minimum (inclusive) creation date of entities that should be returned. |
filters[maxCreatedAt] | String Maximum (inclusive) creation date of entities that should be returned. |
filters[minUpdatedAt] | String Minimum (inclusive) modification date of entities that should be returned. |
filters[maxUpdatedAt] | String Maximum (inclusive) modification date of entities that should be returned. |
filters[variantId] | Int[] Comma-separated list of variant IDs that should be used for filtering. |
filters[variantReferenceKey] | String[] Comma-separated list of product variant reference keys that should be used for filtering. |
filters[variantEan] | String[] Comma-separated list of variant EANs that should be used for filtering. |
filters[attributes] | Object The filter logic will combine all attributes of the same group into an |
filters[masterReferenceKey] | String[] Comma-separated list of master reference keys that should be used for filtering. |
filters[isComposite] | Boolean Pass true to get only composite products, pass false to get the non-composite products. |
Product read can be used with optional parameters - called options
Use with
parameter to load nested resources
Parameter | Type | Details |
---|---|---|
id | Integer | The ID of the product created by SCAYLE. |
problems | String[] | If product is in problem state, the reasons are listed here. |
referenceKey | String | A key that uniquely identifies the product (e.g., a shirt in a specific color) within the tenant's ecosystem. |
name | Object | The localized product name. At least the base language that is configured in SCAYLE is mandatory. |
master | Master | The master entity the product is attached to. |
state | string | The state of the product is determined by the state evaluation process. The only possible values to request are live , draft and blocked . The problem state can only be the result of the state evaluation process. If product is in problem state, the reasons are listed in read-only 'problems' field. The new and inApproval states can be set in the SCAYLE Panel. If a product belongs to multiple merchants, the state is returned based on the hierarchical order live, inApproval, problem, blocked, draft |
attributes | Attribute[] | A list of attributes attached to the product. |
variants | ProductVariant[] | A list of product variants attached to the product. |
images | ProductImage[] | A list of product images attached to the product. |
productSortings | ProductSorting[] | A list of product sortings. |
isComposite | Boolean | Indicates whether the product is composite. |
merchantReferenceKeys | String | A list of merchant reference keys the product belongs to. |
Get a list of ten products with a color filter for green and red:
let response = await adminApi.apis.Products.getProducts({
"limit": 10,
"filters[attributes]": {color: "green,red"},
"filters[variantEan]": "01010101,01010102"
});
let products = response.body.entities;
products.forEach(
product => console.log(product.referenceKey)
);
The referenceKey
uses the format key%3Dmy-key
(i.e., encoding %3D
for =
).
let response = await adminApi.apis.Products.getProduct({productIdentifier: "key=my-key"});
let product = response.body;
console.log(product.name.en_GB);
let response = await adminApi.apis.Products.getProduct({productIdentifier: 1, with: "variants"});
let product = response.body;
product.variants.forEach(
variant => console.log(variant.referenceKey)
);
let response = await adminApi.apis.Products.getProduct({productIdentifier: 1, with: "customData"});
let product = response.body;
console.log(product.customData)
let response = await adminApi.apis.Products.getProduct({productIdentifier: 1, with: "variants.attributes"});
let product = response.body;
product.variants.forEach(variant => {
for (let i = 0; i < variant.attributes.length; i++) {
let attribute = variant.attributes[i];
if (attribute.type === "simple") {
console.log(attribute.name + ': ' + attribute.value)
}
}
});
let response = await adminApi.apis.Products.getProduct({productIdentifier: 1, with: "productSortings"});
let product = response.body;
product.productSortings.forEach(
productSorting => console.log(productSorting.sortValue)
);
Update or replace an existing product. Consider nested entities and locked attributes and categories.
This method does not support partial updates.
Changing attributes might cause the product to be taken offline.
let response = await adminApi.apis.Products.updateProduct({productIdentifier: productIdentifier}, {requestBody: product});
let updatedProduct = response.body;
For efficiency use a dedicated endpoint to upload images.
If there exists a custom data configuration for the product
entity and the custom data isn't provided within the create request, the defaultValue
specified in the custom data configuration for each property would be considered.
When a product being updated has attributes cross mapped with the product master, they will be synchronized on product master regardless of ignoreMasterIfExist
flag. See details about Product Attributes.
Parameter | Type | Details |
---|---|---|
ignoreMasterIfExist | Boolean | Ignore master data from the request, if master exists. When updating a product for an existing master, if master categories or attributes are provided and |
ignoreAttributeLocks | Boolean | Force an update of categories even if they might be locked. |
ignoreCategoryLocks | Boolean | Force an update of categories even if they might be locked. |
with | String | The parameter allows you to include the following nested resources in the response:
|
Not provided properties will get deleted except nested entities as stated below.
variants
is not provided, it will NOT get deleted.variants
is provided, it will be replaced by the provided information.variants
is provided and set to null or empty, it will get deleted.To avoid accidentally deleting or updating attributes that were manually added or edited via the SCAYLE Panel, the query parameter ignoreAttributeLocks
can be used to control the behavior of how these updates should be handled.
The default behavior is to respect attribute locks. Thus, even if an attribute is present in the payload, it will not be updated. The same behavior will be applied, if an attribute is omitted in the payload, so it will not get deleted.
If you want to force updates or deletion of attributes, you need to set ignoreAttributeLocks
= true. In this case, all attributes get updated or deleted even if they are locked.
Master attributes and categories are shared between products.
All future and active prices that are not provided in the request will be invalidated.
Master Categories and Locks
To avoid accidentally updating master categories that were manually changed via the SCAYLE Panel, the query parameter ignoreCategoryLocks
can be used to control the behaviour of how these updates should be handled.
The default behaviour is to respect category locks. This will prevent category updates.
If you want to force updates of categories, you need to set ignoreCategoryLocks
= true. In this case, all categories for all products of the same master get updated even if they are locked.
Updating the product will trigger the state evaluation. When the desired state is live
, the product might end up in the problem
state. Note, that it is not possible to change live
state to draft
.
If there is more than one merchant in the system, you might want to define merchants that sell the product. This can be done by listing merchant reference keys in the merchantReferenceKeys
field.
Prices and stocks provided along with the product information can be also merchant-specific. The relation to a merchant is established via the merchantReferenceKey
field, which must be within the range of merchants defined for the product.
When a product is updated with less merchant reference keys than it was initially created, prices and stocks for non-listed merchants will be removed from the system.
If you send stocks and prices by specifying a merchantReferenceKey
for which no product variant exists, you will receive the error message MERCHANT_REFERENCE_KEY_OUT_OF_RANGE
.
It is possible to specify a set of attributes, which will be either linked to the product if they already exist or created and subsequently linked to the product. The attribute's name
must refer to an attribute group of the product
level.
Parameter | Details |
---|---|
id | Integer READ-ONLY The ID of the product created by SCAYLE. |
problems | String READ-ONLY If product is in problem state, the reasons are listed here. |
referenceKey | String A key that uniquely identifies the product (e.g., a shirt in a specific color) within the tenant's ecosystem. |
name | String The localized product name. At least the base language that is configured in SCAYLE is mandatory. |
master | Master The master the product is attached to. |
state | String The state of the product is determined by the state evaluation process. The only possible values to request are |
attributes | Attribute A list of attributes attached to the product. |
variants | ProductVariant A list of product variants attached to the product. |
images | ProductImage A list of product images attached to the product. |
productSortings | ProductSorting A list of product sortings. |
customData | CustomData |
isComposite | Boolean READ-ONLY Indicates whether the product is composite. |
merchantReferenceKeys | String A list of merchant reference keys the product belongs to. |
let response = await adminApi.apis.Products.getProduct({productIdentifier: 1});
let product = response.body;
product.name = {
en_GB: "My new name",
de_DE: "Mein neuer Name"
};
adminApi.apis.Products.updateProduct({productIdentifier: product.id}, {requestBody: product});
Update or create the time when products go live for the first time in a shop country.
let response = await adminApi.apis.Products.updateProductsFirstLiveAt({}, {requestBody: productsFirstLiveAt});
let productsFirstLiveAt = response.body;
Updating the product state will trigger the state evaluation. When the desired state is live
, the product might end up in the problem
state.
Not all state transitions are allowed!
Parameter | Details |
---|---|
state | String The state of the product determined by the state evaluation process. The only possible values to request are |
merchantReferenceKeys | String A list of merchant reference keys the merchant product belongs to. |
merchantProductStates | MerchantProductState READ-ONLY A list of merchant keys to which the merchant product belongs to and the state of the merchant product. |
let response = await adminApi.apis.Products.updateProductState({productIdentifier: productIdentifier}, {requestBody: productState});
let productState = response.body;
let newProductState = {
state: "live",
merchantReferenceKeys: ["merchant-1", "merchant-2"]
};
let response = await adminApi.apis.Products.updateProductState({productIdentifier: 1}, {requestBody: newProductState});
let updatedProductState = response.body;
Deleting a product will remove it completely from SCAYLE and cannot be undone!
Delete an existing product along with all its dependencies.
adminApi.apis.Products.deleteProduct({productIdentifier: productIdentifier});
adminApi.apis.Products.deleteProduct({productIdentifier: 1});
adminApi.apis.Products.deleteProduct({productIdentifier: "key=my-key"});
Product attributes can be used to enhance product data displayed in a shop, for example, product material, color and more.
Attributes can be either shop-country-specific or global. When an attribute is shop-country-specific, it means that an attribute value will be applied for the specified shop country. This makes it easy to customize attributes in relation to a specific shop country while still maintaining a sensible default value for all other shop countries using the same attribute.
To avoid accidentally deleting or updating attributes that were manually added or edited via the SCAYLE Panel, the query parameter ignoreAttributeLocks
can be used to control the behaviour of how these updates should be handled.
The default behaviour is to respect attribute locks. Thus, even if an attribute is present in the payload, it will not be updated. The same behaviour will be applied, if an attribute is omitted in the payload, so it will not get deleted.
If you want to force updates or deletion of attributes, you need to set ignoreAttributeLocks
= true. In this case, all attributes get updated or deleted even if they are locked.
All data modifying operations will trigger the status evaluation of the related product.
If you encounter any missing advanced attribute on one of the entities, please refer to the respective endpoint fetching a single attribute. For product attributes this will be the endpoint GetProductAttribute. This endpoint will provide you with information why the advanced attribute is missing, i.e. it will return an error message with the reason.
In SCAYLE, you can create a product attribute and override its value for a specific shop.
This method is utilized for the creation of a product attribute. It either creates a new attribute if it doesn't exist and attach it to the product, or attach an existing attribute to the product.
If shop-country-specific values are not provided, then the existing shop country overrides will not be modified. Otherwise, shop country overrides will be replaced with the provided values. In case you wish to remove shop country specific values for a certain attribute, you have to explicitly set shopCountrySpecific
to an empty Array
(PHP & JavaScript) ArrayList
(Java) (see update locked attributes example).
Attributes of system attribute group new
may not be created or updated.
let response = await admminApi.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: productIdentifier},
{requestBody: productAttribute}
);
let createdProductAttribute = response.body;
Product attributes write operations can be used with optional parameters - called options:
Parameter | Details |
---|---|
ignoreAttributeLocks | Boolean Force an update of attributes even if they are locked. |
Updating or creating a product attribute will trigger the status evaluation. The product might end up in the problem
status.
Parameter | Details |
---|---|
name | String The attribute name. |
type | String The attribute type. |
value | Array The attribute value where the datatype is defined by the type property. |
isLocked | Boolean READ-ONLY Specifies if the attribute was locked via SCAYLE Panel. |
shopCountrySpecific | AttributeShopCountrySpecific Used to override the attribute value for a specific shop country. Only supported by products, product masters and variants. |
Create a simple product attribute:
let attribute = {
"name": "size",
"type": "simple",
"value": "M"
};
let response = await adminApi.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: attribute}
);
let createdAttribute = response.body;
Create a simple list product attribute:
let attribute = {
"name": "season",
"type": "simpleList",
"value": ["autumn", "winter"]
};
let response = await adminApi.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: attribute}
);
let createdAttribute = response.body;
Create a localized product attribute:
let attribute = {
"name": "collection",
"type": "localizedString",
"value": {"de_DE": "einzigartig", "en_GB": "unique"}
};
let response = await adminApi.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: attribute}
);
let createdAttribute = response.body;
Create a localized list product attribute:
let attribute = {
"name": "color",
"type": "localizedStringList",
"value": [
{"de_DE": "weiß", "en_GB": "white"},
{"de_DE": "schwarz", "en_GB": "black"}
]
};
let response = await adminApi.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: attribute}
);
let createdAttribute = response.body;
Create an advanced product attribute:
let attribute = {
"name": "dimensions",
"type": "advanced",
"value": {
"height": 100,
"width": 30,
"unit": "cm"
}
};
let response = await adminApi.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: attribute}
);
let createdAttribute = response.body;
Create an advanced list product attribute:
let attribute = {
"name": "material",
"type": "advancedList",
"value": [
{
"name": "wool",
"percentage": 80
},
{
"name": "cotton",
"percentage": 20
}
]
};
let response = await adminApi.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: attribute}
);
let createdAttribute = response.body;
Update a simple attribute ignoring locks:
let productAttribute = {
"name": "material",
"type": "simple",
"value": "cotton"
};
let response = await adminApi.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1, ignoreAttributeLocks: true},
{requestBody: productAttribute}
);
let updatedProductAttribute = response.body;
Create or update simple product attributes; override attribute value for certain shop country
let shopCountrySpecificAttribute = {
"shopKey": "ms",
"countryCode": "de",
"value": "polyester"
};
let productAttribute = {
"name": "material",
"type": "simple",
"value": "cotton",
"shopCountrySpecific": [
shopCountrySpecificAttribute
]
};
let response = await adminApi.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: productAttribute}
);
let updatedProductAttribute = response.body;
Update locked simple product attributes and unassign existing product attributes with an empty array / ArrayList:
let productAttribute = {
"name": "material",
"type": "simple",
"value": "cotton",
"shopCountrySpecific": []
};
let response = await adminApi.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1, ignoreAttributeLocks: true},
{requestBody: productAttribute}
);
let updatedProductAttribute = response.body;
Learn how to retrieve a product attribute
In SCAYLE, you can request a product attribute of the given group.
let response = await adminApi.apis.Attributes.getProductAttribute({
productIdentifier: productIdentifier,
attributeGroupName: attributeGroupName
});
let productAttribute = response.body;
Parameter | Details |
---|---|
name | String The attribute name. |
type | String The attribute type. |
value | Array The attribute value where the datatype is defined by the type property. |
isLocked | Boolean READ-ONLY Specifies if the attribute was locked via SCAYLE Panel. |
shopCountrySpecific | AttributeShopCountrySpecific Used to override the attribute value for a specific shop country. Only supported by products, product masters and variants. |
let response = await adminApi.apis.Attributes.getProductAttribute({
productIdentifier: 1,
attributeGroupName: "material"
});
let productAttribute = response.body;
SCAYLE allows you to retrieve all attributes attached to a product.
let response = await adminApi.apis.Attributes.getProductAttributes({productIdentifier: 1});
let productAttributes = response.body.entities;
Product attributes are deleted along with the shop overrides.
Attributes of system attribute group new
may not be deleted.
adminApi.apis.Attributes.deleteProductAttribute({
productIdentifier: productIdentifier,
attributeGroupName: attributeGroupName
});
The operation can be used with optional parameters - called options
Parameter | Details |
---|---|
ignoreAttributeLocks | Boolean Force attributes deletion even if they are locked. |
Deleting a product attribute will trigger the status evaluation. The product might end up in the problem
status.
Parameter | Details |
---|---|
name | String The attribute name. |
type | String The attribute type. |
value | Array The attribute value where the datatype is defined by the type property. |
isLockedREAD-ONLY | Boolean Specifies if the attribute was locked via SCAYLE Panel. |
shopCountrySpecific | AttributeShopCountrySpecific Used to override the attribute value for a specific shop country. Only supported by products, product masters and variants. |
Import your products into SCAYLE
Robert Merten
VP Tech
Query a single product with more detailed information. For example, this method can be useful for querying a product on the product detail page.
You can request more detailed information via the optional with
parameter.
Parameter | Type | Details |
---|---|---|
productId | Integer | ID of the product. |
with | Object | Use to request the optional fields. Possible keys: variants , attributes , siblings . |
campaignKey | String | Use to get the correct prices for the specified campaign. |
We want to create a product detail page to show information about a T-shirt product with ID 1.
We'll use the getById
method. Besides basic fields we need to tell the API which attributes we would like to receive. Usually on a product detail page we want to receive the name, description, images, prices, colors and sizes. We get the product with these attributes as follows:
// Get product with id 1 and its attributes
const product = await client.products.getById(1, {
with: {
attributes: {
withKey: ["name", "description", "color"],
},
images: "all",
variants: {
attributes: {
withKey: ["size"],
},
},
},
});
console.log(product.attributes.name.values.label);
// => Hilfiger Shirt
{
"id": 1,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:33+00:00",
"updatedAt": "2023-06-12T14:05:34+00:00",
"indexedAt": "2023-09-12T18:43:39+00:00",
"firstLiveAt": "2023-06-12T14:05:33+00:00",
"masterKey": "THS090600",
"referenceKey": "THS0906008000001",
"attributes": {
"color": {
"id": 1001,
"key": "color",
"label": "Color",
"type": "",
"multiSelect": false,
"values": { "id": 9, "label": "Darkblue", "value": "darkblue" }
},
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": { "id": 20005, "label": "Hilfiger Shirt", "value": "name" }
},
"description": {
"id": 20006,
"key": "description",
"label": "Description",
"type": "",
"multiSelect": false,
"values": { "id": 20006, "label": "", "value": "description" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/cd81a5d37e4241686586812d9e179553?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/1c98f7fc408b9d2cca91abfbf5650df1?bg=F4F4F5&quality=75&height=1067&width=800, https://cdn.aboutstatic.com/f",
"attributes": {}
}
],
"variants": [
{
"id": 1,
"referenceKey": "THS0906008000001_S",
"attributes": {
"size": {
"id": 1002,
"key": "size",
"label": "Size",
"type": "",
"multiSelect": false,
"values": { "id": 28, "label": "S", "value": "s" }
}
},
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:33+00:00",
"updatedAt": "2023-08-28T11:19:33+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 31,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 3990,
"withoutTax": 3353,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 637, "rate": 0.19 } },
"appliedReductions": []
},
"customData": { "deliveryEstimate": [] }
},
{
"id": 2,
"referenceKey": "THS0906008000001_M",
"attributes": {
"size": {
"id": 1002,
"key": "size",
"label": "Size",
"type": "",
"multiSelect": false,
"values": { "id": 29, "label": "M", "value": "m" }
}
},
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:33+00:00",
"updatedAt": "2023-08-28T11:19:33+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 0,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 3990,
"withoutTax": 3353,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 637, "rate": 0.19 } },
"appliedReductions": []
},
"customData": {}
},
{
"id": 3,
"referenceKey": "THS0906008000001_L",
"attributes": {
"size": {
"id": 1002,
"key": "size",
"label": "Size",
"type": "",
"multiSelect": false,
"values": { "id": 30, "label": "L", "value": "l" }
}
},
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:33+00:00",
"updatedAt": "2023-06-12T14:06:22+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 0,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 3990,
"withoutTax": 3353,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 637, "rate": 0.19 } },
"appliedReductions": []
},
"customData": {}
}
],
"customData": {}
}
For our product detail page we want to show all related product attributes, not just the name. We can retrieve all attributes as follows:
// Get product with id 1 and all attributes
const product = await client.products.getById(1, {
with: {
attributes: "all",
},
});
console.log(product.attributes.sleevelength.values.label);
// => quartersleeve
{
"id": 1,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:33+00:00",
"updatedAt": "2023-06-12T14:05:34+00:00",
"indexedAt": "2023-06-19T16:09:59+00:00",
"firstLiveAt": "2023-06-12T14:05:33+00:00",
"masterKey": "THS090600",
"referenceKey": "THS0906008000001",
"attributes": {
"length": {
"id": 1007,
"key": "length",
"label": "Length",
"type": "",
"multiSelect": true,
"values": ["Array"]
},
"elasticity": {
"id": 1010,
"key": "elasticity",
"label": "Elasticity",
"type": "",
"multiSelect": false,
"values": ["Object"]
},
"category": {
"id": 551,
"key": "category",
"label": "Master Categories (AG)",
"type": "",
"multiSelect": true,
"values": ["Array"]
},
"brand": {
"id": 550,
"key": "brand",
"label": "Brand",
"type": "",
"multiSelect": false,
"values": ["Object"]
},
"producttype": {
"id": 1004,
"key": "producttype",
"label": "Producttype",
"type": "",
"multiSelect": false,
"values": ["Object"]
},
"badges": {
"id": 1011,
"key": "badges",
"label": "Badges",
"type": "",
"multiSelect": true,
"values": ["Array"]
},
"overallLength": {
"id": 1009,
"key": "overallLength",
"label": "Overalllength",
"type": "",
"multiSelect": false,
"values": ["Object"]
},
"designExtras": {
"id": 1005,
"key": "designExtras",
"label": "Design & Extras",
"type": "",
"multiSelect": true,
"values": ["Array"]
},
"brandLogo": {
"id": 20000,
"key": "brandLogo",
"label": "Brand logo",
"type": "",
"multiSelect": false,
"values": ["Object"]
},
"sleevelength": {
"id": 1006,
"key": "sleevelength",
"label": "Sleevelength",
"type": "",
"multiSelect": false,
"values": ["Object"]
},
"fit": {
"id": 1008,
"key": "fit",
"label": "Fit",
"type": "",
"multiSelect": true,
"values": ["Array"]
},
"countrypermission": {
"id": 1013,
"key": "countrypermission",
"label": "Countrtpermission",
"type": "",
"multiSelect": true,
"values": ["Array"]
},
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": ["Object"]
},
"color": {
"id": 1001,
"key": "color",
"label": "Color",
"type": "",
"multiSelect": false,
"values": ["Object"]
},
"material": {
"id": 1003,
"key": "material",
"label": "Material",
"type": "",
"multiSelect": false,
"values": ["Object"]
},
"description": {
"id": 20006,
"key": "description",
"label": "Description",
"type": "",
"multiSelect": false,
"values": ["Object"]
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/cd81a5d37e4241686586812d9e179553?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/1c98f7fc408b9d2cca91abfbf5650df1?bg=F4F4F5&quality=75&height=1067&width=800, https://cdn.aboutstatic.com/f",
"attributes": {}
}
],
"customData": {}
}
Retrieve all products in a given category by iterating through their result pages. \
The Get Multiple Products method is used to create category pages. You can include parameters for pagination, including limit
, page
, perPage
, and offset
.
const response = await client.products.query({
where: {
categoryId: 20201,
},
pagination: {
perPage: 48,
},
sort: {
by: APISortOption.Price,
direction: APISortOrder.Ascending,
},
with: {
attributes: {
withKey: ["brand", "name"],
},
},
});
We want to create a page to list all products of a certain category with their name, color, and price range. In this case women's shirts, category id 8. We pass the category id as where
parameter, the attributes color
and name
and priceRange
as with
parameter.
All examples require a configured Storefront API client being available as client
.
Let's say we want to create a page to list all products of a certain category with their name, color, and price range. In this case women's shirts, category ID 8. We pass the category id as where
parameter, the attributes color
and name
and priceRange
as with
parameter.
Sorting
We also add a sort
parameter to request the products sorted from lowest to highest price.
Limit
Additionally we want to show maximum 48 products per page. This we specify in pagination.perPage
. You can find more about it under Pagination.
const response = await client.products.query({
where: {
categoryId: 20201,
},
pagination: {
perPage: 48,
},
sort: {
by: APISortOption.Price,
direction: APISortOrder.Ascending,
},
with: {
attributes: {
withKey: ["brand", "name"],
},
},
});
[
{
"id": 13,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:06:00+00:00",
"updatedAt": "2023-06-12T14:06:01+00:00",
"indexedAt": "2023-07-05T10:27:27+00:00",
"firstLiveAt": "2023-06-12T14:06:00+00:00",
"masterKey": "LEV003100",
"referenceKey": "LEV0031009000002",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": { "id": 20005, "label": "Levis T-Shirt", "value": "name" }
},
"color": {
"id": 1001,
"key": "color",
"label": "Color",
"type": "",
"multiSelect": false,
"values": { "id": 41, "label": "Black", "value": "black" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/38ee8cd16ca9f4e7912ec4df24d1c753?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/c4a36b4e67705e7de4be766e78d0a262?quality=75&height=1067&width=800,https://cdn.aboutstatic.com/file/a95cc92",
"attributes": {}
}
],
"priceRange": {
"min": {
"currencyCode": "EUR",
"withTax": 2990,
"withoutTax": 2513,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 477, "rate": 0.19 } },
"appliedReductions": []
},
"max": {
"currencyCode": "EUR",
"withTax": 2990,
"withoutTax": 2513,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 477, "rate": 0.19 } },
"appliedReductions": []
}
},
"customData": {}
},
{
"id": 12,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:58+00:00",
"updatedAt": "2023-06-12T14:05:59+00:00",
"indexedAt": "2023-07-05T10:27:27+00:00",
"firstLiveAt": "2023-06-12T14:05:58+00:00",
"masterKey": "LEV003100",
"referenceKey": "LEV0031001002000",
"attributes": {
"color": {
"id": 1001,
"key": "color",
"label": "Color",
"type": "",
"multiSelect": false,
"values": { "id": 77, "label": "offwhite", "value": "offwhite" }
},
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": { "id": 20005, "label": "Levis T-Shirt", "value": "name" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/6074e8f1a0b1cd81885a1769e5d0cfa1?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/56755a972fefe61b91380e94df8481e8?quality=75&height=1067&width=800,https://cdn.aboutstatic.com/file/4f61adf",
"attributes": {}
}
],
"priceRange": {
"min": {
"currencyCode": "EUR",
"withTax": 2990,
"withoutTax": 2513,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 477, "rate": 0.19 } },
"appliedReductions": []
},
"max": {
"currencyCode": "EUR",
"withTax": 2990,
"withoutTax": 2513,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 477, "rate": 0.19 } },
"appliedReductions": []
}
},
"customData": {}
},
{
"id": 11,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:56+00:00",
"updatedAt": "2023-06-12T14:05:57+00:00",
"indexedAt": "2023-07-05T10:27:26+00:00",
"firstLiveAt": "2023-06-12T14:05:56+00:00",
"masterKey": "LEV003100",
"referenceKey": "LEV0074002000005",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": { "id": 20005, "label": "Levis T-Shirt", "value": "name" }
},
"color": {
"id": 1001,
"key": "color",
"label": "Color",
"type": "",
"multiSelect": false,
"values": { "id": 40, "label": "White", "value": "white" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/68bf124a0517bffaa5fe1dc7ac8707db.jpg?brightness=0.96&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/images/5464df73e16e82b6282309eac5588217.jpg?quality=75&height=1067&width=800,https://cdn.",
"attributes": {}
}
],
"priceRange": {
"min": {
"currencyCode": "EUR",
"withTax": 2990,
"withoutTax": 2513,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 477, "rate": 0.19 } },
"appliedReductions": []
},
"max": {
"currencyCode": "EUR",
"withTax": 2990,
"withoutTax": 2513,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 477, "rate": 0.19 } },
"appliedReductions": []
}
},
"customData": {}
}
]
Here we retrieve all product of a certain brand by its brand id.
You can get all brands including their IDs.
const filteredQuery = {
attributes: [
{
type: "attributes",
key: "brand",
values: [44], // ID of brand "Tom Tailor"
},
],
};
const response = await client.products.query({
where: filteredQuery,
with: {
attributes: {
withKey: ["brand"],
},
},
});
{
"pagination": {
"current": 3,
"total": 3,
"perPage": 100,
"page": 1,
"first": 1,
"prev": 1,
"next": 1,
"last": 1
},
"entities": [
{
"id": 7,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:47+00:00",
"updatedAt": "2023-06-12T14:05:48+00:00",
"indexedAt": "2023-08-27T13:39:55+00:00",
"firstLiveAt": "2023-06-12T14:05:47+00:00",
"masterKey": "TOT881400",
"referenceKey": "TOT8814004000001",
"attributes": {
"brand": {
"id": 550,
"key": "brand",
"label": "Marke",
"type": "",
"multiSelect": false,
"values": { "id": 44, "label": "Tom Tailor", "value": "tom_tailor" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/838cf719621c4727f5927aa812c866cc.jpg?brightness=0.96&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/images/adee9eac06163c89dfa2eab38ff8e7cf.jpg?quality=75&height=1067&width=800,https://cdn.",
"attributes": {}
}
],
"variants": [
{
"id": 19,
"referenceKey": "TOT8814004000001_S",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:47+00:00",
"updatedAt": "2023-06-12T14:06:22+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 23,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 1990,
"withoutTax": 1672,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 318, "rate": 0.19 } },
"appliedReductions": []
},
"customData": { "deliveryEstimate": [] }
},
{
"id": 20,
"referenceKey": "TOT8814004000001_M",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:47+00:00",
"updatedAt": "2023-06-12T14:06:21+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 0,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 1990,
"withoutTax": 1672,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 318, "rate": 0.19 } },
"appliedReductions": []
},
"customData": {}
},
{
"id": 21,
"referenceKey": "TOT8814004000001_L",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:47+00:00",
"updatedAt": "2023-06-12T14:06:22+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 21,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 1990,
"withoutTax": 1672,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 318, "rate": 0.19 } },
"appliedReductions": []
},
"customData": { "deliveryEstimate": [] }
}
],
"customData": {}
},
{
"id": 6,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:45+00:00",
"updatedAt": "2023-06-12T14:05:45+00:00",
"indexedAt": "2023-08-27T13:39:55+00:00",
"firstLiveAt": "2023-06-12T14:05:45+00:00",
"masterKey": "TOT881400",
"referenceKey": "TOT8814003000001",
"attributes": {
"brand": {
"id": 550,
"key": "brand",
"label": "Marke",
"type": "",
"multiSelect": false,
"values": { "id": 44, "label": "Tom Tailor", "value": "tom_tailor" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/f7268d764b2b00648da7edb8f5fb5e47.jpg?brightness=0.96&quality=75&trim=1&height=1280&width=960,https://cdn.aboutstatic.com/file/images/1bd6658e0f20367e5fc4f881e3b0b675.jpg?brightness=0.96&quality=75&height=1067&width=",
"attributes": {}
}
],
"variants": [
{
"id": 16,
"referenceKey": "TOT8814003000001_S",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:45+00:00",
"updatedAt": "2023-06-12T14:06:21+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 10,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 1990,
"withoutTax": 1672,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 318, "rate": 0.19 } },
"appliedReductions": []
},
"customData": { "deliveryEstimate": [] }
},
{
"id": 17,
"referenceKey": "TOT8814003000001_M",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:45+00:00",
"updatedAt": "2023-06-12T14:06:22+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 9,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 1990,
"withoutTax": 1672,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 318, "rate": 0.19 } },
"appliedReductions": []
},
"customData": { "deliveryEstimate": [] }
},
{
"id": 18,
"referenceKey": "TOT8814003000001_L",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:45+00:00",
"updatedAt": "2023-06-12T14:06:23+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 0,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 1990,
"withoutTax": 1672,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 318, "rate": 0.19 } },
"appliedReductions": []
},
"customData": {}
}
],
"customData": {}
},
{
"id": 5,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:43+00:00",
"updatedAt": "2023-06-12T14:05:43+00:00",
"indexedAt": "2023-08-27T13:39:55+00:00",
"firstLiveAt": "2023-06-12T14:05:43+00:00",
"masterKey": "TOT881400",
"referenceKey": "TOT8814001000001",
"attributes": {
"brand": {
"id": 550,
"key": "brand",
"label": "Marke",
"type": "",
"multiSelect": false,
"values": { "id": 44, "label": "Tom Tailor", "value": "tom_tailor" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/7eaab7a1547c73c286d74068515fb5fc.jpg?brightness=0.96&quality=75&trim=1&height=1280&width=960,https://cdn.aboutstatic.com/file/images/0dc17517a1f6b1e75b71fb538ad36fa9.jpg?quality=75&height=1067&width=800,https://cdn.",
"attributes": {}
}
],
"variants": [
{
"id": 13,
"referenceKey": "TOT8814001000001_S",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:43+00:00",
"updatedAt": "2023-06-12T14:06:22+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 0,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 1990,
"withoutTax": 1672,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 318, "rate": 0.19 } },
"appliedReductions": []
},
"customData": {}
},
{
"id": 14,
"referenceKey": "TOT8814001000001_M",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:43+00:00",
"updatedAt": "2023-06-12T14:06:22+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 6,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 1990,
"withoutTax": 1672,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 318, "rate": 0.19 } },
"appliedReductions": []
},
"customData": { "deliveryEstimate": [] }
},
{
"id": 15,
"referenceKey": "TOT8814001000001_L",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:43+00:00",
"updatedAt": "2023-06-12T14:06:21+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 45,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 1990,
"withoutTax": 1672,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 318, "rate": 0.19 } },
"appliedReductions": []
},
"customData": { "deliveryEstimate": [] }
}
],
"customData": {}
}
]
}
Sale products can be retrieved by filtering for sale
.
Products are considered as sale when any of its variants have a sale price on it.
const response = await client.products.query({
where: {
attributes: [{
type: 'boolean',
key: 'sale',
value: true,
}]
},
});
{
"pagination": {
"current": 1,
"total": 1,
"perPage": 100,
"page": 1,
"first": 1,
"prev": 1,
"next": 1,
"last": 1
},
"entities": [
{
"id": 14,
"isActive": true,
"isSoldOut": false,
"isNew": true,
"createdAt": "2023-06-12T14:06:03+00:00",
"updatedAt": "2023-06-12T14:06:03+00:00",
"indexedAt": "2023-08-28T08:39:57+00:00",
"firstLiveAt": "2023-06-12T14:06:03+00:00",
"masterKey": "LIJ048000",
"referenceKey": "LIJ0480001000004",
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/bc06c53f15b5a6634e10747378fc9eb7.png?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/images/c453b9bb1b3265d8f65a4736f7631600.png?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,h"
}
],
"customData": {}
}
]
}
New arrivals can be retrieved by filtered for isnew
.
Products are considered "new" when they were inserted into the shop within a period of 28 days. This value can be adjusted accordingly for each shop.
const response = await client.products.query({
where: {
attributes: [{
type: 'boolean',
key: 'isNew',
value: true,
}]
},
});
{
"pagination": {
"current": 1,
"total": 1,
"perPage": 100,
"page": 1,
"first": 1,
"prev": 1,
"next": 1,
"last": 1
},
"entities": [
{
"id": 14,
"isActive": true,
"isSoldOut": false,
"isNew": true,
"createdAt": "2023-06-12T14:06:03+00:00",
"updatedAt": "2023-06-12T14:06:03+00:00",
"indexedAt": "2023-08-28T08:39:57+00:00",
"firstLiveAt": "2023-06-12T14:06:03+00:00",
"masterKey": "LIJ048000",
"referenceKey": "LIJ0480001000004",
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/bc06c53f15b5a6634e10747378fc9eb7.png?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/images/c453b9bb1b3265d8f65a4736f7631600.png?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,h"
}
],
"customData": {}
}
]
}
To filter for products within a certain price range we can leverage the filters of minPrice
and maxPrice
.
const filteredQuery = {
minPrice: 1990,
maxPrice: 2990,
};
const response = await client.products.query({
where: filteredQuery,
});
{
"pagination": {
"current": 6,
"total": 6,
"perPage": 100,
"page": 1,
"first": 1,
"prev": 1,
"next": 1,
"last": 1
},
"entities": [
{
"id": 13,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:06:00+00:00",
"updatedAt": "2023-06-12T14:06:01+00:00",
"indexedAt": "2023-08-28T09:40:02+00:00",
"firstLiveAt": "2023-06-12T14:06:00+00:00",
"masterKey": "LEV003100",
"referenceKey": "LEV0031009000002",
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/38ee8cd16ca9f4e7912ec4df24d1c753?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/c4a36b4e67705e7de4be766e78d0a262?quality=75&height=1067&width=800,https://cdn.aboutstatic.com/file/a95cc92"
}
],
"customData": {}
},
{
"id": 12,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:58+00:00",
"updatedAt": "2023-06-12T14:05:59+00:00",
"indexedAt": "2023-08-28T09:40:02+00:00",
"firstLiveAt": "2023-06-12T14:05:58+00:00",
"masterKey": "LEV003100",
"referenceKey": "LEV0031001002000",
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/6074e8f1a0b1cd81885a1769e5d0cfa1?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/56755a972fefe61b91380e94df8481e8?quality=75&height=1067&width=800,https://cdn.aboutstatic.com/file/4f61adf"
}
],
"customData": {}
},
{
"id": 11,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:56+00:00",
"updatedAt": "2023-06-12T14:05:57+00:00",
"indexedAt": "2023-08-28T09:40:02+00:00",
"firstLiveAt": "2023-06-12T14:05:56+00:00",
"masterKey": "LEV003100",
"referenceKey": "LEV0074002000005",
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/68bf124a0517bffaa5fe1dc7ac8707db.jpg?brightness=0.96&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/images/5464df73e16e82b6282309eac5588217.jpg?quality=75&height=1067&width=800,https://cdn."
}
],
"customData": {}
},
{
"id": 7,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:47+00:00",
"updatedAt": "2023-06-12T14:05:48+00:00",
"indexedAt": "2023-08-28T09:40:02+00:00",
"firstLiveAt": "2023-06-12T14:05:47+00:00",
"masterKey": "TOT881400",
"referenceKey": "TOT8814004000001",
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/838cf719621c4727f5927aa812c866cc.jpg?brightness=0.96&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/images/adee9eac06163c89dfa2eab38ff8e7cf.jpg?quality=75&height=1067&width=800,https://cdn."
}
],
"customData": {}
},
{
"id": 6,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:45+00:00",
"updatedAt": "2023-06-12T14:05:45+00:00",
"indexedAt": "2023-08-28T09:40:02+00:00",
"firstLiveAt": "2023-06-12T14:05:45+00:00",
"masterKey": "TOT881400",
"referenceKey": "TOT8814003000001",
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/f7268d764b2b00648da7edb8f5fb5e47.jpg?brightness=0.96&quality=75&trim=1&height=1280&width=960,https://cdn.aboutstatic.com/file/images/1bd6658e0f20367e5fc4f881e3b0b675.jpg?brightness=0.96&quality=75&height=1067&width="
}
],
"customData": {}
},
{
"id": 5,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:43+00:00",
"updatedAt": "2023-06-12T14:05:43+00:00",
"indexedAt": "2023-08-28T09:40:02+00:00",
"firstLiveAt": "2023-06-12T14:05:43+00:00",
"masterKey": "TOT881400",
"referenceKey": "TOT8814001000001",
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/7eaab7a1547c73c286d74068515fb5fc.jpg?brightness=0.96&quality=75&trim=1&height=1280&width=960,https://cdn.aboutstatic.com/file/images/0dc17517a1f6b1e75b71fb538ad36fa9.jpg?quality=75&height=1067&width=800,https://cdn."
}
],
"customData": {}
}
]
}
Related products are groups of product with the same core criteria, i.e., share the same attributes like T-shirts of different colors and sizes. Each product of a group shares the same style key attribute. #
In this example we fetch related products for a specific t-shirt which has the style key THS090600
.
const filteredQuery = {
attributes: [
{
type: "attributes",
key: "styleKey",
values: ["THS090600"],
},
],
};
const response = await client.products.query({
where: filteredQuery,
});
{
"pagination": {
"current": 4,
"total": 4,
"perPage": 100,
"page": 1,
"first": 1,
"prev": 1,
"next": 1,
"last": 1
},
"entities": [
Faceted search allows the user to filter products based on its attributes.
SCAYLE’s powerful search function enables the user to search for product information. The search index can process complex search queries within a short time to fulfill essential shop requirements.
The products endpoint's where
parameter, as used to get multiple Products, supports two different kinds of parameters:
You need to manually add a filter in the SCAYLE Panel.
To find all existing filters of our current category's products we use the filters
API and pass the category id as where
parameter.
This will return us a list of attributes we can filter by. In our shop UI we would list these for our users to select.
// Get available filters for our category
const options = {
where: {
categoryId: 8,
},
};
const filters = await client.filters.get(options);
const colorFilter = filters.find((filter) => filter.slug === "color");
console.log(colorFilter.values.map((filter) => filter.name));
// [ 'White', 'black', 'offwhite' ]
[
{
"id": null,
"slug": "prices",
"name": "Prices",
"attributeGroupType": "computed_attribute",
"type": "range",
"values": [{ "min": 2990, "max": 2990, "productCount": 3 }]
},
{
"id": null,
"slug": "sale",
"name": "Sale",
"attributeGroupType": "computed_attribute",
"type": "boolean",
"values": [
{ "name": false, "productCount": 3 },
{ "name": true, "productCount": 0 }
]
},
{
"id": null,
"slug": "max_savings_percentage",
"name": "Savings",
"attributeGroupType": "computed_attribute",
"type": "range",
"values": [{ "min": 0, "max": 0, "productCount": 3 }]
},
{
"id": 1001,
"slug": "color",
"name": "Farbe",
"attributeGroupType": "",
"type": "attributes",
"values": [
{ "name": "White", "productCount": 1, "id": 40, "value": "white" },
{ "name": "black", "productCount": 1, "id": 41, "value": "black" },
{ "name": "offwhite", "productCount": 1, "id": 77, "value": "offwhite" }
]
}
]
We pick the color attribute filter and use its first value to refine your product search.
In a user-facing application, you might want to display all filters on the screen and then have the user select their desired filters and values.
// Get filtered product results
// Variables colorFilter and options are based on step 1
const filteredQuery = {
...options,
attributes: [
{
type: "attributes",
key: colorFilter.slug,
values: [colorFilter.values[0].id], // ID of color "white"
},
],
};
const response = await client.products.query({
where: filteredQuery,
with: {
variants: "all",
attributes: {
withKey: ["color"],
},
},
});
console.log(response.entities[0].attributes.color.values.label);
// White
The products
API returns paginated results. You can see here how to build a pagination.
To include additional properties in the response, use the with
parameter.
We recommend to update the website URL with the applied filters. This makes it easier for your users to bookmark the URL and revisit your shop with pre-filtered results.
{
"pagination": {
"current": 2,
"total": 2,
"perPage": 100,
"page": 1,
"first": 1,
"prev": 1,
"next": 1,
"last": 1
},
"entities": [
{
"id": 11,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:56+00:00",
"updatedAt": "2023-06-12T14:05:57+00:00",
"indexedAt": "2023-07-06T08:12:40+00:00",
"firstLiveAt": "2023-06-12T14:05:56+00:00",
"masterKey": "LEV003100",
"referenceKey": "LEV0074002000005",
"attributes": {
"color": {
"id": 1001,
"key": "color",
"label": "Farbe",
"type": "",
"multiSelect": false,
"values": { "id": 40, "label": "white", "value": "white" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/68bf124a0517bffaa5fe1dc7ac8707db.jpg?brightness=0.96&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/images/5464df73e16e82b6282309eac5588217.jpg?quality=75&height=1067&width=800,https://cdn.",
"attributes": {}
}
],
"variants": [
{
"id": 31,
"referenceKey": "LEV0074002000005_S",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:56+00:00",
"updatedAt": "2023-06-12T14:06:24+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 40,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 2990,
"withoutTax": 2513,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 477, "rate": 0.19 } },
"appliedReductions": []
},
"customData": {}
},
{
"id": 32,
"referenceKey": "LEV0074002000005_M",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:56+00:00",
"updatedAt": "2023-06-12T14:06:23+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 41,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 2990,
"withoutTax": 2513,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 477, "rate": 0.19 } },
"appliedReductions": []
},
"customData": {}
},
{
"id": 33,
"referenceKey": "LEV0074002000005_L",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:56+00:00",
"updatedAt": "2023-06-12T14:06:23+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 42,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 2990,
"withoutTax": 2513,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 477, "rate": 0.19 } },
"appliedReductions": []
},
"customData": {}
}
],
"customData": {}
},
{
"id": 2,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:36+00:00",
"updatedAt": "2023-06-12T14:05:37+00:00",
"indexedAt": "2023-07-06T08:12:40+00:00",
"firstLiveAt": "2023-06-12T14:05:36+00:00",
"masterKey": "THS090600",
"referenceKey": "THS0906006000001",
"attributes": {
"color": {
"id": 1001,
"key": "color",
"label": "Farbe",
"type": "",
"multiSelect": false,
"values": { "id": 40, "label": "Weiß", "value": "weiss" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/8de1d6ebb091d7363a05bcf99a0095f3?quality=75&height=1067&width=800,https://cdn.aboutstatic.com/file/1894bfbbfec69306940eb79ee3c6c8f4?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,",
"attributes": {}
}
],
"variants": [
{
"id": 4,
"referenceKey": "THS0906006000001_S",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:36+00:00",
"updatedAt": "2023-06-12T14:06:23+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 34,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 3990,
"withoutTax": 3353,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 637, "rate": 0.19 } },
"appliedReductions": []
},
"customData": {}
},
{
"id": 5,
"referenceKey": "THS0906006000001_M",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:36+00:00",
"updatedAt": "2023-06-12T14:06:22+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 11,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 3990,
"withoutTax": 3353,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 637, "rate": 0.19 } },
"appliedReductions": []
},
"customData": {}
},
{
"id": 6,
"referenceKey": "THS0906006000001_L",
"firstLiveAt": "0001-01-01T00:00:00+00:00",
"createdAt": "2023-06-12T14:05:36+00:00",
"updatedAt": "2023-06-12T14:06:22+00:00",
"stock": {
"supplierId": 1,
"warehouseId": 1,
"quantity": 36,
"isSellableWithoutStock": false
},
"price": {
"currencyCode": "EUR",
"withTax": 3990,
"withoutTax": 3353,
"recommendedRetailPrice": null,
"tax": { "vat": { "amount": 637, "rate": 0.19 } },
"appliedReductions": []
},
"customData": {}
}
],
"customData": {}
}
]
}
It is also possible to get possible values and their product counts of a single filter. In the following example we want to get all values from color filter.
// Get all color values and their product counts
const options = {
category: 8,
};
const response = await client.filters.getValues("color", {
where: options,
});
console.log(response[0].name);
// Black
[
{ "name": "Black", "productCount": 5, "id": 41, "value": "black" },
{ "name": "White", "productCount": 2, "id": 40, "value": "white" },
{
"name": "Grey",
"productCount": 2,
"id": 42,
"value": "grey"
},
{ "name": "Navy", "productCount": 2, "id": 9, "value": "navy" },
{ "name": "Turquoise", "productCount": 1, "id": 51, "value": "turquoise" },
{ "name": "Offwhite", "productCount": 1, "id": 77, "value": "offwhite" }
]
Search by term allows the user to find products based on a word or a phrase.
Searching by term can be used in combination with the faceted search. We leverage the term
parameter of the products endpoint for that. You can read more about this endpoint in the Get multiple products section.
Logic by example
Example, where name and attribute1 are set as searchable through SCAYLE Panel:
When searching for "blue sweater" the returned results would be:
Product4 will not be returned as the searched term does not match the name or attribute1.
All examples require a configured Storefront API client being available as client
. See Authentication for setup.
In this example we are searching for all products including the term shirt
in their product name.
// Search for products with "shirt" in their name
const products = await client.products.query({
where: { term: "shirt" },
with: {
attributes: {
withKey: ["name"],
},
},
});
console.log(products.entities[0].attributes.name.values.label);
// Tom Tailor T-Shirt
{
"pagination": {
"current": 10,
"total": 10,
"perPage": 100,
"page": 1,
"first": 1,
"prev": 1,
"next": 1,
"last": 1
},
"entities": [
{
"id": 7,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:47+00:00",
"updatedAt": "2023-06-12T14:05:48+00:00",
"indexedAt": "2023-08-05T14:37:52+00:00",
"firstLiveAt": "2023-06-12T14:05:47+00:00",
"masterKey": "TOT881400",
"referenceKey": "TOT8814004000001",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": {
"id": 20005,
"label": "Tom Tailor T-Shirt",
"value": "name"
}
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/838cf719621c4727f5927aa812c866cc.jpg?brightness=0.96&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/images/adee9eac06163c89dfa2eab38ff8e7cf.jpg?quality=75&height=1067&width=800,https://cdn.",
"attributes": {}
}
],
"customData": {}
},
{
"id": 6,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:45+00:00",
"updatedAt": "2023-06-12T14:05:45+00:00",
"indexedAt": "2023-08-05T14:37:52+00:00",
"firstLiveAt": "2023-06-12T14:05:45+00:00",
"masterKey": "TOT881400",
"referenceKey": "TOT8814003000001",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": {
"id": 20005,
"label": "Tom Tailor T-Shirt",
"value": "name"
}
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/f7268d764b2b00648da7edb8f5fb5e47.jpg?brightness=0.96&quality=75&trim=1&height=1280&width=960,https://cdn.aboutstatic.com/file/images/1bd6658e0f20367e5fc4f881e3b0b675.jpg?brightness=0.96&quality=75&height=1067&width=",
"attributes": {}
}
],
"customData": {}
},
{
"id": 5,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:43+00:00",
"updatedAt": "2023-06-12T14:05:43+00:00",
"indexedAt": "2023-08-05T14:37:52+00:00",
"firstLiveAt": "2023-06-12T14:05:43+00:00",
"masterKey": "TOT881400",
"referenceKey": "TOT8814001000001",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": {
"id": 20005,
"label": "Tom Tailor T-Shirt",
"value": "name"
}
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/7eaab7a1547c73c286d74068515fb5fc.jpg?brightness=0.96&quality=75&trim=1&height=1280&width=960,https://cdn.aboutstatic.com/file/images/0dc17517a1f6b1e75b71fb538ad36fa9.jpg?quality=75&height=1067&width=800,https://cdn.",
"attributes": {}
}
],
"customData": {}
},
{
"id": 4,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:41+00:00",
"updatedAt": "2023-06-12T14:05:41+00:00",
"indexedAt": "2023-08-05T14:37:52+00:00",
"firstLiveAt": "2023-06-12T14:05:41+00:00",
"masterKey": "THS090600",
"referenceKey": "THS1561003000001",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": { "id": 20005, "label": "Hilfiger Shirt", "value": "name" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/dac81f069b3f7bcea884c806726d5188?bg=F4F4F5&quality=75&trim=1&height=1067&width=800, https://cdn.aboutstatic.com/file/images/9b955c9d77708548b0d8486f306e0132.jpg?quality=75&height=1067&width=800, https://cdn.aboutstatic.com",
"attributes": {}
}
],
"customData": {}
},
{
"id": 3,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:38+00:00",
"updatedAt": "2023-06-12T14:05:39+00:00",
"indexedAt": "2023-08-05T14:37:52+00:00",
"firstLiveAt": "2023-06-12T14:05:38+00:00",
"masterKey": "THS090600",
"referenceKey": "THS0906007000001",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": { "id": 20005, "label": "Hilfiger Shirt", "value": "name" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/9692f6858f7e017f50861290cbb424c4?bg=F4F4F5&quality=75&trim=1&height=1280&width=960, https://cdn.aboutstatic.com/file/1ac0057101b527a9d4340379feededfb?quality=75&height=1067&width=800, https://cdn.aboutstatic.com/file/34800",
"attributes": {}
}
],
"customData": {}
},
{
"id": 1,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:33+00:00",
"updatedAt": "2023-06-12T14:05:34+00:00",
"indexedAt": "2023-08-05T14:37:52+00:00",
"firstLiveAt": "2023-06-12T14:05:33+00:00",
"masterKey": "THS090600",
"referenceKey": "THS0906008000001",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": { "id": 20005, "label": "Hilfiger Shirt", "value": "name" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/cd81a5d37e4241686586812d9e179553?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/1c98f7fc408b9d2cca91abfbf5650df1?bg=F4F4F5&quality=75&height=1067&width=800, https://cdn.aboutstatic.com/f",
"attributes": {}
}
],
"customData": {}
},
{
"id": 2,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:36+00:00",
"updatedAt": "2023-06-12T14:05:37+00:00",
"indexedAt": "2023-08-05T14:37:52+00:00",
"firstLiveAt": "2023-06-12T14:05:36+00:00",
"masterKey": "THS090600",
"referenceKey": "THS0906006000001",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": { "id": 20005, "label": "Hilfiger Shirt", "value": "name" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/8de1d6ebb091d7363a05bcf99a0095f3?quality=75&height=1067&width=800,https://cdn.aboutstatic.com/file/1894bfbbfec69306940eb79ee3c6c8f4?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,",
"attributes": {}
}
],
"customData": {}
},
{
"id": 13,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:06:00+00:00",
"updatedAt": "2023-06-12T14:06:01+00:00",
"indexedAt": "2023-08-05T14:37:52+00:00",
"firstLiveAt": "2023-06-12T14:06:00+00:00",
"masterKey": "LEV003100",
"referenceKey": "LEV0031009000002",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": { "id": 20005, "label": "Levis T-Shirt", "value": "name" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/38ee8cd16ca9f4e7912ec4df24d1c753?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/c4a36b4e67705e7de4be766e78d0a262?quality=75&height=1067&width=800,https://cdn.aboutstatic.com/file/a95cc92",
"attributes": {}
}
],
"customData": {}
},
{
"id": 12,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:58+00:00",
"updatedAt": "2023-06-12T14:05:59+00:00",
"indexedAt": "2023-08-05T14:37:52+00:00",
"firstLiveAt": "2023-06-12T14:05:58+00:00",
"masterKey": "LEV003100",
"referenceKey": "LEV0031001002000",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": { "id": 20005, "label": "Levis T-Shirt", "value": "name" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/6074e8f1a0b1cd81885a1769e5d0cfa1?bg=F4F4F5&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/56755a972fefe61b91380e94df8481e8?quality=75&height=1067&width=800,https://cdn.aboutstatic.com/file/4f61adf",
"attributes": {}
}
],
"customData": {}
},
{
"id": 11,
"isActive": true,
"isSoldOut": false,
"isNew": false,
"createdAt": "2023-06-12T14:05:56+00:00",
"updatedAt": "2023-06-12T14:05:57+00:00",
"indexedAt": "2023-08-05T14:37:52+00:00",
"firstLiveAt": "2023-06-12T14:05:56+00:00",
"masterKey": "LEV003100",
"referenceKey": "LEV0074002000005",
"attributes": {
"name": {
"id": 20005,
"key": "name",
"label": "Name",
"type": "",
"multiSelect": false,
"values": { "id": 20005, "label": "Levis T-Shirt", "value": "name" }
}
},
"images": [
{
"hash": "https://cdn.aboutstatic.com/file/images/68bf124a0517bffaa5fe1dc7ac8707db.jpg?brightness=0.96&quality=75&trim=1&height=1067&width=800,https://cdn.aboutstatic.com/file/images/5464df73e16e82b6282309eac5588217.jpg?quality=75&height=1067&width=800,https://cdn.",
"attributes": {}
}
],
"customData": {}
}
]
}
Product attributes can be used to enhance product data displayed in a shop, for example, product material, color and more.
Attributes are defined as values that can be assigned to products. Their primary purpose is to describe a product and to provide specific details about this exact product. Attributes also contribute to increasing the overall product data quality, enable filtering options, and serve as the foundation for translations. Standard attributes might include brand, size, and color.
Working with attributes enables users to perform the following actions in SCAYLE:
We distinguish between simple and advanced attribute structures. Both types are used to form attribute groups, which are then assigned to products. Attribute groups do not only describe a product in more detail (e.g., defining a single value of color, size, or season). Attribute groups are furthermore assigned an entity to structure product levels and can constitute of multiple components.
Moreover, it is possible to automatically aggregate product information by referencing attribute groups to one another (n:m). This way, merchant attributes can be mapped to the attributes defined in the system – only in this order.
SCAYLE automatically references additional attributes to a product if one of the attribute values is assigned to the item. For example, when the detail color "light blue" is assigned to a product, it automatically gains the search color attribute "blue."
Simple attribute groups consist of clearly defined separate values that can be assigned to multiple products. This set of values does not change when describing products. Furthermore, simple attribute groups are used for configuration purposes, such as shop filters or assortment mappings.
Example
There are two attribute groups – "size" and "color." Customers should be able to filter products according to the included attributes (e.g., "small" or "red"). The simple values within these two attribute groups will not change and can be chosen on the product detail page from the defined set of options (e.g., "red," "yellow," "green" or "blue" for "color").
Advanced attributes have a more complex structure. It is useful to work with advanced attributes if the user wants to add particular specifications to a product that are not shared with other products. It is possible to use different components to create a customized component structure for advanced attributes to ensure that product data will be provided in a consistent manner.
The use of advanced attributes is particularly recommended if the user wants to add free text to the product information (e.g., a product description or warning notices).
The following components are available for defining the structure of an advanced attribute:
The user can take these field types and set up any combination to define an advanced attribute structure. Additionally, users can specify if an advanced attribute can be used once or multiple times per product.
Example: Multiple Options Material Composition
When using advanced attribute groups, users can define a more complex structure within this attribute group. For example, if a shirt consists of different materials in different percentages, users can set the material composition individually for each product using an advanced attribute group.
Attributes can be either shop-country-specific or global. When an attribute is shop-country-specific, it means that an attribute value will be applied for the specified shop country. This makes it easy to customize attributes in relation to a specific shop country while still maintaining a sensible default value for all other shop countries using the same attribute.
To avoid accidentally deleting or updating attributes that were manually added or edited via the SCAYLE Panel, the query parameter ignoreAttributeLocks
can be used to control the behaviour of how these updates should be handled.
The default behaviour is to respect attribute locks. Thus, even if an attribute is present in the payload, it will not be updated. The same behaviour will be applied, if an attribute is omitted in the payload, so it will not get deleted.
If you want to force updates or deletion of attributes, you need to set ignoreAttributeLocks
= true. In this case, all attributes get updated or deleted even if they are locked.
All data modifying operations will trigger the status evaluation of the related product.
In SCAYLE, you can create a product attribute and override its value for a specific shop.
This method is utilized for the creation of a product attribute. It either creates a new attribute if it doesn't exist and attach it to the product, or attach an existing attribute to the product.
If shop-country-specific values are not provided, then the existing shop country overrides will not be modified. Otherwise, shop country overrides will be replaced with the provided values. In case you wish to remove shop country specific values for a certain attribute, you have to explicitly set shopCountrySpecific
to an empty Array
(PHP & JavaScript) ArrayList
(Java)
let response = await client.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: productIdentifier},
{requestBody: productAttribute}
);
let createdProductAttribute = response.body;
Product attributes write operations can be used with optional parameters - called options.
Updating or creating a product attribute will trigger the status evaluation. The product might end up in the problem
status.
let attribute = {
"name": "size",
"type": "simple",
"value": "M"
};
let response = await client.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: attribute}
);
let createdAttribute = response.body;
let attribute = {
"name": "season",
"type": "simpleList",
"value": ["autumn", "winter"]
};
let response = await client.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: attribute}
);
let createdAttribute = response.body;
let attribute = {
"name": "collection",
"type": "localizedString",
"value": {"de_DE": "einzigartig", "en_GB": "unique"}
};
let response = await client.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: attribute}
);
let createdAttribute = response.body;
let attribute = {
"name": "dimensions",
"type": "advanced",
"value": {
"height": 100,
"width": 30,
"unit": "cm"
}
};
let response = await client.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: attribute}
);
let createdAttribute = response.body;
let attribute = {
"name": "material",
"type": "advancedList",
"value": [
{
"name": "wool",
"percentage": 80
},
{
"name": "cotton",
"percentage": 20
}
]
};
let response = await client.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: attribute}
);
let createdAttribute = response.body;
let productAttribute = {
"name": "material",
"type": "simple",
"value": "cotton"
};
let response = await client.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1, ignoreAttributeLocks: true},
{requestBody: productAttribute}
);
let updatedProductAttribute = response.body;
Create or update simple product attributes; override attribute value for certain shop country
let shopCountrySpecificAttribute = {
"shopKey": "ms",
"countryCode": "de",
"value": "polyester"
};
let productAttribute = {
"name": "material",
"type": "simple",
"value": "cotton",
"shopCountrySpecific": [
shopCountrySpecificAttribute
]
};
let response = await client.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1},
{requestBody: productAttribute}
);
let updatedProductAttribute = response.body;
Update locked simple product attributes and unassign existing product attributes with an empty array / ArrayList
let productAttribute = {
"name": "material",
"type": "simple",
"value": "cotton",
"shopCountrySpecific": []
};
let response = await client.apis.Attributes.updateOrCreateProductAttribute(
{productIdentifier: 1, ignoreAttributeLocks: true},
{requestBody: productAttribute}
);
let updatedProductAttribute = response.body;
let response = await client.apis.Attributes.getProductAttribute({
productIdentifier: 1,
attributeGroupName: "material"
});
let productAttribute = response.body;
Retrieve all attributes attached to a product.
let response = await client.apis.Attributes.getProductAttributes({productIdentifier: productIdentifier});
let productAttributes = response.body.entities;
Deleting a product attribute will trigger the status evaluation.
client.apis.Attributes.deleteProductAttribute({
productIdentifier: 1,
attributeGroupName: "material"
Fetch a single attribute information using its key.
You can retrieve a specific attribute with all its possible values by the key
value which is the groupName
or attributeGroupName
in the API Reference.
Parameter | Details |
---|---|
key | String
|
All examples require a configured Storefront API client being available as client
.
In this example we fetch all possible values of the attribute color
.
// Get all values for color
const attribute = await client.attributes.getByKey("color");
console.log(attribute.label);
console.log(attribute.values[0].label);
{
"id": 1001,
"key": "color",
"label": "Color",
"type": "",
"multiSelect": false,
"values": [
{ "id": 42, "label": "Navy", "value": "navy" },
{ "id": 77, "label": "offwhite", "value": "offwhite" },
{ "id": 41, "label": "Black", "value": "black" },
{ "id": 40, "label": "White", "value": "white" }
]
}