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

Manage Product Variants

General

In the product hierarchy of SCAYLE each product has one or more Variants. These variants are the entities that customers buy online. Stock is managed on variants. Variants differ from each other by defining attributes such as "size" or "pack-size". Just like products, variants can have simple and advanced attributes.

Variants are entities with the most specific representation of a product and are the actual items sold in shops, e.g., sneaker: specific brand > color: white > size: 42).

Variant Stocks

Stocks represent the number of the available items and are defined on variant level. To ensure correct stock information, you update stock information in a specific warehouse.

More about Stocks.

Variant Prices

Prices are defined on variant level and contain all information about prices, taxes and validity — upcoming prices can also be defined for automatic future price updates. Prices may also include information about the respective price alternative, such as campaign discounts or promotion prices.

More about Prices.

Variant Attributes

Variant attributes can be used to enhance variant data displayed in a shop, for example, variant size, color and more.

Attributes can be either shop-country-specific or global. When an attribute is shop-country-specific, it means that an attribute value will be applied for the specified shop country. This makes it easy to customize attributes in relation to a specific shop country while still maintaining a sensible default value for all other shop countries using the same attribute.

To avoid accidentally deleting or updating attributes that were manually added or edited via the SCAYLE, 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.

More about Attributes.

Parameters

ParameterDetails
id

Integer READ-ONLY

ID assigned by SCAYLE.

referenceKey

String

A key that uniquely identifies the variant of a product (usually an SKU) within the tenant's ecosystem.

ean

String

An ean that refers to a product variant .

attributes

Attribute

A list of attributes attached to the product variant.

prices

ProductVariantPrice

A list of prices attached to the product variant.

stocks

ProductVariantStock

The product variant stock information.

customDataCustomData
isCompositeREAD-ONLY

Boolean

Indicates whether the variant is composite.

relatedVariants

RelatedProductVariant

A list of variants that belong to the composite variant.

Custom Data

This entity supports custom data, please check the documentation at Custom Data.

Admin API

Create product variant

Creating a variant in its basic version only requires a reference key. However, if you want to create a complete product variant, you can add additional attributes likes size, prices or promotion keys.

The method is used to create a product variant, which can be purchased by a customer.

All prices returned in the response will only contain active prices. If you want to get more detailed information, e.g., future prices, please use the Get Prices Method.

let response = await adminApi.apis.Variants.getProductVariants({productIdentifier: productIdentifier});
let productVariants = response.body.entities;

If there exists a custom data configuration for the productVariant 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.

Options

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

ParameterDetails
updateIfExists

Boolean

When set to true, a lookup is done for the variant with the given reference key and if it exists then the variant will be updated, otherwise the variant will get created.

ignoreAttributeLocks

Boolean

Force an update or deletion of attributes even if they might be locked.

with

String

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

  • attributes
  • customData
  • prices
  • stocks

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

Attributes

It is possible to specify a set of attributes, which will be either linked to the product variant if they already exist or created and subsequently linked to the product variant. The attribute's name must refer to an attribute group of the variant level.

Parameters

ParameterTypeDescription
idintegerID assigned by SCAYLE.
READ-ONLY
referenceKeystringA key that uniquely identifies the variant of a product (usually an SKU) within the tenant's ecosystem.
eanstringAn EAN that refers to a product variant.
attributesAttributeA list of attributes attached to the product variant.
pricesProductVariantPriceA list of prices attached to the product variant.
stocksProductVariantStockThe product variant stock information.
customDataCustomDataCustom data associated with the product variant.
isCompositebooleanIndicates whether the variant is composite.
READ-ONLY
relatedVariantsRelatedProductVarianA list of variants that belong to the composite variant.

Create a Basic Product Variant

let newProductVariant = {
  referenceKey: "myReferenceKey",
  ean: "0000007738357"
};

let response = await adminApi.apis.Variants.createProductVariant({productIdentifier: 1}, {requestBody: newProductVariant});
let createdProductVariant = response.body;

Create a Complete Product Variant

let newProductVariant = {
    referenceKey: "myReferenceKey",
    ean: "0000007738357",
    attributes: [
        {
            name: "size",
            type: "simple",
            value: "M"
        }
    ],
    prices: [
        {
            price: 5000,
            tax: 19.0,
            currencyCode: "EUR",
            countryCode: "DE",
            oldPrice: 6000,
            recommendedRetailPrice: 5500,
            groupKey: "myGroupKey",
            promotionKey: "myPromotionKey",
            validFrom: "2020-06-18T12:00:00+00:00",
            validTo: null
        }
    ],
    customData: {
        "additionalDetails": "details"
    }
};

let response = await adminApi.apis.Variants.createProductVariant({productIdentifier: 1}, {requestBody: newProductVariant});
let createdProductVariant = response.body;

Creation with Options

Create a product variant with reference key and EAN:

let newProductVariant = {
  referenceKey: "myReferenceKey",
  ean: "0000007738357",
  attributes: [
    {
      name: "size",
      type: "simple",
      value: "M"
    }
  ],
  prices: [
    {
      price: 5000,
      tax: 19.0,
      currencyCode: "EUR",
      countryCode: "DE",
      oldPrice: 6000,
      recommendedRetailPrice: 5500,
      groupKey: "myGroupKey",
      promotionKey: "myPromotionKey",
      validFrom: "2020-06-18T12:00:00+00:00",
      validTo: null
    }
  ],
  customData: {
    "additionalDetails": "details"
  }
};

let response = await adminApi.apis.Variants.createProductVariant({productIdentifier: 1}, {requestBody: newProductVariant});
let createdProductVariant = response.body;

Update product variant

This method replaces the product variant with the provided data.

As updating variants will replace attribute values, it is necessary to confirm overriding locked attributes. In general, this endpoint replaces the product variant with the provided information, meaning not provided properties will get deleted, except for nested entities: attributes, prices, stocks, customData, relatedVariants. This logic is only applied to them if they are part of the payload. So, for example, if an empty array of prices is provided, all active prices will be invalidated and all future prices will be deleted.

This method can be used to update/replace an existing product variant.

This method does not support partial updates.

Method Signature

let response = await adminApi.apis.Variants.updateProductVariant(
  {productIdentifier: productIdentifier, variantIdentifier: variantIdentifier},
  {requestBody: productVariant}
);

let updatedProductVariant = response.body;

If there exists a custom data configuration for the productVariant 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.

Options

Product variant update can be used with optional parameters - called options:

ParameterDetails
ignoreAttributeLocks

Boolean

Force an update or deletion of attributes, even if they might be locked.

with

String

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

  • attributes
  • customData
  • prices
  • stocks

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

Details

This method replaces the product variant with the provided data.

Attribute Locks

To avoid accidentally deleting or updating attributes that were manually added or edited in the SCAYLE Panel, you can use the query parameter ignoreAttributeLocks to control the behaviour of how these updates should be handled.

The default behaviour is to respect attribute locks, meaning 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/deleted even if they are locked.

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 variant attributes this will be the endpoint GetVariantAttribute. This endpoint will provide you with information why the advanced attribute is missing, i.e. it will return an error message with the reason.

Attributes

It is possible to specify a set of attributes, which will be either linked to the product variant if they already exist or created and subsequently linked to the product variant. The attribute's name must refer to an attribute group of the variant level.

Parameters

ParameterDetails
id

Integer READ-ONLY

ID assigned by SCAYLE.

referenceKey

String

A key that uniquely identifies the variant of a product (usually an SKU) within the tenant's ecosystem.

ean

String

An ean that refers to a product variant .

attributes

Attribute

A list of attributes attached to the product variant.

prices

ProductVariantPrice

A list of prices attached to the product variant.

stocks

ProductVariantStock

The product variant stock information.

customDataCustomData
isCompositeREAD-ONLY

Boolean

Indicates whether the variant is composite.

relatedVariants

RelatedProductVariant

A list of variants that belong to the composite variant.

Examples

Update Product Variant Prices

let response = await adminApi.apis.Variants.getProductVariant({
  productIdentifier: 1,
  variantIdentifier: 1,
  with: "prices"
});

let productVariant = response.body;
let key = productVariant.prices.findIndex(price => price.groupKey === "myGroupKey");

productVariant.prices[key].price = 9999;

adminApi.apis.Variants.updateProductVariant(
  {productIdentifier: 1, variantIdentifier: productVariant.id},
  {requestBody: productVariant}
);

Update with Options

let response = await adminApi.apis.Variants.getProductVariant({
  productIdentifier: 1,
  variantIdentifier: 1,
  with: "attributes"
});

let productVariant = response.body;
let key = productVariant.attributes.findIndex(attribute => attribute.name === "size");

productVariant.attributes[key].value = "S";

client.apis.Variants.updateProductVariant(
  {productIdentifier: 1, variantIdentifier: productVariant.id, ignoreAttributeLocks: true},
  {requestBody: productVariant}
);

Delete product variant

Learn how to delete a variant using an identifier.

Deleting a product variant requires using one of two identifiers:

  • id
  • referenceKey

About this Method

This method can be used to delete an existing product variant along with all its dependencies.

This action can not be undone!

Method Signature

adminApi.apis.Variants.deleteProductVariant({productIdentifier: productIdentifier, variantIdentifier: variantIdentifier});

Examples

Delete by ID

Delete a product variant by id:

adminApi.apis.Variants.deleteProductVariant({productIdentifier: 1, variantIdentifier: 1});

Delete by Reference Key

Delete a product variant by reference key.

adminApi.apis.Variants.deleteProductVariant({productIdentifier: "key=product-key", variantIdentifier: "key=variant-key"});

Get product variant

You can request a product variant using unique identifiers.

About this Method

This method can be used to get an existing product variant either by using SCAYLE's internal ID or the user defined reference key.

This method allows you to include nested resources using the with parameter.

Method Signature

let response = await adminApi.apis.Variants.getProductVariant({productIdentifier: productIdentifier, variantIdentifier: variantIdentifier});
let productVariant = response.body;

Options

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

ParameterDetails
with

String

Allows to load the following nested resources within this request:

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

Parameters

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

Get a Product Variant by ID

let response = await adminApi.apis.Variants.getProductVariant({productIdentifier: 1, variantIdentifier: 1});
let productVariant = response.body;

Read with Options

Get a product variant with prices, attributes and custom data:

let response = await adminApi.apis.Variants.getProductVariant({
  productIdentifier: 1,
  variantIdentifier: 1,
  with: "prices,attributes,customData"
});

let productVariant = response.body;

productVariant.prices.forEach(
  price => console.log(price.price)
);
console.log(productVariant.customData)

Get a collection of product variant

Learn how to request a variant collection.

You can also request several product variants by using all respective identifiers at once. However, we suggest you to fine-tune your search, e.g., by combing filter logics and using pagination.

About this Method

This method can be used to get a collection of variants for any given product. It is possible to refine the search by applying filter options.

This method allows you to include nested resources using the with parameter.

Method Signature

let response = await adminApi.apis.Variants.getProductVariants({productIdentifier: productIdentifier});
let productVariants = response.body.entities;

Options

Product variant collection read can be used with optional parameters - called options:

ParameterDetails
with

String

Allows you to load the following nested resources within this request:

  • attributes
  • prices
  • customData
  • stocks
limit

Integer

Maximum number of items in the result. (default: 100, maximum: 1000)

filters[id]

String

Comma-separated list of product variant IDs that should be used for filtering.

filters[minId]

Integer

Minimum product variant ID of entities that should be returned.

filters[maxId]

Integer

Maximum product variant ID of entities that should be returned.

filters[minCreatedAt]

String

Minimum creation date of variants that should be returned.

filters[maxCreatedAt]

String

Maximum creation date of variants that should be returned.

filters[minUpdatedAt]

String

Minimum modification date of variants that should be returned.

filters[maxUpdatedAt]

String

Maximum modification date of variants that should be returned.

filters[attributes]

Object

This parameter allows you to filter for products with the given simple attributes.

The array/object key must be the attribute name. 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.

sort

String

Sort by the provided column. Available values: id.

sortDir

String

Defines the sorting order: ascending or descending. Available values: asc (default), desc.

Parameter

ParameterDetails
entities

ProductVariant

A collection of product variants.

cursor

Cursor

An object containing information for use in pagination.

Examples

Get a list of Product Variants

let response = await adminApi.apis.Variants.getProductVariants({productIdentifier: 1});
let productVariants = response.body.entities;

productVariants.forEach(
  productVariant => console.log(productVariant.referenceKey)
);

Read with Options

Get product variants filtered by size:

let response = await adminApi.apis.Variants.getProductVariants({productIdentifier: 1});
let productVariants = response.body.entities;

productVariants.forEach(
  productVariant => console.log(productVariant.referenceKey)
);

Create or Update a Variant Attribute

The method is used to create a variant attribute if it does not exist or update an existing variant attribute.

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 complex update example).

Method Signature

let response = await client.apis.Attributes.updateOrCreateProductVariantAttribute(
    {productIdentifier: productIdentifier, variantIdentifier: variantIdentifier},
    {requestBody: variantAttribute}
);

let createdVariantAttribute = response.body;

Options

ParameterDetails
ignoreAttributeLocks

Boolean

Force an update of attributes even if they are locked.

See this example for details on how to use options.

Create a simple variant attribute

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

let response = await client.apis.Attributes.updateOrCreateProductVariantAttribute(
    {productIdentifier: 1, variantIdentifier: 1},
    {requestBody: attribute}
);

let createdAttribute = response.body;

Create a simple list variant attribute

let attribute = {
    "name": "season",
    "type": "simpleList",
    "value": ["autumn", "winter"]
};

let response = await client.apis.Attributes.updateOrCreateProductVariantAttribute(
    {productIdentifier: 1, variantIdentifier: 1},
    {requestBody: attribute}
);

let createdAttribute = response.body;

Create a localized variant attribute

let attribute = {
    "name": "collection",
    "type": "localizedString",
    "value": {"de_DE": "einzigartig", "en_GB": "unique"}
};

let response = await client.apis.Attributes.updateOrCreateProductVariantAttribute(
    {productIdentifier: 1, variantIdentifier: 1},
    {requestBody: attribute}
);

let createdAttribute = response.body;

Create a localized list variant attribute

let attribute = {
    "name": "color",
    "type": "localizedStringList",
    "value": [
        {"de_DE": "weiß", "en_GB": "white"},
        {"de_DE": "schwarz", "en_GB": "black"}
    ]
};

let response = await client.apis.Attributes.updateOrCreateProductVariantAttribute(
    {productIdentifier: 1, variantIdentifier: 1},
    {requestBody: attribute}
);

let createdAttribute = response.body;

Create an advanced variant attribute

let attribute = {
    "name": "dimensions",
    "type": "advanced",
    "value": {
        "height": 100,
        "width": 30,
        "unit": "cm"
    }
};

let response = await client.apis.Attributes.updateOrCreateProductVariantAttribute(
    {productIdentifier: 1, variantIdentifier: 1},
    {requestBody: attribute}
);

let createdAttribute = response.body;

Create an advanced list variant attribute

let attribute = {
    "name": "material",
    "type": "advancedList",
    "value": [
        {
            "name": "wool",
            "percentage": 80
        },
        {
            "name": "cotton",
            "percentage": 20
        }
    ]   
};

let response = await client.apis.Attributes.updateOrCreateProductVariantAttribute(
    {productIdentifier: 1, variantIdentifier: 1},
    {requestBody: attribute}
);

let createdAttribute = response.body;

Update a simple variant attribute ignoring locks

let variantAttribute = {
    "name": "material",
    "type": "simple",
    "value": "cotton"
};

let response = await client.apis.Attributes.updateOrCreateProductVariantAttribute(
    {productIdentifier: 1, variantIdentifier: 2, ignoreAttributeLocks: true},
    {requestBody: variantAttribute}
);

let updatedVariantAttribute = response.body;

Create or update simple variant attributes; override attribute value for certain shop country

let shopCountrySpecificAttribute = {
    "shopKey": "ms",
    "countryCode": "de",
    "value": "polyester"
};

let variantAttribute = {
    "name": "material",
    "type": "simple",
    "value": "cotton",
    "shopCountrySpecific": [
        shopCountrySpecificAttribute
    ]
};

let response = await client.apis.Attributes.updateOrCreateProductVariantAttribute(
    {productIdentifier: 1, variantIdentifier: 2}, 
    {requestBody: variantAttribute}
);

let updatedProductAttribute = response.body;

Update locked simple variant attributes; unassign existing variants attributes with NULL

let variantAttribute = {
    "name": "material",
    "type": "simple",
    "value": "cotton",
    "shopCountrySpecific": []
};

let response = await client.apis.Attributes.updateOrCreateProductVariantAttribute(
    {productIdentifier: 1, variantIdentifier: 2, ignoreAttributeLocks: true},
    {requestBody: variantAttribute}
);

let updatedVariantAttribute = response.body;

Delete a Variant Attribute

Variant attributes are deleted along with the shop overrides.

client.apis.Attributes.deleteProductVariantAttribute({
    productIdentifier: productIdentifier,
    variantIdentifier: variantIdentifier,
    attributeGroupName: attributeGroupName
});

Options

The operation can be used with optional parameters - called options:

ParameterDetails
ignoreAttributeLocks

Boolean

Force attributes deletion even if they are locked.

Delete a Variant Attribute

client.apis.Attributes.deleteProductVariantAttribute({
    productIdentifier: 1,
    variantIdentifier: 2,
    attributeGroupName: "material"
});

Delete a variant attribute ignoring locks

client.apis.Attributes.deleteProductVariantAttribute({
    productIdentifier: 1,
    variantIdentifier: 2,
    attributeGroupName: "material",
    ignoreAttributeLocks: true
});

Get a Variant Attribute

In SCAYLE, you can request a variant attribute of the given group.

Method signature

let response = await client.apis.Attributes.getProductVariantAttribute({
    productIdentifier: productIdentifier, 
    variantIdentifier: variantIdentifier, 
    attributeGroupName: attributeGroupName
});

let variantAttribute = response.body;

Get a Variant Attribute

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

let variantAttribute = response.body;

Get a Collection of Variant Attributes

SCAYLE allows you to retrieve all attributes attached to a variant.

Method Signature

let response = await client.apis.Attributes.getProductVariantAttributes({
    productIdentifier: productIdentifier,
    variantIdentifier: variantIdentifier
});

let variantAttributes = response.body.entities;

Get a list of Variant Attributes

let response = await client.apis.Attributes.getProductVariantAttributes({productIdentifier: 1, variantIdentifier: 2});
let variantAttributes = response.body.entities;

Storefront API

Overview

You can retrieve a single variant or a list of variants based on their IDs.

Variants are the actual items/entities to be sold in a shop. Through the /variants endpoint variant specific information is retrieved (prices, available quantities, attributes).

In the product hierarchy, each product has one or more variants. These variants are the entities that customers buy online. Stock is managed on the variant-level. Variants differ from each other by defining attributes such as "size" or "pack-size".

When retrieving items from a wishlist or a basket, it is essential to keep in mind that the actual entity to be sold is the variant. Therefore, you should always be sure to retrieve not only the products themselves, but also the variants in question.

Get a Single Variant

Get a single variant by its ID.

Parameters

ParameterTypeDetails
variantsIdsNumberID of the variant to retrieve
withVariantWithContained as `with` inside the options object
campaignKeyStringUsed to get the correct prices for the specified campaign.
pricePromotionKeyStringAdjust variant price based on the specified pricePromotionKey. If the variant does not have a matching price promotion, the default price is returned.

Get Multiple Variants

When retrieving multiple variants by their IDs, you can specify their properties like stock and also retrieve prices relevant to a particular campaign or promotion.

Parameters

ParameterTypeDetails
variantsIdsNumberID of the variant to retrieve
withVariantWithContained as `with` inside the options object
campaignKeyStringUsed to get the correct prices for the specified campaign.
pricePromotionKeyStringAdjust variant price based on the specified pricePromotionKey. If the variant does not have a matching price promotion, the default price is returned.

Example

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

See Authentication for how to set up.

Get Variants

$variants = $client->variants->getByIds([1, 2, 3], [
  'with' => 'attributes,stock',
  'campaignKey' => 'promo_test_20'
])->entities;

$price = $variants[0]->price;
$savings = $price->appliedReductions[0]->amount["absoluteWithTax"];
$oldPrice = $savings + $price->withTax;

var_dump("Price: " . $price->withTax);
var_dump("Savings: " . $savings);
var_dump("Previous Price: " . $oldPrice);
// string(11) "Price: 3192"
// string(12) "Savings: 798"
// string(20) "Previous Price: 3990"
Response
[
  {
    "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": 3192,
      "withoutTax": 2682,
      "recommendedRetailPrice": null,
      "tax": { "vat": { "amount": 510, "rate": 0.19 } },
      "appliedReductions": [
        {
          "category": "campaign",
          "type": "relative",
          "amount": { "relative": 0.2, "absoluteWithTax": 798 }
        }
      ]
    },
    "customData": { "deliveryEstimate": [] },
    "productId": 1
  },
  {
    "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": 3192,
      "withoutTax": 2682,
      "recommendedRetailPrice": null,
      "tax": { "vat": { "amount": 510, "rate": 0.19 } },
      "appliedReductions": [
        {
          "category": "campaign",
          "type": "relative",
          "amount": { "relative": 0.2, "absoluteWithTax": 798 }
        }
      ]
    },
    "customData": {},
    "productId": 1
  },
  {
    "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": 3192,
      "withoutTax": 2682,
      "recommendedRetailPrice": null,
      "tax": { "vat": { "amount": 510, "rate": 0.19 } },
      "appliedReductions": [
        {
          "category": "campaign",
          "type": "relative",
          "amount": { "relative": 0.2, "absoluteWithTax": 798 }
        }
      ]
    },
    "customData": {},
    "productId": 1
  }
]