# Working with product models using the API

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

{% tabs %}
{% tab title="HTTP" %}
**POST** /v1/productstructures
{% endtab %}

{% tab title="Request body (json)" %}

```

  "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
  "Alias": "string",
  "Label": "string",
  "HasVariants": true,
  "HasVariantGroups": true,
  "ProductConfiguration": {
    "ThumbnailReference": "string",
    "NameConfiguration": {
      "NamePattern": "string",
      "NameAttributes": [
        "3fa85f64-5717-4562-b3fc-2c963f66afa6"
      ]
    },
    "CreateWizard": {
      "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "Steps": [
        {
          "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "Headline": "string",
          "Description": "string"
        }
      ]
    },
    "CopyWizard": {
      "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "Steps": [
        {
          "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "Headline": "string",
          "Description": "string"
        }
      ]
    },
    "Tabs": [
      {
        "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "ViewPermission": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "SavePermission": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
      }
    ]
  },
  "VariantGroupConfiguration": {
    "GroupingAttributes": [
      "3fa85f64-5717-4562-b3fc-2c963f66afa6"
    ],
    "ThumbnailReference": "string",
    "NameConfiguration": {
      "NamePattern": "string",
      "NameAttributes": [
        "3fa85f64-5717-4562-b3fc-2c963f66afa6"
      ]
    },
    "CreateWizard": {
      "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "Steps": [
        {
          "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "Headline": "string",
          "Description": "string"
        }
      ]
    },
    "CopyWizard": {
      "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "Steps": [
        {
          "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "Headline": "string",
          "Description": "string"
        }
      ]
    },
    "Tabs": [
      {
        "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "ViewPermission": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "SavePermission": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
      }
    ]
  },
  "VariantConfiguration": {
    "ThumbnailReference": "string",
    "CreateWizard": {
      "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "Steps": [
        {
          "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
          "Headline": "string",
          "Description": "string"
        }
      ]
    },
    "Tabs": [
      {
        "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "ViewPermission": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "SavePermission": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
      }
    ]
  },
  "VariationDefinitions": [
    {
      "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "Alias": "string",
      "Name": "string",
      "NameConfiguration": {
        "NamePattern": "string",
        "NameAttributes": [
          "3fa85f64-5717-4562-b3fc-2c963f66afa6"
        ]
      },
      "DefiningAttributes": [
        "3fa85f64-5717-4562-b3fc-2c963f66afa6"
      ],
      "SortOrder": 0
    }
  ],
  "AlwaysOnDefiningAttributes": [
    "3fa85f64-5717-4562-b3fc-2c963f66afa6"
  ],
  "ProductIdentifierDefinitions": [
    {
      "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "Alias": "string",
      "IdentifierPattern": "string",
      "IdentifierAttributes": [
        "3fa85f64-5717-4562-b3fc-2c963f66afa6"
      ]
    }
  ],
  "VariantGroupIdentifierDefinitions": [
    {
      "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "Alias": "string",
      "IdentifierPattern": "string",
      "IdentifierAttributes": [
        "3fa85f64-5717-4562-b3fc-2c963f66afa6"
      ]
    }
  ],
  "VariantIdentifierDefinitions": [
    {
      "Uid": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
      "Alias": "string",
      "IdentifierPattern": "string",
      "IdentifierAttributes": [
        "3fa85f64-5717-4562-b3fc-2c963f66afa6"
      ]
    }
  ]
}
```

{% endtab %}
{% endtabs %}

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](/api-reference/endpoints/productstructures.md#post-v1-productstructures).

### Product structure model

{% code title="C#" overflow="wrap" %}

```csharp
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; }
}
```

{% endcode %}

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

{% code title="C#" overflow="wrap" %}

```csharp
ProductStructure productStructure = new ProductStructure()
{
    Uid = Guid.NewGuid(),
    Alias = "ClothingDemo",
    Label = "ClothingDemo",
    HasVariants = false,
    HasVariantGroups = false,

    ProductConfiguration = new ProductConfiguration
    {
        ...
    },
    ...
}
```

{% endcode %}

### 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 contains `sections` 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

{% code title="C#" overflow="wrap" %}

```csharp
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") 
        }
    },
    ...
}
```

{% endcode %}

The property  `NameConfiguration` consists of a [name pattern](#user-content-fn-1)[^1] 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.&#x20;

The `Guid` assigned is a previously created attribute which we have fetched using the following Attributes endpoint [/v1/attributes](/api-reference/endpoints/attributes.md#get-v1-attributes).

### Tabs

{% code title="C#" overflow="wrap" %}

```csharp
Tabs = new List<TabSetup>
{
    new DynamicTabSetup
    {
        Uid = Guid.NewGuid(),
        Label = "General",
        Sections = new List<SectionSetup>
        {
            ...
        }
    },
    ...
}
```

{% endcode %}

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:

{% code title="C#" overflow="wrap" %}

```csharp
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") }
                }
            },
            ...
        }
    },
    ...
}
```

{% endcode %}

### Sections

Setting up a section is similar to setting up a tab. The main differences are:

* A section uses the `Headline` property instead of `Label`.
* 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`.&#x20;

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:

{% code title="C#" overflow="wrap" %}

```csharp
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") }
                        }
                    },
                    ...
                }
            },
            ...
        }
    },
    ...
}
```

{% endcode %}

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.

{% code title="C#" overflow="wrap" %}

```csharp
ProductIdentifierDefinitions = new List<IdentifierDefinition>
{
    new IdentifierDefinition
    {
        Uid = Guid.NewGuid(),
        Alias = "ModelNumber",
        IdentifierPattern = "{0}",
        IdentifierAttributes = new List<Guid>
        {
            new Guid("74a43fc6-63b1-4743-aa1e-816a8133b4c1")
        }
    }
},
```

{% endcode %}

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 definitions
* An `IdentifierPattern` used to construct the identifier string
* A 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.

{% hint style="info" %}
**Tip** identifiers must be unique across value and alias. So be mindful when choosing the alias, identifier pattern and identifier attributes to avoid collisions.
{% endhint %}

## 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:

<pre class="language-csharp" data-title="C#" data-overflow="wrap"><code class="lang-csharp">ProductConfiguration = new ProductConfiguration
{
    NameConfiguration = new NameConfiguration
    {
        NamePattern = "{0}",
        NameAttributes = new List&#x3C;Guid>
        { 
            new Guid("de5572ed-1fb5-4192-a9ca-db73140f4cf5")
        }
    },
    CreateWizard = new WizardSetup
    {
        Uid = Guid.NewGuid(),
        Steps = new List&#x3C;WizardStepSetup>
        {
            new DynamicWizardStepSetup
            {
                Uid = Guid.NewGuid(),
                Headline = "Step 1",
                Description = "Basic product details",
                Properties = new List&#x3C;WizardPropertySetup>
                {
                    new AttributeWizardPropertySetup
                    {
                        Uid = new Guid("30995d23-9492-4467-ab13-faa565afd579"),
                        PropertyUid = newGuid, Mandatory = true
                    },
                    ...
                }
            },
            ...
        }
    },
    CopyWizard = new WizardSetup
    {
        Uid = Guid.NewGuid(),
        Steps = new List&#x3C;WizardStepSetup>
        {
            new DynamicWizardStepSetup
            {
                Uid = Guid.NewGuid(),
                Headline = "Step A",
                Description = "Select base product",
                Properties = new List&#x3C;WizardPropertySetup>
                {
                    new AttributeWizardPropertySetup
                    { 
                        Uid = Guid.NewGuid(),
<strong>                        PropertyUid = new Guid("30995d23-9492-4467-ab13-faa565afd579"),
</strong><strong>                        Mandatory = true
</strong><strong>                    },
</strong><strong>                    ...
</strong>                }
            },
            ...
        }
    },
    ...
}
</code></pre>

The wizard setup contains:

* A `Uid` for identification
* A list of `Steps` (`WizardStepSetup` instances)

Each step includes:

* A `Uid`, `Headline`, and `Description` to define the step
* A list of `Properties` of type `WizardPropertySetup`
  * They are inherited by `AttributeWizardPropertySetup`, which includes:
    * `Uid` — unique identifier for the wizard property
    * `PropertyUid` — references a property UID from the `SectionSetup` (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:

{% code title="C#" overflow="wrap" %}

```csharp

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
            {
```

{% endcode %}

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.

{% code title="C#" overflow="wrap" %}

```csharp
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") }
                    }
                },
                ...
            }
        },
        ...
    }
}

```

{% endcode %}

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.

{% code title="C#" overflow="wrap" %}

```csharp
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

    },
    ...
}
```

{% endcode %}

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.

{% code title="C#" overflow="wrap" %}

```csharp
AlwaysOnDefiningAttributes = new List<Guid>
{
    new Guid("17c5eca3-a439-42b2-95df-8d4e82d1f16b")
}
```

{% endcode %}

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

{% code title="C#" overflow="wrap" %}

```csharp
VariantIdentifierDefinitions = new List<IdentifierDefinition>
{
    new IdentifierDefinition
    {
        Uid = Guid.NewGuid(),
        Alias = "SKU",
        IdentifierPattern = "{0}",
        IdentifierAttributes = new List<Guid>
        {
            new Guid("17c5eca3-a439-42b2-95df-8d4e82d1f16b")
        }
    },
    ...
}
```

{% endcode %}

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.

{% code title="C#" overflow="wrap" %}

```csharp
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") }
                    }
                },
                ...
            }
        },
        ...
    }
}
```

{% endcode %}

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

{% code title="C#" overflow="wrap" %}

```csharp
VariantGroupIdentifierDefinitions = new List<IdentifierDefinition>
{
    new IdentifierDefinition
    {
        Uid = Guid.NewGuid(),
        Alias = "StyleNumber",
        IdentifierPattern = "{0}",
        IdentifierAttributes = new List<Guid>
        {
            new Guid("f0a0cc7b-1dbf-4b55-bb20-a2004400811c")
        }
    }
}
```

{% endcode %}

[^1]: {0} will render as your first nameAttribute, {1} as your second and so on. Alphanumeric characters are also allowed in the name pattern.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.struct.com/tutorials/guides/how-to-use-struct-pims-api/working-with-product-models-using-the-api.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
