# Create Attribute Set

Creates a new attribute set for the tenant from the supplied name and optional Product and Variant form layouts, returning the created attribute set and a Location header pointing to it.

The Product and Variant layouts behave differently when omitted: an omitted productLayout falls back to a standard default layout, whereas an omitted variantLayout is not created at all (no Variant layout is stored). A Variant layout can be added later with PATCH /v2/AttributeSets({id}).

## Authentication

Requires a valid API key in the X-API-KEY header.

## Request Body

| Field           | Required | Description                                                                               |
|-----------------|----------|-------------------------------------------------------------------------------------------|
| name            | ✅ Yes   | Unique name for the attribute set within the tenant.                                     |
| productLayout   | ❌ No    | Form layout for Products. Defaults to the standard layout when omitted.                   |
| variantLayout   | ❌ No    | Form layout for Variants. When omitted, no Variant layout is created (it can be added later via PATCH). |

## Layout Structure

Each layout is a JSON document with a sections array. Each section has a title and a rows array. Each row has a fields array and an optional divider (dividerType, dividerTitle). Each field carries an attributeId and a size.

```json
{
  "sections": [
    {
      "title": "General",
      "rows": [
        {
          "fields": [
            { "attributeId": "prod_title", "size": "half" },
            { "attributeId": "prod_ref",   "size": "half" }
          ]
        },
        {
          "dividerType": "normal",
          "dividerTitle": "Details",
          "fields": [
            { "attributeId": "prod_description", "size": "row" }
          ]
        }
      ]
    }
  ]
}
```

size — width of the field in the form grid. One of: quarter, half, threeQuarters, row.

dividerType — optional visual separator above the row. One of: normal, wide, lineBreak. dividerTitle is optional and only meaningful when dividerType is set. Both properties are omitted from rows that have no divider.

## Layout Validation

A layout may contain any subset of the tenant's valid attributes — you do not need to include all of them. Attributes omitted from the layout simply do not appear in the form for this attribute set; they are not removed from the tenant.

If a layout is supplied it must satisfy all of the following rules; otherwise the request returns 400 Bad Request describing each failure:

- The layout must be well-formed: the sections, rows and fields arrays must all be present (non-null). Omitting a sections, rows or fields array (or sending it as null) is rejected.
- Every attributeId included must exist for the entity type (Products or Variants) in the tenant's storage definition.
- No attributeId may appear more than once across the entire layout.
- Each field size must be one of: quarter, half, threeQuarters, row.
- The sum of field sizes within any single row must not exceed a full row.
- Every row must contain at least one field.
- Section title values must be unique (case-insensitive).
- When a row sets dividerType it must be one of: normal, wide, lineBreak.

### Required attributes

These attributes must always be present in their respective layout:

| Layout         | Required attribute IDs                                                                                       |
|----------------|--------------------------------------------------------------------------------------------------------------|
| productLayout  | typ_id, prod_ref, prod_title, cat_ref, prod_stat, prod_description, prod_image, prod_tags                    |
| variantLayout  | frmt_stat, prod_ref, frmt_ref, frmt_tags                                                                    |

## Response

201 Created — The Location header points to the new resource: /v2/AttributeSets({id}). The response body contains the created attribute set (CreateAttributeSet2Response).

## Error Responses

- 400 Bad Request — Missing body, missing name, duplicate name, or layout validation failure.
- 401 Unauthorized — Missing or invalid tenant identifier.
- 500 Internal Server Error — Unexpected technical error.

## Example

Request:
```
POST /v2/AttributeSets HTTP/1.1
X-API-KEY: your-api-key-here
Content-Type: application/json

{ "name": "Electronics" }
```

Response:
```
HTTP/1.1 201 Created
Location: /v2/AttributeSets(7)
```

### Endpoint: POST /v2/AttributeSets
### Version: 2.0.0

## Request fields (application/json):

- `name` (string,null)

- `productLayout` (object)
    Example: {"sections":[{"title":"General","rows":[{"fields":[{"attributeId":"code","size":"half"},{"attributeId":"name","size":"half"}]},{"fields":[{"attributeId":"parent_ref","size":"row"}],"dividerType":"normal","dividerTitle":"Hierarchy"}]}]}]}

- `productLayout.sections` (array,null)
    Example: [{"title":"General","rows":[{"fields":[{"attributeId":"code","size":"half"},{"attributeId":"name","size":"half"}]},{"fields":[{"attributeId":"parent_ref","size":"row"}],"dividerType":"normal","dividerTitle":"Hierarchy"}]}]}

- `productLayout.sections.title` (string,null)

- `productLayout.sections.rows` (array,null)

- `productLayout.sections.rows.fields` (array,null)

- `productLayout.sections.rows.fields.attributeId` (string,null)

- `productLayout.sections.rows.fields.size` (string)
    Enum: "quarter", "half", "threeQuarters", "row"

- `productLayout.sections.rows.dividerType` (string,null)
    Enum: "normal", "wide", "lineBreak"

- `productLayout.sections.rows.dividerTitle` (string,null)

- `variantLayout` (object)
    Example: {"sections":[{"title":"General","rows":[{"fields":[{"attributeId":"code","size":"half"},{"attributeId":"name","size":"half"}]},{"fields":[{"attributeId":"parent_ref","size":"row"}],"dividerType":"normal","dividerTitle":"Hierarchy"}]}]}]}

## Response 201 fields (application/json):

- `@readLink` (string,null)

- `@editLink` (string,null)

- `@etag` (string,null)

- `@navigationLinks` (array,null)

- `@navigationLinks.uri` (string,null)

- `@associationLinks` (array,null)

- `@associationLinks.uri` (string,null)

- `@context` (string,null)

- `value` (any,null)

## Response 400 fields (application/json):

- `validationFailures` (object,null)
    Example: {"Layout":[{"PropertyName":"Layout","ErrorMessage":"The layout must contain exactly the attributes of the stored layout. Missing: tags. Unknown: extra_field.","AttemptedValue":null}]}

## Response 401 fields (application/json):

- `type` (string,null)

- `title` (string,null)

- `status` (integer,null)

- `detail` (string,null)

- `instance` (string,null)

## Response 500 fields (application/json):

- `error` (string,null)

- `details` (any,null)
