docs
  1. SCAYLE Resource Center
  2. Developer Guides
  3. Products
  4. Manage Products

Manage Products

General

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.

Entity levels

  • Masters: collections of products belonging together, sharing the highest level of attributes (e.g., T-shirt).
  • Products: collections of variants belonging together, each sharing underlying similarities (e.g., color).
  • Variants: entities with the most specific representation of a product. These items carry stock and price info and are being sold in the shops (e.g., sneaker of specific brand > color: white > size: 42).

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.

Product data is split into 3 entity levels

In general, product information relates to three different data types:

  • Categories
  • Attributes
  • Advanced attributes

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:

  • Internal ID, which enables data exchange between different SCAYLE products.
  • External key, which allows data exchange with external services.
  • Cross-market ID, for example, EAN.
  • Status information.

Retrieving Product details is a primary use case in shop management. /products endpoint supports all the required use cases:

  • Display Product Information: Retrieve relevant product information like product name, description, price, images, and specifications.
  • Price and Availability: Display real-time price and availability information. This may require integrating with inventory management and pricing systems.
  • Product Variants: If a product has different variants (e.g., sizes), developers need to implement a way for users to select and view these variants.
  • Images and Media: Ensure the PDP can handle multiple high-quality images, 360-degree views, and videos to help users visualize the product.
  • Product Customization: For customizable products (e.g., custom engraving), developers need to build tools for users to make selections and view the customizations in real-time.
  • Product Recommendations: Implement recommendation systems that suggest related or complementary products to encourage upselling and cross-selling.

Good Practices :

  • SEO Optimization: Optimize the Product Display Page for search engines by ensuring proper meta tags, schema markup, and clean URL structures.
  • Performance Optimization: Optimize the page's loading speed to provide a seamless user experience.

Admin API

Create product

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 theignoreMasterIfExistflag. See details about Product Attributes.

Options

Product creation can be used with optional parameters - called options:

ParameterTypeDetails
ignoreMasterIfExistboolean

Ignore master data from the request, if master exists.

If set to true and a master product with the given master.referenceKey already exists, then the provided master data will be ignored.updateIfExists doesn't affect this behavior.

When creating a new product (updateIfExists=false or not provided) for an existing master, if master categories or attributes are provided and ignoreMasterIfExist is set to false or not provided, an error is returned.

When updating a product (in combination with updateIfExists=true) for an existing master, if master categories or attributes are provided and ignoreMasterIfExist is set to false or not provided, provided master data will be processed.

updateIfExistsbooleanWhen 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.
ignoreAttributeLocksbooleanForce an update of categories even if they might be locked
ignoreCategoryLocksbooleanForce an update of categories even if they might be locked.

Nested resources

Include nested resources

Use with parameter to include following nested resources:

  • attributes
  • images
  • variants
  • variants.attributes
  • variants.customData
  • variants.prices
  • variants.relatedVariants
  • variants.stocks
  • productSortings
  • customData

Master

Providing the master as part of the product hierarchy is mandatory.

  • If an existing master.referenceKey is provided, the product will inherit all attributes and categories of the existing master.
  • Master attributes and categories can only be defined when creating a new master.
  • Master categories must contain a root category.

State

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.

Merchants

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.

Attributes

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.

Variants

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.

Images

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.

Create basic product

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 complete product

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;

Get products

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;

Get a collection of products

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;

Filters

ParameterDetails
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

This query parameter allows you to filter for entities with the given simple attributes. The array/object key must be the attribute name and the value can be a comma-separated list of attribute values.

The filter logic will combine all attributes of the same group into an OR filter and all attribute groups into an AND filter.

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.

Options

Product read can be used with optional parameters - called options

Load nested resources

Use with parameter to load nested resources

  • attributes
  • images
  • variants
  • variants.attributes
  • variants.prices
  • variants.stocks
  • variants.customData
  • productSortings
  • customData

Product entity

ParameterTypeDetails
idIntegerThe ID of the product created by SCAYLE.
problemsString[]If product is in problem state, the reasons are listed here.
referenceKeyStringA key that uniquely identifies the product (e.g., a shirt in a specific color) within the tenant's ecosystem.
nameObjectThe localized product name. At least the base language that is configured in SCAYLE is mandatory.
masterMasterThe master entity the product is attached to.
statestringThe 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
attributesAttribute[]A list of attributes attached to the product.
variantsProductVariant[]A list of product variants attached to the product.
imagesProductImage[]A list of product images attached to the product.
productSortingsProductSorting[]A list of product sortings.
isCompositeBooleanIndicates whether the product is composite.
merchantReferenceKeysStringA list of merchant reference keys the product belongs to.

Get A List Of Products

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)
);

Get a product by reference key

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);

Get a product with variants

let response = await adminApi.apis.Products.getProduct({productIdentifier: 1, with: "variants"});
let product = response.body;

product.variants.forEach(
    variant => console.log(variant.referenceKey)
);

Get a product with custom data

let response = await adminApi.apis.Products.getProduct({productIdentifier: 1, with: "customData"});
let product = response.body;

console.log(product.customData)

Get a product with variant attributes

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)
        }
    }
});

Get a product with product sorting

let response = await adminApi.apis.Products.getProduct({productIdentifier: 1, with: "productSortings"});
let product = response.body;

product.productSortings.forEach(
    productSorting => console.log(productSorting.sortValue)
);

Update Products

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.

Optional parameters

ParameterTypeDetails
ignoreMasterIfExistBoolean

Ignore master data from the request, if master exists.

If set to true and a master product with the given master.referenceKey already exists, then the provided master data will be ignored.

When updating a product for an existing master, if master categories or attributes are provided and ignoreMasterIfExist is set to false or not provided, provided master data will be processed.

ignoreAttributeLocksBooleanForce an update of categories even if they might be locked.
ignoreCategoryLocksBooleanForce an update of categories even if they might be locked.
withString

The parameter allows you to include the following nested resources in the response:

  • attributes
  • images
  • variants
  • variants.attributes
  • variants.customData
  • variants.prices
  • variants.stocks
  • variants.relatedVariants
  • productSortings
  • customData

    It is also possible to exclude all nested resources from the response by providing an empty string as the value.
Nested entities

Not provided properties will get deleted except nested entities as stated below.

  • If a nested entity or array of nested entities like variants is not provided, it will NOT get deleted.
  • If a nested entity or array of nested entities like variants is provided, it will be replaced by the provided information.
  • If a nested entity or array of nested entities like variants is provided and set to null or empty, it will get deleted.

Attribute Locks

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

Master attributes and categories are shared between products.

Prices

All future and active prices that are not provided in the request will be invalidated.

  • Changes applied to the master will affect all related products.
  • The state evaluation is triggered for each product of the same master.

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.

State

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.

Merchants

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.

Attributes

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.

ParameterDetails
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 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.

customDataCustomData
isComposite

Boolean READ-ONLY

Indicates whether the product is composite.

merchantReferenceKeys

String

A list of merchant reference keys the product belongs to.

Examples

Update a product's name

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 a product's first live at

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;

Update product state

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!

ParameterDetails
state

String

The state of the product 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

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;

Set product live state

let newProductState = {
    state: "live",
    merchantReferenceKeys: ["merchant-1", "merchant-2"]
 };

let response = await adminApi.apis.Products.updateProductState({productIdentifier: 1}, {requestBody: newProductState});
let updatedProductState = response.body;

Delete product

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});

Delete a product by id

adminApi.apis.Products.deleteProduct({productIdentifier: 1});

Delete a product by reference key

adminApi.apis.Products.deleteProduct({productIdentifier: "key=my-key"});

Product attributes

Product attributes can be used to enhance product data displayed in a shop, for example, product material, color and more.

Shop Overrides

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.

Attribute Locks

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.

Status

All data modifying operations will trigger the status evaluation of the related product.

Handling missing advanced attributes

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.

Create or update a product attribute

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;

Options

Product attributes write operations can be used with optional parameters - called options:

ParameterDetails
ignoreAttributeLocks

Boolean

Force an update of attributes even if they are locked.

Status

Updating or creating a product attribute will trigger the status evaluation. The product might end up in the problem status.

ParameterDetails
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.

Examples

Create Simple Attribute

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 Simple List Attribute

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 Localized Attribute

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 Localized List Attribute

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 Advanced Attribute

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 advanced list attribute

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 product attribute with options

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;

Example with Shop Country Overrides

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 Attributes

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;

Get a product attribute

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;
ParameterDetails
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.

Examples

let response = await adminApi.apis.Attributes.getProductAttribute({
    productIdentifier: 1,
    attributeGroupName: "material"
});

let productAttribute = response.body;

Get a collection of product attributes

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;

Delete a product attribute

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
});

Options

The operation can be used with optional parameters - called options

ParameterDetails
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.

ParameterDetails
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.

Further education - SCAYLE Academy

Storefront API

Get a single product

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.

ParameterTypeDetails
productIdIntegerID of the product.
withObjectUse to request the optional fields.

Possible keys: variants, attributes, siblings.
campaignKeyStringUse to get the correct prices for the specified campaign.

Get a product with specific attributes

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
Response
{
  "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": {}
}

Get products with all attributes

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
Response
{
    "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": {}
}

Get multiple products

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"],
    },
  },
});

Get Products for Category Page

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.

Examples

All examples require a configured Storefront API client being available as client.

Get Products for Category Page

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"],
    },
  },
});
Response
[
    {
        "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": {}
    }
]

Get Products by Brand

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"],
    },
  },
});
Response
{
  "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": {}
    }
  ]
}

Get Products with Special Offers

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,
    }]
  },
});
Response
{
  "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": {}
    }
  ]
}

Get New Arrivals

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,
    }]
  },
});
Response
{
  "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": {}
    }
  ]
}

Get Products within Price Range

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,
});
Response
{
  "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,
});
Response
{
  "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:

  1. Queries for standard properties that are always present on a product (e.g. category, price range but also texts like name and description).
  2. Queries for product attributes that are defined by and specific to each shop instance.

You need to manually add a filter in the SCAYLE Panel.

Get all available Filters

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' ]
Response
[
    {
        "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.

Response
{
    "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": {}
        }
    ]
}

Additional: Get single filter values

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
Response
[
  { "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" }
]

Filter products by search term

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:

  • Product1:
    • name: "christmas sweater"
    • attribute1: "light blue"
  • Product2:
    • name: "pants"
    • attribute1: "blue"
  • Product3:
    • name: "cardigan sweater"
    • attribute1: "red"
  • Product4:
    • name: "pants"
    • attribute1: "red"

When searching for "blue sweater" the returned results would be:

  1. Product1 - it will rank the highest as both "blue" and "sweater" match
  2. Product3 - it will be returned because searched word "sweater" matches the name
  3. Product2 - it will be returned because searched word "blue" matches the attribute1. By default, it will rank lower than Product3 as name is given higher relevance than attribute1, however this can be adjusted through SCAYLE Panel.

Product4 will not be returned as the searched term does not match the name or attribute1.

Example

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
Response
{
  "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

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:

  • define a filter for shop pages
  • facilitate translation efforts
  • improve product data quality
  • accelerate product data enhancement processes

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

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").

Simple Attribute Groups

Advanced Attribute Groups

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:

  • Text (short)
  • Text (long)
  • Number
  • Attribute
  • List of attributes (attribute group)
  • Date

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.

Advanced Attribute Groups

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.

Advanced Attribute Group. Example: material composition

Shop Overrides

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.

Attribute Locks

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.

Status

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;

Options

Product attributes write operations can be used with optional parameters - called options.

Status

Updating or creating a product attribute will trigger the status evaluation. The product might end up in the problem status.

Create a simple product attribute

let attribute = {
    "name": "size",
    "type": "simple",
    "value": "M"
};

let response = await client.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 client.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 client.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 client.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 client.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 client.apis.Attributes.updateOrCreateProductAttribute(
    {productIdentifier: 1, ignoreAttributeLocks: true},
    {requestBody: productAttribute}
);

let updatedProductAttribute = response.body;

Example with Shop Country Overrides

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 Attributes

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;

Get an existing product attribute

let response = await client.apis.Attributes.getProductAttribute({
    productIdentifier: 1,
    attributeGroupName: "material"
});

let productAttribute = response.body;

Get a collection of product attributes

Retrieve all attributes attached to a product.

let response = await client.apis.Attributes.getProductAttributes({productIdentifier: productIdentifier});
let productAttributes = response.body.entities;

Delete a product attribute

Deleting a product attribute will trigger the status evaluation.

client.apis.Attributes.deleteProductAttribute({
    productIdentifier: 1,
    attributeGroupName: "material"

Get a Single Attribute

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.

ParameterDetails
key

String

groupName value of the attribute.

Example

All examples require a configured Storefront API client being available as client.

Get Attribute by groupName

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);
Response
{
  "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" }
  ]
}