Working with product models using the API
A guide in how to digest and use a product model
Getting started
Below is an example in JSON format, showcasing the size of the product structure model when attempting to create one through the /v1/productstructures
endpoint.
POST /v1/productstructures
There is a lot to digest and in the following segment we will break the model into smaller pieces making it easier to digest. To start off, we will demonstrate a general example where we focus on configuring the layout of products under the product structure. For a more detailed explanation of each property and their child attributes you can read the API documentation for the ProductStructure-endpoints.
Product structure model
public class ProductStructure
{
public Guid Uid { get; set; }
public string? Alias { get; set; }
public string? Label { get; set; }
public bool HasVariants { get; set; }
public bool HasVariantGroups { get; set; }
public ProductConfiguration? ProductConfiguration { get; set; }
public VariantGroupConfiguration? VariantGroupConfiguration { get; set; }
public VariantConfiguration? VariantConfiguration { get; set; }
public List<VariationDefinition>? VariationDefinitions { get; set; }
public List<Guid>? AlwaysOnDefiningAttributes { get; set; }
public List<IdentifierDefinition>? ProductIdentifierDefinitions { get; set; }
public List<IdentifierDefinition>? VariantGroupIdentifierDefinitions { get; set; }
public List<IdentifierDefinition>? VariantIdentifierDefinitions { get; set; }
}
Above you can see the class ProductStructure
and all the content within. Not all is required for setting up a product structure.
We begin by creating an instance of the class ProductStructure
and defining the label
and alias
, along with a unique Uid
so that it is easily identifiable. As this structure does not contain variants, HasVariants
and HasVariantGroups
are set to false
.
ProductStructure productStructure = new ProductStructure()
{
Uid = Guid.NewGuid(),
Alias = "ClothingDemo",
Label = "ClothingDemo",
HasVariants = false,
HasVariantGroups = false,
ProductConfiguration = new ProductConfiguration
{
...
},
...
}
Product configuration
Setting up ProductConfiguration will define the layout of the products following this structure. The properties you will be working with here are:
ThumbnailReference
: Refers to a media attribute which holds image the image which should be presented as thumbnail for the product.NameConfiguration
: Contains NamePattern and NameAttributes which will define how names are generated for products following this structure.CreateWizard
: Step wizard presentation for data fulfillment when creating a product following this structure.CopyWizard
: Step wizard presentation for data fulfillment when copying a product following this structure.Tabs
: Contains the tabs which shall be shown on products following this product configuration in the backoffice. Also containssections
which contains the properties that should be displayed on each product.
To keep the example simple the wizard properties will not be used along with the thumbnail reference.
Name configuration
ProductConfiguration = new ProductConfiguration
{
NameConfiguration = new NameConfiguration
{
NamePattern = "{0} - {1}",
NameAttributes = new List<Guid>
{
new Guid("74a43fc6-63b1-4743-aa1e-816a8133b4c1"),
new Guid("de5572ed-1fb5-4192-a9ca-db73140f4cf5")
}
},
...
}
The property NameConfiguration
consists of a along with a list of named attributes. Together they define how each product should be named and it is important for the NamePattern
to match the number of attributes in NameAttributes
as seen in the example above.
The Guid
assigned is a previously created attribute which we have fetched using the following Attributes endpoint /v1/attributes.
Tabs
Tabs = new List<TabSetup>
{
new DynamicTabSetup
{
Uid = Guid.NewGuid(),
Label = "General",
Sections = new List<SectionSetup>
{
...
}
},
...
}
After setting up the NameConfiguration
, the next step is to define the tabs and their layout.
Since TabSetup
is an abstract class, you must use a class that inherits from it. In this case, we use DynamicTabSetup
, which defines the layout of a single tab.
Each tab must be uniquely identifiable, which is done by assigning a new Guid
to the Uid
property. The visible name of the tab is defined through the Label
property. Inside each tab, we configure one or more sections using the Sections
property.
Here is an example setup:
Tabs = new List<TabSetup>
{
new DynamicTabSetup
{
Uid = Guid.NewGuid(),
Label = "General",
Sections = new List<SectionSetup>
{
new DynamicSectionSetup
{
Uid = Guid.NewGuid(),
Headline = "General information",
Properties = new List<PropertySetup>
{
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("de5572ed-1fb5-4192-a9ca-db73140f4cf5") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("c28af57f-7f8e-413c-909b-fea67ef42b25") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("74a43fc6-63b1-4743-aa1e-816a8133b4c1") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("f886acd6-1397-4004-aba0-a3b2d6180151") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("2c19e970-77e2-45db-9508-925082684081") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("e2342c65-3def-4f57-9fe7-3fe9d3f093ed") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("04b4f1b6-7240-44ac-a631-bca618c0f8b8") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("45e8b8b2-bf4a-4c85-92c9-db70cedcac9a"), ReadOnly = true },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("ccfcffdf-236a-4740-9009-c7cb25365a27") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("a7522788-ad62-4759-83a6-d8ef2bdb75db") }
}
},
...
}
},
...
}
Sections
Setting up a section is similar to setting up a tab. The main differences are:
A section uses the
Headline
property instead ofLabel
.Sections define a list of properties, each of which maps to a specific attribute.
Each property within a section is configured using a class such as AttributeSetup
, and references an attribute via its AttributeUid
. These attribute UIDs can be retrieved using the Attributes endpoint from the API.
When defining a property, you can also configure the behavior through the following properties:
ReadOnly
Mandatory
Unchangeable
Inherits
These are all boolean values that control how the property behaves in the UI. In the example above, we have set ReadOnly = true
on one of the properties.
Each property also gets a unique Uid
.
Once you have defined the layout for one tab, adding additional tabs follow the same structure. Here is an example of what it would look like with multiple tabs:
ProductStructure productStructure = new ProductStructure()
{
Uid = Guid.NewGuid(),
Alias = "ClothingDemo",
Label = "ClothingDemo",
HasVariants = false,
HasVariantGroups = false,
ProductConfiguration = new ProductConfiguration
{
NameConfiguration = new NameConfiguration
{
NamePattern = "{0} - {1}",
NameAttributes = new List<Guid>
{
new Guid("74a43fc6-63b1-4743-aa1e-816a8133b4c1"),
new Guid("de5572ed-1fb5-4192-a9ca-db73140f4cf5")
}
},
Tabs = new List<TabSetup>
{
new DynamicTabSetup
{
Uid = Guid.NewGuid(),
Label = "General",
Sections = new List<SectionSetup>
{
new DynamicSectionSetup
{
Uid = Guid.NewGuid(),
Headline = "General information",
Properties = new List<PropertySetup>
{
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("de5572ed-1fb5-4192-a9ca-db73140f4cf5") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("c28af57f-7f8e-413c-909b-fea67ef42b25") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("74a43fc6-63b1-4743-aa1e-816a8133b4c1") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("f886acd6-1397-4004-aba0-a3b2d6180151") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("2c19e970-77e2-45db-9508-925082684081") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("e2342c65-3def-4f57-9fe7-3fe9d3f093ed") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("04b4f1b6-7240-44ac-a631-bca618c0f8b8") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("45e8b8b2-bf4a-4c85-92c9-db70cedcac9a"), ReadOnly = true },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("ccfcffdf-236a-4740-9009-c7cb25365a27") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("a7522788-ad62-4759-83a6-d8ef2bdb75db") }
}
},
...
}
},
new DynamicTabSetup
{
Uid = Guid.NewGuid(),
Label = "Media",
Sections = new List<SectionSetup>
{
new DynamicSectionSetup
{
Uid = Guid.NewGuid(),
Headline = "Images",
Properties = new List<PropertySetup>
{
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("2380b93c-9a98-4321-a18e-dabb628e5958") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("80156c4b-bd7f-447d-b8ea-93d84da86a87") }
}
},
...
}
},
...
}
},
...
}
From here we can proceed to define the product identifier definitions. The definition will configure how the identifiers of products following the structure should be generated.
Product identifier definitions
Now we just need to add the ProductIdentifierDefinitions
, where we configure the identifier(s) for the products using this product structure.
ProductIdentifierDefinitions = new List<IdentifierDefinition>
{
new IdentifierDefinition
{
Uid = Guid.NewGuid(),
Alias = "ModelNumber",
IdentifierPattern = "{0}",
IdentifierAttributes = new List<Guid>
{
new Guid("74a43fc6-63b1-4743-aa1e-816a8133b4c1")
}
}
},
In the example above, we have added a ProductIdentifierDefinitions
collection containing a single IdentifierDefinition
.
Each identifier definition includes:
A unique
Uid
An
Alias
to distinguish it from other definitionsAn
IdentifierPattern
used to construct the identifier stringA list of
IdentifierAttributes
whose values are used in the pattern
In this case, the pattern is simply {0}
, and the single attribute used is the one with the GUID 74a43fc6-63b1-4743-aa1e-816a8133b4c1
, which represents the ModelNumber attribute in the PIM. This means the generated product identifier will directly reflect the value of the ModelNumber attribute.
With this you now have a model setup which you can use to create a product structure inside the PIM.
Example of wizard use and permission
In this section, we will demonstrate how to configure both the CreateWizard
and CopyWizard
for guiding the user when creating or copying a product in backoffice. We will also cover the use and set up of view and save permissions on individual tabs.
Wizard create and copy
The step wizard setup enables a guided, step-by-step flow for entering product data. This improves data consistency and user experience in the PIM backoffice.
Both CreateWizard
and CopyWizard
share the same structure, so we will focus on the CreateWizard
example below:
ProductConfiguration = new ProductConfiguration
{
NameConfiguration = new NameConfiguration
{
NamePattern = "{0}",
NameAttributes = new List<Guid>
{
new Guid("de5572ed-1fb5-4192-a9ca-db73140f4cf5")
}
},
CreateWizard = new WizardSetup
{
Uid = Guid.NewGuid(),
Steps = new List<WizardStepSetup>
{
new DynamicWizardStepSetup
{
Uid = Guid.NewGuid(),
Headline = "Step 1",
Description = "Basic product details",
Properties = new List<WizardPropertySetup>
{
new AttributeWizardPropertySetup
{
Uid = new Guid("30995d23-9492-4467-ab13-faa565afd579"),
PropertyUid = newGuid, Mandatory = true
},
...
}
},
...
}
},
CopyWizard = new WizardSetup
{
Uid = Guid.NewGuid(),
Steps = new List<WizardStepSetup>
{
new DynamicWizardStepSetup
{
Uid = Guid.NewGuid(),
Headline = "Step A",
Description = "Select base product",
Properties = new List<WizardPropertySetup>
{
new AttributeWizardPropertySetup
{
Uid = Guid.NewGuid(),
PropertyUid = new Guid("30995d23-9492-4467-ab13-faa565afd579"),
Mandatory = true
},
...
}
},
...
}
},
...
}
The wizard setup contains:
A
Uid
for identificationA list of
Steps
(WizardStepSetup
instances)
Each step includes:
A
Uid
,Headline
, andDescription
to define the stepA list of
Properties
of typeWizardPropertySetup
They are inherited by
AttributeWizardPropertySetup
, which includes:Uid
— unique identifier for the wizard propertyPropertyUid
— references a property UID from theSectionSetup
(can be found via API)Mandatory
— marks the field as required
View and save permission
You can define view and save permissions on multiple levels within the product structure, including:
Tabs
Sections
Individual Properties
These permissions ensure that only users with the correct access rights (fetched using the /v1/permissions
endpoint) can view or modify specific UI components.
Here is an example of permission setup on a tab:
Tabs = new List<TabSetup>
{
new DynamicTabSetup
{
Uid = Guid.NewGuid(),
Label = "General",
ViewPermission = new Guid("313e11e2-e2e4-4a82-82a0-f68ec8682522"),
SavePermission = new Guid("e3d4c882-517c-4d89-9337-8a0b74d09b54"),
Sections = new List<SectionSetup>
{
new DynamicSectionSetup
{
Now, to view or save the tab, the user must have the required permission that has been set.
Example of product structure with variants
In this example we will focus on adding variants as well as variant groups to our product structure.
To create a product structure that support variants, we must set HasVariants = true
and provide a VariantConfiguration
object. We do the same for VariantGroupConfiguration.
Additionally, we define VariationDefinitions
, which specify how variants are structured based on certain attributes like size, color, etc.
VariantConfiguration = new VariantConfiguration
{
Tabs = new List<TabSetup>
{
new DynamicTabSetup
{
Uid = Guid.NewGuid(),
Label = "VariantTab",
Sections = new List<SectionSetup>
{
new DynamicSectionSetup
{
Uid = Guid.NewGuid(),
Headline = "Variant Information",
Properties = new List<PropertySetup>
{
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("de5572ed-1fb5-4192-a9ca-db73140f4cf5") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("17c5eca3-a439-42b2-95df-8d4e82d1f16b") },
new AttributeSetup { Uid = Guid.NewGuid(), AttributeUid = new Guid("74a43fc6-63b1-4743-aa1e-816a8133b4c1") }
}
},
...
}
},
...
}
}
Above you can see we have set up VariantConfiguration
just like ProductConfiguration
. The main difference is that it does not contain NameConfiguration
.
Variant definitions
To support dynamic variant structures, we define one or more VariationDefinitions
. Each defines how variants are differentiated based on selected attributes.
VariationDefinitions = new List<VariationDefinition>
{
new VariationDefinition
{
Uid = Guid.NewGuid(),
Name = "DemoNew",
Alias = "DemoNew",
NameConfiguration = new NameConfiguration
{
NamePattern = "{0}",
NameAttributes = new List<Guid>
{
new Guid("17c5eca3-a439-42b2-95df-8d4e82d1f16b")
}
},
DefiningAttributes = new List<Guid>
{
new Guid("17c5eca3-a439-42b2-95df-8d4e82d1f16b")
},
SortOrder = 0
},
...
}
This example defines a single variation definition based on the Color attribute. The NameConfiguration
ensures each variant’s name will be based on that attribute’s value.
Always on defining attributes
Defining attributes are typically only available to variants if they are included in a specific VariationDefinition
. However, there are cases where you may want certain attributes, like size, color, or SKU, to always be available for all variants, regardless of how the variations are defined.
The AlwaysOnDefiningAttributes
property allows you to specify a set of defining attributes that are always included for every variant following the product structure.
In the example we have SKU as our AlwaysOnDefiningAttributes
. If we want other options like name or StyleNumber, we would have to expand the VariantDefinition
to contain those attributes before being able to assign them as an always show defining attribute.
AlwaysOnDefiningAttributes = new List<Guid>
{
new Guid("17c5eca3-a439-42b2-95df-8d4e82d1f16b")
}
Variant identifier definitions
When setting up the VariantConfiguration
in the product structure, you also have the option to specify identifier definitions, just like you do for the product itself.
VariantIdentifierDefinitions = new List<IdentifierDefinition>
{
new IdentifierDefinition
{
Uid = Guid.NewGuid(),
Alias = "SKU",
IdentifierPattern = "{0}",
IdentifierAttributes = new List<Guid>
{
new Guid("17c5eca3-a439-42b2-95df-8d4e82d1f16b")
}
},
...
}
Below is a similar setup for variant groups, configured using the VariantGroupConfiguration
. Variant groups help organize and manage variants that share common characteristics like color.
When looking at the VariantGroupConfiguration
model below, you can see that it includes a property called GroupingAttributes
. This property is a list of attribute GUIDs from the PIM, used to determine how variants are grouped. In this case, the attribute is color, meaning variants will be grouped by color.
VariantGroupConfiguration = new VariantGroupConfiguration
{
GroupingAttributes = new List<Guid>
{
new Guid("c3fbf795-79be-4ab0-ae7d-e264b8227b88")
},
NameConfiguration = new NameConfiguration
{
NamePattern = "{0}",
NameAttributes = new List<Guid>
{
new Guid("c3fbf795-79be-4ab0-ae7d-e264b8227b88")
}
},
Tabs = new List<TabSetup?>
{
new DynamicTabSetup
{
Uid = Guid.NewGuid(),
Label = "VariantGroupTab",
Sections = new List<SectionSetup>
{
new DynamicSectionSetup
{
Uid = Guid.NewGuid(),
Headline = "Variant Group Information",
Properties = new List<PropertySetup>
{
new AttributeSetup { AttributeUid = new Guid("c3fbf795-79be-4ab0-ae7d-e264b8227b88") },
new AttributeSetup { AttributeUid = new Guid("f0a0cc7b-1dbf-4b55-bb20-a2004400811c") }
}
},
...
}
},
...
}
}
Variant group identifier definitions
Just like products and variants, VariantGroupConfiguration
can also include identifier definitions. These definitions allow you to generate unique identifiers (e.g., group StyleNumbers or codes) for variant groups based on selected attributes.
VariantGroupIdentifierDefinitions = new List<IdentifierDefinition>
{
new IdentifierDefinition
{
Uid = Guid.NewGuid(),
Alias = "StyleNumber",
IdentifierPattern = "{0}",
IdentifierAttributes = new List<Guid>
{
new Guid("f0a0cc7b-1dbf-4b55-bb20-a2004400811c")
}
}
}
Last updated