openapi: 3.0.1
info:
 title: Sales Layer Catalog REST API
 version: 2.0.0
 description: >
 The Sales Layer Catalog REST API provides programmatic access to the catalog
 data managed in Sales Layer.

Use this reference to retrieve, filter, create, update, or delete products,
 variants, categories, attribute sets, custom entities, metadata, and
 changelog records. These endpoints support synchronization, enrichment,
 publishing, reporting, and other integration workflows across ecommerce
 platforms, ERPs, marketplaces, DAM systems, supplier systems, and internal
 tools.

Start with metadata endpoints when your integration needs to discover
 available fields and relationships, use pagination and filtering for large
 reads, and rely on changelogs for incremental synchronization whenever
 possible.
servers:
 \- url: https://api2.saleslayer.com/catalog
 description: Sales Layer Catalog API
paths:
 /AttributeSets:
 get:
 tags:
 \- Attribute Sets
 summary: Filter Attribute Sets
 description: "\\r\\n\\r\\n Filters the tenant's **Attribute Set** resources using OData query options ( **$select**, **$expand**, **$filter**, **$orderby**, **$skip**, **$top**, **$skipToken**). Result's paging is done using the default paging size options.\\r\\n \\r\\n\\r\\n\\r\\n **Parameters details**\\r\\n \\r\\n\\r\\n \\r\\n **\\r\\n _X-API-KEY_\\r\\n**\\r\\n \\r\\nCustom HTTP request header containing the API key used for authentication.\\r\\n \\r\\n \\r\\n\\r\\n **\\r\\n _Accept-Language_\\r\\n**\\r\\n \\r\\nStandard HTTP request header indicates the natural language and locale that the client prefers.\\r\\n \\r\\nIt can take one of the following values:\\r\\n \\r\\n **\*** : All the localized content is available in the result, regardless of the culture . This option is currently disabled.\\r\\n \\r\\n **_null_** : The content localized in the default culture is available in the result.\\r\\n \\r\\n **culture-code** : The content localized in the specified culture is available in the result.\\r\\n \\r\\n Specifying various culture codes or q-factor weighting are currently disabled.\\r\\n \\r\\n _Examples:_\\r\\n - Expression **es** returns the content localized in the culture **es**. \\r\\n \\r\\n - Expression **en-us** returns the content localized in the culture **en-us**.\\r\\n \\r\\n \\r\\n\\r\\n **\\r\\n _$select_\\r\\n**\\r\\n \\r\\nExpression describing the list of **Attribute Set** resource properties to be included in the result.\\r\\n \\r\\nThe full list of the available **Attribute Set** resource properties is available in the JSON schema returned by the **/AttributeSets/$metadata** endpoint.\\r\\n \\r\\nThe name of the **Attribute Set** resource properties (both implicit and custom properties) must be specified.\\r\\n \\r\\nCurrently, the API does not support selecting the properties of an embedded resource or the properties of a resource within an embedded collection.\\r\\n \\r\\nThe expression follows the format: **ATTRIBUTE\_SET\_PROPERTY1\_NAME{, ATTRIBUTE\_SET\_PROPERTY2\_NAME...}**.\\r\\n \\r\\n _Examples:_\\r\\n - Expression **typ\_title** includes in the result only the property **typ\_title** of the current resource ( **Attribute Set**).\\r\\n \\r\\n - Expression **typ\_stat,typ\_title** includes in the result only the properties **typ\_stat** and **typ\_title** of the current resource ( **Attribute Set**).\\r\\n \\r\\n \\r\\n\\r\\n **\\r\\n _$expand_\\r\\n**\\r\\n \\r\\nExpression describing the list of collections embedded in the **Attribute Set** resource ( **Products**) to be included in the result.\\r\\n \\r\\nBy default (if no value is supplied to this parameter), the result doesn't include the embedded collections ( **Products**).\\r\\n \\r\\nThe expression follows the format: **EMBEDDED\_COLLECTION\_OF\_RESOURCE1\_NAME{,EMBEDDED\_COLLECTION\_OF\_RESOURCE1\_NAME...}**.\\r\\n \\r\\nCurrently only the embedded collections are supported, not the embedded resources.\\r\\n \\r\\n _Examples:_\\r\\n - Expression **Products** includes in the result the number elements of the **Products** resource, embedded in the current resource ( **Attribute Set**).\\r\\n \\r\\n \\r\\n\\r\\n **\\r\\n _$filter_\\r\\n**\\r\\n \\r\\nExpression describing the filters applied to the resources included in the result.\\r\\n \\r\\nBy default (if no value is supplied to this parameter), no filters are applied\\r\\n \\r\\nCurrently, filtering on the nested resources properties is not supported.\\r\\n \\r\\nThe expression follows the ODATA version 4.01 URI conventions (http://docs.oasis-open.org/odata/odata/v4.01/odata-v4.01-part2-url-conventions.html).\\r\\n \\r\\n The following filter options are currently supported:\\r\\n \\r\\n - logical operators ( **eq**, **ne**, **gt**, **lt**, **ge**, **le**, **or**, **and**, **in**)\\r\\n \\r\\n - functions: string functions ( **contains**, **startswith**, **endswith**)\\r\\n \\r\\n Currently it supports only the operators and functions applied on the properties of the root resource ( **Category**).\\r\\n \\r\\n The logical operators/functions are applied over the data types of the corresponding properties in the filter criteria:\\r\\n \\r\\n - integer : _property\_of\_type\_integer lt -100_\\r\\n - big integer: _property\_of\_type\_big\_integer gt 10000_\\r\\n - double: _property\_of\_type\_double ge 0.31415926535897931e1_\\r\\n - decimal: _property\_of\_type\_decimal eq 12.34_\\r\\n - string: _property\_of\_type\_string eq 'Hello world!'_\\r\\n - date: _property\_of\_type\_date eq 2023-12-01_\\r\\n - date time offset: _property\_of\_type\_datetimeoffset lt 2012-12-03T07:16:23Z_ or _property\_of\_type\_datetimeoffset lt 2012-12-03T07:16:23+00:00_ or _property\_of\_type\_datetimeoffset lt 2012-12-03_\\r\\nFurther examples:\\r\\n \\r\\n - _contains(property1, 'stringValue1')_\\r\\n - _endswith(property1, 'stringValue1')_\\r\\n - _startswith(property1, 'stringValue1')_\\r\\n - _property1 in (value1, value2)_\\r\\n - _property1 gt integerValue1 and property2 eq 'stringValue1'_\\r\\n - _property1 gt integerValue1 or property2 eq 'stringValue1'_\\r\\n - _(property1 eq 'stringValue1' or property1 eq 'stringValue2') and (contains(property2, 'stringValue3') or startsWith(property3, 'stringValue4') or startsWith(property4, 'stringValue5'))_\\r\\n \\r\\n\\r\\n **\\r\\n _$orderby_\\r\\n**\\r\\n \\r\\nExpression describing the ordering applied to the properties of resources included in the result.\\r\\n \\r\\nBy default (if no value is supplied to this parameter), no sorting is applied.\\r\\n \\r\\nCurrently, ordering on multiple properties and ordering on embedded resources properties are not supported.\\r\\n \\r\\nThe expression follows the format: **RESOURCE\_PROPERTY\_NAME (asc)\|desc**. \\r\\n \\r\\n _Examples:_\\r\\n - Expression **typ\_title** orders the result **ascendingly** on the property **typ\_title** of the current resource ( **Attribute Set**).\\r\\n \\r\\n - Expression **typ\_title asc** orders the result **ascendingly** on the property **typ\_title** of the current resource ( **Attribute Set**).\\r\\n \\r\\n - Expression **typ\_stat desc** orders the result **descendingly** on the property **typ\_stat** of the current resource ( **Attribute Set**).\\r\\n \\r\\n \\r\\n\\r\\n **\\r\\n _$skip_\\r\\n**\\r\\n \\r\\nExpression setting up result's paging according to the **limit and offset paging strategy**.\\r\\n \\r\\nUsing this paging strategy involves using both **$skip** and **$top** parameters.\\r\\n \\r\\nWe recommend **limit and offset paging strategy** for the extraction of data where $orderby clauses needs to be applied to the data to be extracted.\\r\\n \\r\\n **limit and offset paging** is not as fast as the **continuation token paging**, but has 2 advantages over the later:\\r\\n \\r\\n - the possibility of applying sorting on the result;\\r\\n \\r\\n - a fine control over the data extracted.\\r\\n \\r\\nThe expression follows the format: NUMBER\_OF\_ITEMS\_TO\_BE\_SKIPPED\_IN\_THE\_RESULT. \\r\\n \\r\\nThe page size for the **Attribute Set** resource is limited by default to 100 items.\\r\\n \\r\\nThe paging is performed through resource ( **Attribute Set**), not through the resources in the embedded collections.\\r\\n \\r\\n _Examples:_\\r\\n - Expression **1000** returns the **Attribute Set** items starting from the 1001st element in the result.\\r\\n \\r\\n \\r\\n\\r\\n **\\r\\n _$skipToken_\\r\\n**\\r\\n \\r\\nExpression setting up the continuation token used in paging the result.\\r\\n \\r\\nThe expression follows the format: \[CONTINUATION\_TOKEN\]. \\r\\n \\r\\nThe page size for the **Attribute Set** resource is limited to 1 item.\\r\\n \\r\\nThe paging is performed through resource ( **Attribute Set**), not through the resources in the embedded collections.\\r\\n \\r\\n _Examples:_\\r\\n - Expression **123456789** limits the **Attribute Set** items to the **next default** number of items, starting from the continuation token **123456789**.\\r\\n \\r\\n \\r\\n\\r\\n **\\r\\n _$top_\\r\\n**\\r\\n \\r\\nExpression setting up the number of items in the result.\\r\\n \\r\\nThe expression follows the format: \[PAGE\_SIZE\]. \\r\\n \\r\\nThe page size for the **Attribute Set** resource is limited to 1 item.\\r\\n \\r\\nThe paging is performed through resource ( **Attribute Set**), not through the resources in the embedded collections.\\r\\n \\r\\n _Examples:_\\r\\n - Expression **10** limits the **Attribute Set** items to the first 10 elements, given the other filter, sorting and paging criteria.\\r\\n \\r\\n \\r\\n\\r\\n **See also:** A newer version of this endpoint is available at **GET /v2/AttributeSets**.\\r\\n The v2 endpoint returns a structured response ( **GetAttributeSetsResponse**) that includes form layout configuration ( **ProductLayout**, **VariantLayout**) and is not interchangeable with the OData-style response returned by this endpoint.\\r\\n \\r\\n"
 operationId: FilterAttributeSetsAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: The localization cultures
 schema:
 type: string
 \- name: $filter
 in: query
 schema:
 type: string
 \- name: $orderby
 in: query
 schema:
 type: string
 \- name: $skip
 in: query
 schema:
 type: integer
 format: int64
 \- name: $skipToken
 in: query
 schema:
 type: string
 \- name: $top
 in: query
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '403':
 description: Forbidden
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /AttributeSets({attributeSetIdentifier}):
 get:
 tags:
 \- Attribute Sets
 summary: Get Attribute Set
 description: "\\r\\n\\r\\n Returns a single **Attribute Set** resource by its identifier, using OData query options ( **$select**, **$expand**) to shape the result.\\r\\n \\r\\n\\r\\n\\r\\n **Parameters details**\\r\\n \\r\\n\\r\\n \\r\\n **\\r\\n _X-API-KEY_\\r\\n**\\r\\n \\r\\nCustom HTTP request header containing the API key used for authentication.\\r\\n \\r\\n \\r\\n\\r\\n **\\r\\n _Accept-Language_\\r\\n**\\r\\n \\r\\nStandard HTTP request header indicates the natural language and locale that the client prefers.\\r\\n \\r\\nIt can take one of the following values:\\r\\n \\r\\n **\*** : All the localized content is available in the result, regardless of the culture . This option is currently disabled.\\r\\n \\r\\n **_null_** : The content localized in the default culture is available in the result.\\r\\n \\r\\n **culture-code** : The content localized in the specified culture is available in the result.\\r\\n \\r\\n Specifying various culture codes or q-factor weighting are currently disabled.\\r\\n \\r\\n _Examples:_\\r\\n - Expression **es** returns the content localized in the culture **es**. \\r\\n \\r\\n - Expression **en-us** returns the content localized in the culture **en-us**.\\r\\n \\r\\n \\r\\n\\r\\n **\\r\\n _$select_\\r\\n**\\r\\n \\r\\nExpression describing the list of **Attribute Set** resource properties to be included in the result.\\r\\n \\r\\nThe full list of the available **Attribute Set** resource properties is available in the JSON schema returned by the **/AttributeSets/$metadata** endpoint.\\r\\n \\r\\nThe name of the **Attribute Set** resource properties (both implicit and custom properties) must be specified.\\r\\n \\r\\nCurrently, the API does not support selecting the properties of an embedded resource or the properties of a resource within an embedded collection.\\r\\n \\r\\nThe expression follows the format: **ATTRIBUTE\_SET\_PROPERTY1\_NAME{, ATTRIBUTE\_SET\_PROPERTY2\_NAME...}**.\\r\\n \\r\\n _Examples:_\\r\\n - Expression **typ\_title** includes in the result only the property **typ\_title** of the current resource ( **Attribute Set**).\\r\\n \\r\\n - Expression **typ\_stat,typ\_title** includes in the result only the properties **typ\_stat** and **typ\_title** of the current resource ( **Attribute Set**).\\r\\n \\r\\n \\r\\n\\r\\n **\\r\\n _$expand_\\r\\n**\\r\\n \\r\\nExpression describing the list of collections embedded in the **Attribute Set** resource ( **Products**) to be included in the result.\\r\\n \\r\\nBy default (if no value is supplied to this parameter), the result doesn't include the embedded collections ( **Products**).\\r\\n \\r\\nThe expression follows the format: **EMBEDDED\_COLLECTION\_OF\_RESOURCE1\_NAME{,EMBEDDED\_COLLECTION\_OF\_RESOURCE1\_NAME...}**.\\r\\n \\r\\nCurrently only the embedded collections are supported, not the embedded resources.\\r\\n \\r\\n _Examples:_\\r\\n - Expression **Products** includes in the result the number elements of the **Products** resource, embedded in the current resource ( **Attribute Set**).\\r\\n \\r\\n \\r\\n\\r\\n **See also:** A newer version of this endpoint is available at **GET /v2/AttributeSets({id})**.\\r\\n The v2 endpoint returns a typed response with form layout details ( **ProductLayout**, **VariantLayout**) and differs in structure from this endpoint.\\r\\n \\r\\n"
 operationId: SearchAttributeSetAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: The localization cultures
 schema:
 type: string
 \- name: attributeSetIdentifier
 in: path
 description: Attribute Set resource identifier
 required: true
 schema:
 type: integer
 format: int32
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '403':
 description: Forbidden
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /AttributeSets({attributeSetIdentifier})/Products:
 get:
 tags:
 \- Attribute Sets
 summary: Filter Attribute Set Products
 description: "Filters and returns a paginated collection of Product resources scoped to the given Attribute Set, using OData query options.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for localized content.\\r\\n- \*\*omitted / null\*\*: content in the tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): content localized in the specified culture.\\r\\n- \*\*\`\*\`\*\* and q-factor weighting are currently not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\n### $select\\r\\n \\r\\nComma-separated list of root-resource property names to include in the response.\\r\\nSee \`/Products/$metadata\` for the available properties.\\r\\nSelecting properties of embedded resources is not supported.\\r\\n \\r\\nExample: \`$select=prod\_description,prod\_tags\`\\r\\n \\r\\n### $expand\\r\\n \\r\\nComma-separated list of embedded collections to include (e.g. \`Variants\`).\\r\\nBy default, embedded collections are not included.\\r\\nOnly embedded collections (not embedded resources) are supported.\\r\\n \\r\\nExample: \`$expand=Variants\`\\r\\n \\r\\n### $filter\\r\\n \\r\\nOData v4.01 URI conventions. Filtering is restricted to properties of the root resource (Product).\\r\\n \\r\\n\*\*Comparison operators:\*\* \`eq\`, \`ne\`, \`gt\`, \`ge\`, \`lt\`, \`le\`\\r\\n \\r\\n\*\*Logical operators:\*\* \`and\`, \`or\`, \`not\`\\r\\n \\r\\n\*\*Set operator:\*\* \`in\`\\r\\n \\r\\n\*\*String functions:\*\* \`contains\`, \`startswith\`, \`endswith\`\\r\\n \\r\\nExamples:\\r\\n- \`$filter=prod\_ref eq 'SKU-001'\`\\r\\n- \`$filter=contains(prod\_description, 'pro')\`\\r\\n- \`$filter=prod\_id gt 100 and contains(prod\_description, 'pro')\`\\r\\n \\r\\n### $orderby\\r\\n \\r\\nSingle property, ascending by default. Multi-property ordering and ordering on embedded\\r\\nproperties are not supported.\\r\\n \\r\\nExamples:\\r\\n- \`$orderby=prod\_description\`\\r\\n- \`$orderby=prod\_ref desc\`\\r\\n \\r\\n### Pagination — $top, $skip, $skipToken\\r\\n \\r\\n- \`$top\` — maximum number of items returned.\\r\\n- \`$skip\` — number of items to skip (offset paging).\\r\\n- \`$skipToken\` — continuation-token paging. Recommended when no \`$orderby\` is applied\\r\\n (faster than offset paging).\\r\\n \\r\\nPaging applies only to the root resource (Product), never to embedded collections.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — \`CollectionRepresentation\` with the matching Product resources, pagination\\r\\nmetadata (\`Count\`, \`Skip\`, \`Top\`, \`HasNext\`, continuation token) and the cultures echoed\\r\\nfrom \`Accept-Language\`.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression or unsupported \`$orderby\`/\`$filter\` field\\r\\n (returns \`ValidationFailureRepresentation\`).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Attribute Set with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /AttributeSets(7)/Products?$filter=contains(prod\_description,'pro')&$top=20 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterProductsInAttributeSetAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (Accept-Language header)
 schema:
 type: string
 \- name: attributeSetIdentifier
 in: path
 description: Attribute Set resource identifier
 required: true
 schema:
 type: integer
 format: int32
 \- name: $filter
 in: query
 schema:
 type: string
 \- name: $orderby
 in: query
 schema:
 type: string
 \- name: $skip
 in: query
 schema:
 type: integer
 format: int64
 \- name: $skipToken
 in: query
 schema:
 type: string
 \- name: $top
 in: query
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /AttributeSets/$metadata:
 get:
 tags:
 \- Attribute Sets
 summary: Get Attribute Set Metadata
 description: "\\r\\n\\r\\n Returns the public metadata of the **Attribute Set** model as a JSON schema document describing the resources ( **Product**, **Variant**) associated to the **Attribute Set** and the relationships between them. Use it to build requests against the various methods of the API.\\r\\n "
 operationId: GetAttributeSetMetadataAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '403':
 description: Forbidden
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /v2/AttributeSets:
 get:
 tags:
 \- Attribute Sets v2
 summary: Get Attribute Sets
 description: "Returns all attribute sets defined for the tenant, each including its name, identifier,\\r\\nand form layout configuration for Products and Variants (\`ProductLayout\`, \`VariantLayout\`).\\r\\n \\r\\n\*\*See also:\*\* A legacy OData-style version of this endpoint is available at \`GET /AttributeSets\`.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — \`GetAttributeSetsResponse\` containing the list of attribute sets.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid tenant identifier.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /v2/AttributeSets HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: GetAttributeSets
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 post:
 tags:
 \- Attribute Sets v2
 summary: Create Attribute Set
 description: "Creates a new attribute set for the tenant from the supplied \`name\` and optional Product and\\r\\nVariant form layouts, returning the created attribute set and a \`Location\` header pointing to it.\\r\\n \\r\\nThe Product and Variant layouts behave differently when omitted: an omitted \`productLayout\`\\r\\nfalls back to a standard default layout, whereas an omitted \`variantLayout\` is \*\*not\*\* created\\r\\nat all (no Variant layout is stored). A Variant layout can be added later with\\r\\n\`PATCH /v2/AttributeSets({id})\`.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Request Body\\r\\n \\r\\n\| Field \| Required \| Description \|\\r\\n\|---\|---\|---\|\\r\\n\| \`name\` \| ✅ Yes \| Unique name for the attribute set within the tenant. \|\\r\\n\| \`productLayout\` \| ❌ No \| Form layout for Products. Defaults to the standard layout when omitted. \|\\r\\n\| \`variantLayout\` \| ❌ No \| Form layout for Variants. When omitted, no Variant layout is created (it can be added later via \`PATCH\`). \|\\r\\n \\r\\n## Layout Structure\\r\\n \\r\\nEach layout is a JSON document with a \`sections\` array. Each section has a \`title\` and a \`rows\`\\r\\narray. Each row has a \`fields\` array and an optional divider (\`dividerType\`, \`dividerTitle\`).\\r\\nEach field carries an \`attributeId\` and a \`size\`.\\r\\n \\r\\n\`\`\`json\\r\\n{\\r\\n \\"sections\\": \[\\r\\n {\\r\\n \\"title\\": \\"General\\",\\r\\n \\"rows\\": \[\\r\\n {\\r\\n \\"fields\\": \[\\r\\n { \\"attributeId\\": \\"prod\_title\\", \\"size\\": \\"half\\" },\\r\\n { \\"attributeId\\": \\"prod\_ref\\", \\"size\\": \\"half\\" }\\r\\n \]\\r\\n },\\r\\n {\\r\\n \\"dividerType\\": \\"normal\\",\\r\\n \\"dividerTitle\\": \\"Details\\",\\r\\n \\"fields\\": \[\\r\\n { \\"attributeId\\": \\"prod\_description\\", \\"size\\": \\"row\\" }\\r\\n \]\\r\\n }\\r\\n \]\\r\\n }\\r\\n \]\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*\`size\`\*\* — width of the field in the form grid. One of: \`quarter\`, \`half\`, \`threeQuarters\`, \`row\`.\\r\\n \\r\\n\*\*\`dividerType\`\*\* — optional visual separator above the row. One of: \`normal\`, \`wide\`, \`lineBreak\`.\\r\\n\`dividerTitle\` is optional and only meaningful when \`dividerType\` is set.\\r\\nBoth properties are omitted from rows that have no divider.\\r\\n \\r\\n## Layout Validation\\r\\n \\r\\nA layout may contain \*\*any subset\*\* of the tenant's valid attributes — you do not need to\\r\\ninclude all of them. Attributes omitted from the layout simply do not appear in the form\\r\\nfor this attribute set; they are not removed from the tenant.\\r\\n \\r\\nIf a layout is supplied it must satisfy all of the following rules; otherwise the request\\r\\nreturns \`400 Bad Request\` describing each failure:\\r\\n \\r\\n- 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.\\r\\n- Every \`attributeId\` included must exist for the entity type (Products or Variants) in the tenant's storage definition.\\r\\n- No \`attributeId\` may appear more than once across the entire layout.\\r\\n- Each field \`size\` must be one of: \`quarter\`, \`half\`, \`threeQuarters\`, \`row\`.\\r\\n- The sum of field sizes within any single row must not exceed a full row.\\r\\n- Every row must contain at least one field.\\r\\n- Section \`title\` values must be unique (case-insensitive).\\r\\n- When a row sets \`dividerType\` it must be one of: \`normal\`, \`wide\`, \`lineBreak\`.\\r\\n \\r\\n### Required attributes\\r\\n \\r\\nThese attributes must always be present in their respective layout:\\r\\n \\r\\n\| Layout \| Required attribute IDs \|\\r\\n\|---\|---\|\\r\\n\| \`productLayout\` \| \`typ\_id\`, \`prod\_ref\`, \`prod\_title\`, \`cat\_ref\`, \`prod\_stat\`, \`prod\_description\`, \`prod\_image\`, \`prod\_tags\` \|\\r\\n\| \`variantLayout\` \| \`frmt\_stat\`, \`prod\_ref\`, \`frmt\_ref\`, \`frmt\_tags\` \|\\r\\n \\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*201 Created\*\* — The \`Location\` header points to the new resource: \`/v2/AttributeSets({id})\`.\\r\\nThe response body contains the created attribute set (\`CreateAttributeSet2Response\`).\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Missing body, missing \`name\`, duplicate name, or layout validation failure.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid tenant identifier.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nPOST /v2/AttributeSets HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nContent-Type: application/json\\r\\n \\r\\n{ \\"name\\": \\"Electronics\\" }\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 201 Created\\r\\nLocation: /v2/AttributeSets(7)\\r\\n\`\`\`"
 operationId: CreateAttributeSet
 requestBody:
 description: Attribute set creation payload.
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CreateAttributeSetBody'
 text/json:
 schema:
 $ref: '#/components/schemas/CreateAttributeSetBody'
 application/\*+json:
 schema:
 $ref: '#/components/schemas/CreateAttributeSetBody'
 responses:
 '201':
 description: Created
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /v2/AttributeSets({id}):
 get:
 tags:
 \- Attribute Sets v2
 summary: Get Attribute Set
 description: "Returns a single attribute set identified by \`id\`. Accepted values:\\r\\n- \*\*\`default\`\*\* (case-insensitive) — retrieves the tenant's default attribute set.\\r\\n- \*\*Positive integer\*\* — retrieves the attribute set with that numeric ID.\\r\\n \\r\\nAny other value is rejected with \`400 Bad Request\`.\\r\\n \\r\\nThe response includes the attribute set name and its form layout configuration for Products\\r\\nand Variants (\`ProductLayout\`, \`VariantLayout\`). When the set has no Variant layout configured,\\r\\n\`VariantLayout\` and \`VariantAttributeIds\` are omitted from the response.\\r\\n \\r\\n\*\*See also:\*\* A legacy OData-style version of this endpoint is available at\\r\\n\`GET /AttributeSets({attributeSetIdentifier})\`.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — The requested attribute set with its layout configuration.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — \`id\` is not \`default\` or a valid positive integer.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid tenant identifier.\\r\\n- \*\*404 Not Found\*\* — No attribute set with the given identifier exists for this tenant.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /v2/AttributeSets(1) HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: GetAttributeSet
 parameters:
 \- name: id
 in: path
 description: 'Attribute set identifier: \`default\` or a positive integer.'
 required: true
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 patch:
 tags:
 \- Attribute Sets v2
 summary: Update Attribute Set
 description: "Partially updates an existing attribute set identified by \`id\`. Accepted values:\\r\\n- \*\*\`default\`\*\* (case-insensitive) — updates the tenant's default attribute set.\\r\\n- \*\*Positive integer\*\* — updates the attribute set with that numeric ID.\\r\\n \\r\\nAny other value is rejected with \`400 Bad Request\`.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Request Body\\r\\n \\r\\nAll fields are optional. Omitted (null) fields are left unchanged (PATCH semantics).\\r\\nWhen a layout is supplied it \*\*fully replaces\*\* the currently stored layout — it is not merged.\\r\\n \\r\\n\| Field \| Description \|\\r\\n\|---\|---\|\\r\\n\| \`name\` \| New unique name for the attribute set. \|\\r\\n\| \`productLayout\` \| Replacement form layout for Products. \|\\r\\n\| \`variantLayout\` \| Form layout for Variants. Sets the Variant layout when the set does not yet have one (e.g. created without it), or replaces it when it does. \|\\r\\n \\r\\n## Layout Structure\\r\\n \\r\\nEach layout is a JSON document with a \`sections\` array. Each section has a \`title\` and a \`rows\`\\r\\narray. Each row has a \`fields\` array and an optional divider (\`dividerType\`, \`dividerTitle\`).\\r\\nEach field carries an \`attributeId\` and a \`size\`.\\r\\n \\r\\n\`\`\`json\\r\\n{\\r\\n \\"sections\\": \[\\r\\n {\\r\\n \\"title\\": \\"General\\",\\r\\n \\"rows\\": \[\\r\\n {\\r\\n \\"fields\\": \[\\r\\n { \\"attributeId\\": \\"prod\_title\\", \\"size\\": \\"half\\" },\\r\\n { \\"attributeId\\": \\"prod\_ref\\", \\"size\\": \\"half\\" }\\r\\n \]\\r\\n },\\r\\n {\\r\\n \\"dividerType\\": \\"normal\\",\\r\\n \\"dividerTitle\\": \\"Details\\",\\r\\n \\"fields\\": \[\\r\\n { \\"attributeId\\": \\"prod\_description\\", \\"size\\": \\"row\\" }\\r\\n \]\\r\\n }\\r\\n \]\\r\\n }\\r\\n \]\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*\`size\`\*\* — width of the field in the form grid. One of: \`quarter\`, \`half\`, \`threeQuarters\`, \`row\`.\\r\\n \\r\\n\*\*\`dividerType\`\*\* — optional visual separator above the row. One of: \`normal\`, \`wide\`, \`lineBreak\`.\\r\\n\`dividerTitle\` is optional and only meaningful when \`dividerType\` is set.\\r\\nBoth properties are omitted from rows that have no divider.\\r\\n \\r\\n## Layout Validation\\r\\n \\r\\nA layout may contain \*\*any subset\*\* of the tenant's valid attributes — you do not need to\\r\\ninclude all of them. Attributes omitted from the layout simply do not appear in the form\\r\\nfor this attribute set; they are not removed from the tenant.\\r\\n \\r\\nThis is different from \`PUT /Categories/layout\` and \`PUT /CustomEntities('{id}')/layout\`,\\r\\nwhere the payload must contain every attribute currently in the stored layout — no more, no less.\\r\\n \\r\\nIf a layout is supplied it must satisfy all of the following rules; otherwise the request\\r\\nreturns \`400 Bad Request\` describing each failure:\\r\\n \\r\\n- 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.\\r\\n- Every \`attributeId\` included must exist for the entity type (Products or Variants) in the tenant's storage definition.\\r\\n- No \`attributeId\` may appear more than once across the entire layout.\\r\\n- Each field \`size\` must be one of: \`quarter\`, \`half\`, \`threeQuarters\`, \`row\`.\\r\\n- The sum of field sizes within any single row must not exceed a full row.\\r\\n- Every row must contain at least one field.\\r\\n- Section \`title\` values must be unique (case-insensitive).\\r\\n- When a row sets \`dividerType\` it must be one of: \`normal\`, \`wide\`, \`lineBreak\`.\\r\\n \\r\\n### Required attributes\\r\\n \\r\\nThese attributes must always be present in their respective layout:\\r\\n \\r\\n\| Layout \| Required attribute IDs \|\\r\\n\|---\|---\|\\r\\n\| \`productLayout\` \| \`typ\_id\`, \`prod\_ref\`, \`prod\_title\`, \`cat\_ref\`, \`prod\_stat\`, \`prod\_description\`, \`prod\_image\`, \`prod\_tags\` \|\\r\\n\| \`variantLayout\` \| \`frmt\_stat\`, \`prod\_ref\`, \`frmt\_ref\`, \`frmt\_tags\` \|\\r\\n \\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — The updated attribute set (\`UpdateAttributeSet2Response\`).\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid \`id\`, missing body, or layout validation failure.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid tenant identifier.\\r\\n- \*\*404 Not Found\*\* — No attribute set with the given identifier exists for this tenant.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nPATCH /v2/AttributeSets(1) HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nContent-Type: application/json\\r\\n \\r\\n{ \\"name\\": \\"Electronics v2\\" }\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: UpdateAttributeSet
 parameters:
 \- name: id
 in: path
 description: 'Attribute set identifier: \`default\` or a positive integer.'
 required: true
 schema:
 type: string
 requestBody:
 description: Attribute set update payload. All fields are optional.
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/UpdateAttributeSetBody'
 text/json:
 schema:
 $ref: '#/components/schemas/UpdateAttributeSetBody'
 application/\*+json:
 schema:
 $ref: '#/components/schemas/UpdateAttributeSetBody'
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 delete:
 tags:
 \- Attribute Sets v2
 summary: Delete Attribute Set
 description: "Deletes the attribute set identified by \`id\` (a positive integer). The tenant's default\\r\\nattribute set cannot be deleted.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Query Parameters\\r\\n \\r\\n\| Parameter \| Required \| Description \|\\r\\n\|---\|---\|---\|\\r\\n\| \`deleteAssociatedProductsAndVariants\` \| ❌ No \| When \`true\`, products and variants associated to the attribute set are deleted along with it. When \`false\` or omitted, those products and variants are reassigned to the tenant's default attribute set. \|\\r\\n \\r\\n## Response\\r\\n \\r\\n- \*\*200 OK\*\* — Attribute set deleted; the response body (\`DeleteAttributeSet2Response\`) summarises the operation.\\r\\n- \*\*204 No Content\*\* — Nothing to delete (idempotent success).\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — \`id\` is not a positive integer or the request is otherwise invalid (\`ValidationFailureRepresentation\`).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid tenant identifier.\\r\\n- \*\*404 Not Found\*\* — No attribute set with the given identifier exists for this tenant.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nDELETE /v2/AttributeSets(7)?deleteAssociatedProductsAndVariants=false HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: DeleteAttributeSet
 parameters:
 \- name: id
 in: path
 description: Attribute set identifier (positive integer).
 required: true
 schema:
 type: integer
 format: int32
 \- name: deleteAssociatedProductsAndVariants
 in: query
 description: >-
 When \`true\`, also deletes associated products and variants. When
 \`false\` or omitted, those products and variants are reassigned to
 the default attribute set.
 schema:
 type: boolean
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '204':
 description: No Content
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Categories:
 get:
 tags:
 \- Categories
 summary: Filter Categories
 description: "Filters the tenant's Categories using OData query options and returns the matching\\r\\nresources as a paginated collection.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for localized content.\\r\\n- \*\*omitted / null\*\*: content in the tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): content localized in the specified culture.\\r\\n- \*\*\`\*\`\*\* and q-factor weighting are currently not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\n### $select\\r\\n \\r\\nComma-separated list of root-resource property names to include in the response.\\r\\nThe available property names are published in \`/Categories/$metadata\`.\\r\\nSelecting properties of embedded resources is not supported.\\r\\n \\r\\nExample: \`$select=cat\_title,cat\_description\`\\r\\n \\r\\n### $expand\\r\\n \\r\\nComma-separated list of embedded collections to include.\\r\\nBy default, embedded collections are not included.\\r\\nOnly embedded collections (not embedded resources) are supported.\\r\\n \\r\\nExample: \`$expand=Products\`\\r\\n \\r\\n### $filter\\r\\n \\r\\nOData v4.01 URI conventions. Filtering is restricted to properties of the root resource (Category).\\r\\n \\r\\n\*\*Comparison operators:\*\* \`eq\`, \`ne\`, \`gt\`, \`ge\`, \`lt\`, \`le\`\\r\\n \\r\\n\*\*Logical operators:\*\* \`and\`, \`or\`, \`not\`\\r\\n \\r\\n\*\*Set operator:\*\* \`in\`\\r\\n \\r\\n\*\*String functions:\*\* \`contains\`, \`startswith\`, \`endswith\`\\r\\n \\r\\nExamples:\\r\\n- \`$filter=cat\_title eq 'Outdoor'\`\\r\\n- \`$filter=contains(cat\_title, 'pro')\`\\r\\n- \`$filter=cat\_id in (1, 2, 3)\`\\r\\n- \`$filter=cat\_id gt 100 and contains(cat\_title, 'pro')\`\\r\\n \\r\\n### $orderby\\r\\n \\r\\nSingle property, ascending by default. Multi-property ordering and ordering on embedded\\r\\nproperties are not supported.\\r\\n \\r\\nExamples:\\r\\n- \`$orderby=cat\_title\` (asc by default)\\r\\n- \`$orderby=cat\_title asc\`\\r\\n- \`$orderby=cat\_ref desc\`\\r\\n \\r\\n### Pagination — $top, $skip, $skipToken\\r\\n \\r\\n- \`$top\` — maximum number of items returned.\\r\\n- \`$skip\` — number of items to skip (offset paging).\\r\\n- \`$skipToken\` — continuation-token paging. Recommended when no \`$orderby\` is applied\\r\\n (faster than offset paging).\\r\\n \\r\\nPaging applies only to the root resource (Category), never to embedded collections.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — \`CollectionRepresentation\` with the matching Category resources, pagination\\r\\nmetadata (\`Count\`, \`Skip\`, \`Top\`, \`HasNext\`, continuation token) and the cultures echoed\\r\\nfrom \`Accept-Language\`.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression or unsupported \`$orderby\`/\`$filter\` field\\r\\n (returns \`ValidationFailureRepresentation\`).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or model not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Categories?$filter=contains(cat\_title,'pro')&$orderby=cat\_title asc&$top=20 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterCategoriesAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (Accept-Language header)
 schema:
 type: string
 \- name: $filter
 in: query
 schema:
 type: string
 \- name: $orderby
 in: query
 schema:
 type: string
 \- name: $skip
 in: query
 schema:
 type: integer
 format: int64
 \- name: $skipToken
 in: query
 schema:
 type: string
 \- name: $top
 in: query
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 post:
 tags:
 \- Categories
 summary: Create Category
 description: "Creates a new Category from the supplied JSON object and returns its location in the\\r\\n\`Location\` header.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nCulture used to interpret the localized field values supplied in the request body.\\r\\n- \*\*omitted / null\*\*: tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): the specified culture.\\r\\n \\r\\n## Request Body\\r\\n \\r\\nA single JSON object whose properties match the writable fields published by\\r\\n\`/Categories/$metadata\`. The body is normalized before reaching the application layer:\\r\\n \\r\\n- Must be a non-empty JSON object.\\r\\n- A JSON array is accepted only if it contains exactly one element.\\r\\n- Values are coerced to CLR primitives (\`string\`, \`long\`, \`double\`, \`bool\`, \`null\`),\\r\\n nested objects and arrays.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*201 Created\*\* — The \`Location\` header points to the new resource: \`/Categories({id})\`.\\r\\nNo response body.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Payload normalization or validation failure (empty body,\\r\\n multi-element array, invalid field values, etc.). Validation errors are returned\\r\\n as \`ValidationFailureRepresentation\`.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or referenced resource not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nPOST /Categories HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\nContent-Type: application/json\\r\\n \\r\\n{\\r\\n \\"cat\_title\\": \\"Outdoor\\",\\r\\n \\"cat\_ref\\": \\"OUT-001\\",\\r\\n \\"cat\_description\\": \\"Outdoor products category\\"\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 201 Created\\r\\nLocation: /Categories(123)\\r\\n\`\`\`"
 operationId: CreateCategoryAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: >-
 Culture for localized field values in the request body
 (Accept-Language header)
 schema:
 type: string
 requestBody:
 description: JSON object with the Category fields to create
 content:
 application/json:
 schema: {}
 responses:
 '201':
 description: Created
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Categories({categoryIdentifier}):
 get:
 tags:
 \- Categories
 summary: Get Category
 description: "Returns a single Category resource identified by its route identifier, optionally shaping\\r\\nthe response with \`$select\` and \`$expand\`.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for localized content.\\r\\n- \*\*omitted / null\*\*: content in the tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): content localized in the specified culture.\\r\\n- \*\*\`\*\`\*\* and q-factor weighting are currently not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\n### $select\\r\\n \\r\\nComma-separated list of root-resource property names to include in the response.\\r\\nSee \`/Categories/$metadata\` for the available properties.\\r\\nSelecting properties of embedded resources is not supported.\\r\\n \\r\\nExample: \`$select=cat\_title,cat\_description\`\\r\\n \\r\\n### $expand\\r\\n \\r\\nComma-separated list of embedded collections to include.\\r\\nBy default, embedded collections are not included.\\r\\nOnly embedded collections (not embedded resources) are supported.\\r\\n \\r\\nExample: \`$expand=Products\`\\r\\n \\r\\n\`$filter\`, \`$orderby\`, \`$top\`, \`$skip\` and \`$skipToken\` are not applicable to this endpoint.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — \`EntityRepresentation\` with the requested Category resource.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid \`$select\` or \`$expand\` expression (returns \`ValidationFailureRepresentation\`).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Category with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Categories(123)?$select=cat\_title,cat\_description&$expand=Products HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: SearchCategoryAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (Accept-Language header)
 schema:
 type: string
 \- name: categoryIdentifier
 in: path
 description: Category resource identifier
 required: true
 schema:
 type: integer
 format: int32
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Categories({categoryId}):
 patch:
 tags:
 \- Categories
 summary: Update Category
 description: "Updates an existing Category identified by its route identifier, applying only the writable\\r\\nfields supplied in the request body (PATCH semantics).\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nCulture used to interpret the localized field values supplied in the request body.\\r\\n- \*\*omitted / null\*\*: tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): the specified culture.\\r\\n \\r\\n## Request Body\\r\\n \\r\\nA single JSON object with the subset of writable fields to update (PATCH semantics —\\r\\nonly the supplied fields are modified). Field names must match those published by\\r\\n\`/Categories/$metadata\`. Normalization rules:\\r\\n \\r\\n- Must be a non-empty JSON object.\\r\\n- A JSON array is accepted only if it contains exactly one element.\\r\\n- Values are coerced to CLR primitives, nested objects and arrays.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Update applied.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Payload normalization or validation failure\\r\\n (returns \`ValidationFailureRepresentation\` for validation errors).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Category with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nPATCH /Categories(123) HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\nContent-Type: application/json\\r\\n \\r\\n{\\r\\n \\"cat\_title\\": \\"Outdoor & Camping\\"\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\n\`\`\`"
 operationId: UpdateCategoryAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: >-
 Culture for localized field values in the request body
 (Accept-Language header)
 schema:
 type: string
 \- name: categoryId
 in: path
 description: Category resource identifier
 required: true
 schema:
 type: integer
 format: int32
 requestBody:
 description: JSON object with the Category fields to update
 content:
 application/json:
 schema: {}
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 delete:
 tags:
 \- Categories
 summary: Delete Category
 description: "Deletes the Category identified by its route identifier.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*204 No Content\*\* — Category deleted.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Category with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nDELETE /Categories(123) HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 204 No Content\\r\\n\`\`\`"
 operationId: DeleteCategoryAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: categoryId
 in: path
 description: Category resource identifier
 required: true
 schema:
 type: integer
 format: int32
 responses:
 '204':
 description: No Content
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Categories({categoryIdentifier})/Products:
 get:
 tags:
 \- Categories
 summary: Filter Category Products
 description: "Filters and returns a paginated collection of Product resources scoped to the given Category, using OData query options.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for localized content.\\r\\n- \*\*omitted / null\*\*: content in the tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): content localized in the specified culture.\\r\\n- \*\*\`\*\`\*\* and q-factor weighting are currently not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\n### $select\\r\\n \\r\\nComma-separated list of root-resource property names to include in the response.\\r\\nSee \`/Products/$metadata\` for the available properties.\\r\\nSelecting properties of embedded resources is not supported.\\r\\n \\r\\nExample: \`$select=prod\_description,prod\_tags\`\\r\\n \\r\\n### $expand\\r\\n \\r\\nComma-separated list of embedded collections to include (e.g. \`Variants\`).\\r\\nBy default, embedded collections are not included.\\r\\nOnly embedded collections (not embedded resources) are supported.\\r\\n \\r\\nExample: \`$expand=Variants\`\\r\\n \\r\\n### $filter\\r\\n \\r\\nOData v4.01 URI conventions. Filtering is restricted to properties of the root resource (Product).\\r\\n \\r\\n\*\*Comparison operators:\*\* \`eq\`, \`ne\`, \`gt\`, \`ge\`, \`lt\`, \`le\`\\r\\n \\r\\n\*\*Logical operators:\*\* \`and\`, \`or\`, \`not\`\\r\\n \\r\\n\*\*Set operator:\*\* \`in\`\\r\\n \\r\\n\*\*String functions:\*\* \`contains\`, \`startswith\`, \`endswith\`\\r\\n \\r\\nExamples:\\r\\n- \`$filter=prod\_ref eq 'SKU-001'\`\\r\\n- \`$filter=contains(prod\_description, 'pro')\`\\r\\n- \`$filter=prod\_id gt 100 and contains(prod\_description, 'pro')\`\\r\\n \\r\\n### $orderby\\r\\n \\r\\nSingle property, ascending by default. Multi-property ordering and ordering on embedded\\r\\nproperties are not supported.\\r\\n \\r\\nExamples:\\r\\n- \`$orderby=prod\_description\`\\r\\n- \`$orderby=prod\_ref desc\`\\r\\n \\r\\n### Pagination — $top, $skip, $skipToken\\r\\n \\r\\n- \`$top\` — maximum number of items returned.\\r\\n- \`$skip\` — number of items to skip (offset paging).\\r\\n- \`$skipToken\` — continuation-token paging. Recommended when no \`$orderby\` is applied\\r\\n (faster than offset paging).\\r\\n \\r\\nPaging applies only to the root resource (Product), never to embedded collections.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — \`CollectionRepresentation\` with the matching Product resources, pagination\\r\\nmetadata (\`Count\`, \`Skip\`, \`Top\`, \`HasNext\`, continuation token) and the cultures echoed\\r\\nfrom \`Accept-Language\`.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression or unsupported \`$orderby\`/\`$filter\` field\\r\\n (returns \`ValidationFailureRepresentation\`).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Category with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Categories(123)/Products?$filter=contains(prod\_description,'pro')&$top=20 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterProductsInCategoryAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (Accept-Language header)
 schema:
 type: string
 \- name: categoryIdentifier
 in: path
 description: Category resource identifier
 required: true
 schema:
 type: integer
 format: int32
 \- name: $filter
 in: query
 schema:
 type: string
 \- name: $orderby
 in: query
 schema:
 type: string
 \- name: $skip
 in: query
 schema:
 type: integer
 format: int64
 \- name: $skipToken
 in: query
 schema:
 type: string
 \- name: $top
 in: query
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Categories({categoryIdentifier})/Products({productIdentifier}):
 get:
 tags:
 \- Categories
 summary: Get Category Product
 description: "Returns a single Product resource by its identifier, scoped to the given Category.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for localized content.\\r\\n- \*\*omitted / null\*\*: content in the tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): content localized in the specified culture.\\r\\n- \*\*\`\*\`\*\* and q-factor weighting are currently not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\n### $select\\r\\n \\r\\nComma-separated list of root-resource property names to include in the response.\\r\\nSee \`/Products/$metadata\` for the available properties.\\r\\nSelecting properties of embedded resources is not supported.\\r\\n \\r\\nExample: \`$select=prod\_description,prod\_tags\`\\r\\n \\r\\n### $expand\\r\\n \\r\\nComma-separated list of embedded collections to include (e.g. \`Variants\`).\\r\\nBy default, embedded collections are not included.\\r\\nOnly embedded collections (not embedded resources) are supported.\\r\\n \\r\\nExample: \`$expand=Variants\`\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — \`EntityRepresentation\` with the Product resource scoped to the given Category.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression (returns \`ValidationFailureRepresentation\`).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Category or Product with the given identifier does not exist, or the\\r\\n Product is not associated with the Category.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Categories(123)/Products(456)?$expand=Variants HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: SearchProductInCategoryAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (Accept-Language header)
 schema:
 type: string
 \- name: categoryIdentifier
 in: path
 description: Category resource identifier
 required: true
 schema:
 type: integer
 format: int32
 \- name: productIdentifier
 in: path
 description: Product resource identifier
 required: true
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Categories/Changelog:
 get:
 tags:
 \- Categories
 summary: Get Categories Changelog
 description: "Returns the changelog entries for the tenant's Categories as a collection, filterable and\\r\\npageable with OData query options.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nSupports \`$filter\`, \`$orderby\`, \`$top\`, \`$skip\` over the changelog fields.\\r\\n\`$select\`, \`$expand\` and \`$skipToken\` are not supported by this endpoint.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Collection of changelog entries (\`CollectionRepresentation\`).\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Categories/Changelog?$orderby=changedAt desc&$top=50 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterCategoriesChangelogAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: $filter
 in: query
 description: OData \`$filter\` expression
 schema:
 type: string
 \- name: $orderby
 in: query
 description: OData \`$orderby\` expression
 schema:
 type: string
 \- name: $top
 in: query
 description: OData \`$top\` page size
 schema:
 type: integer
 format: int64
 \- name: $skip
 in: query
 description: OData \`$skip\` offset
 schema:
 type: integer
 format: int64
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Categories({categoryIdentifier})/Changelog:
 get:
 tags:
 \- Categories
 summary: Get Category Changelog
 description: "Returns the changelog entries for a single Category identified by its route identifier,\\r\\nfilterable and pageable with OData query options.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nSupports \`$filter\`, \`$orderby\`, \`$top\`, \`$skip\` over the changelog fields.\\r\\n\`$select\`, \`$expand\` and \`$skipToken\` are not supported by this endpoint.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Collection of changelog entries for the specified Category.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Categories(123)/Changelog?$top=20 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterCategoryChangelogAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: categoryIdentifier
 in: path
 description: Category resource identifier
 required: true
 schema:
 type: integer
 format: int32
 \- name: $filter
 in: query
 description: OData \`$filter\` expression
 schema:
 type: string
 \- name: $orderby
 in: query
 description: OData \`$orderby\` expression
 schema:
 type: string
 \- name: $top
 in: query
 description: OData \`$top\` page size
 schema:
 type: integer
 format: int64
 \- name: $skip
 in: query
 description: OData \`$skip\` offset
 schema:
 type: integer
 format: int64
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Categories/layout:
 get:
 tags:
 \- Categories
 summary: Get Category Layout
 description: "The layout describes how the Category edit form is rendered. It is a JSON document with a\\r\\n\`sections\` array; each section has a \`title\` and a \`rows\` array; each row has a\\r\\n\`fields\` array and, optionally, a divider (\`dividerType\` and \`dividerTitle\`).\\r\\nEach field carries an \`attributeId\` and a grid \`size\` — one of \`quarter\`,\\r\\n\`half\`, \`threeQuarters\` or \`row\`. When a row has a divider its \`dividerType\`\\r\\nis one of \`normal\`, \`wide\` or \`lineBreak\`. \`dividerType\` and\\r\\n\`dividerTitle\` are omitted from a row when they have no value, so a row without a divider\\r\\ncontains only its \`fields\`.\\r\\n \\r\\nThe Category model has a single layout shared by all categories. A layout must already be\\r\\nconfigured for the tenant; if none exists the request fails."
 operationId: GetCategoryFormLayoutAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '401':
 description: Unauthorized
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 put:
 tags:
 \- Categories
 summary: Update Category Layout
 description: "Fully overwrites the currently stored Category layout. The payload is \*\*not merged\*\* with the\\r\\nexisting layout — it replaces it entirely.\\r\\n \\r\\nA layout must already exist for the tenant; this operation replaces it and does not create one.\\r\\nIf none exists the request returns \`404 Not Found\`.\\r\\n \\r\\n## ⚠️ All attributes are required\\r\\n \\r\\nThe payload must contain \*\*every attribute currently in the stored layout\*\* — no more, no less.\\r\\nOmitting an attribute removes it from the form. Adding an attribute that is not already in the\\r\\nlayout is also rejected. Use \`GET /Categories/layout\` first to obtain the current set of attributes.\\r\\n \\r\\nThis is different from \`PATCH /v2/AttributeSets({id})\`, where layouts may contain any subset of\\r\\nthe tenant's attributes.\\r\\n \\r\\n## Layout Structure\\r\\n \\r\\nThe payload has the same shape as the \`GET /Categories/layout\` response:\\r\\n \\r\\n\`\`\`json\\r\\n{\\r\\n \\"sections\\": \[\\r\\n {\\r\\n \\"title\\": \\"General\\",\\r\\n \\"rows\\": \[\\r\\n {\\r\\n \\"fields\\": \[\\r\\n { \\"attributeId\\": \\"cat\_title\\", \\"size\\": \\"half\\" },\\r\\n { \\"attributeId\\": \\"cat\_ref\\", \\"size\\": \\"half\\" }\\r\\n \]\\r\\n },\\r\\n {\\r\\n \\"dividerType\\": \\"normal\\",\\r\\n \\"dividerTitle\\": \\"Details\\",\\r\\n \\"fields\\": \[\\r\\n { \\"attributeId\\": \\"cat\_description\\", \\"size\\": \\"row\\" }\\r\\n \]\\r\\n }\\r\\n \]\\r\\n }\\r\\n \]\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*\`size\`\*\* — one of: \`quarter\`, \`half\`, \`threeQuarters\`, \`row\`.\\r\\n \\r\\n\*\*\`dividerType\`\*\* — optional; one of: \`normal\`, \`wide\`, \`lineBreak\`. \`dividerTitle\` is optional\\r\\nand only meaningful when \`dividerType\` is set. Both are omitted from rows that have no divider.\\r\\n \\r\\n## Validation Rules\\r\\n \\r\\nIf any rule is violated the request returns \`400 Bad Request\` describing each failure:\\r\\n \\r\\n- The layout must contain every attribute currently in the stored layout — no more, no less.\\r\\n- No \`attributeId\` may appear more than once.\\r\\n- Each field \`size\` must be one of: \`quarter\`, \`half\`, \`threeQuarters\`, \`row\`.\\r\\n- The sum of field sizes within any single row must not exceed a full row.\\r\\n- Every row must contain at least one field.\\r\\n- Section \`title\` values must be unique (case-insensitive).\\r\\n- When a row sets \`dividerType\` it must be one of: \`normal\`, \`wide\`, \`lineBreak\`."
 operationId: UpdateCategoryFormLayoutAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key
 schema:
 type: string
 requestBody:
 description: The new form layout to store
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/FormLayoutDto'
 responses:
 '204':
 description: No Content
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Categories/$metadata:
 get:
 tags:
 \- Categories
 summary: Get Category Metadata
 description: "The metadata is a JSON Schema document that describes:\\r\\n- The implicit and custom properties exposed by the Category resource.\\r\\n- The embedded resources (\`Products\`, \`Variants\`) and their relationships.\\r\\n \\r\\nThe schema should be consulted to build requests against the other Category endpoints\\r\\n(which fields can be used in \`$select\`, \`$filter\`, \`$orderby\`, request bodies, etc.).\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Returns the JSON Schema as a \`ServiceDocumentRepresentation\`.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or model not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Categories/$metadata HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: GetCategoryMetadataAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Products:
 get:
 tags:
 \- Products
 summary: Filter Products
 description: "Filters and returns a paginated collection of Product resources using OData query options.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for localized content.\\r\\n- \*\*omitted / null\*\*: content in the tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): content localized in the specified culture.\\r\\n- \*\*\`\*\`\*\* and q-factor weighting are currently not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\n### $select\\r\\n \\r\\nComma-separated list of root-resource property names to include in the response.\\r\\nSee \`/Products/$metadata\` for the available properties.\\r\\nSelecting properties of embedded resources is not supported.\\r\\n \\r\\nExample: \`$select=prod\_description,prod\_tags\`\\r\\n \\r\\n### $expand\\r\\n \\r\\nComma-separated list of embedded collections to include (e.g. \`Variants\`).\\r\\nBy default, embedded collections are not included.\\r\\nOnly embedded collections (not embedded resources) are supported.\\r\\n \\r\\nExample: \`$expand=Variants\`\\r\\n \\r\\n### $filter\\r\\n \\r\\nOData v4.01 URI conventions. Filtering is restricted to properties of the root resource (Product).\\r\\n \\r\\n\*\*Comparison operators:\*\* \`eq\`, \`ne\`, \`gt\`, \`ge\`, \`lt\`, \`le\`\\r\\n \\r\\n\*\*Logical operators:\*\* \`and\`, \`or\`, \`not\`\\r\\n \\r\\n\*\*Set operator:\*\* \`in\`\\r\\n \\r\\n\*\*String functions:\*\* \`contains\`, \`startswith\`, \`endswith\`\\r\\n \\r\\nExamples:\\r\\n- \`$filter=prod\_ref eq 'SKU-001'\`\\r\\n- \`$filter=contains(prod\_description, 'pro')\`\\r\\n- \`$filter=prod\_id in (1, 2, 3)\`\\r\\n- \`$filter=prod\_id gt 100 and contains(prod\_description, 'pro')\`\\r\\n \\r\\n### $orderby\\r\\n \\r\\nSingle property, ascending by default. Multi-property ordering and ordering on embedded\\r\\nproperties are not supported.\\r\\n \\r\\nExamples:\\r\\n- \`$orderby=prod\_description\` (asc by default)\\r\\n- \`$orderby=prod\_description asc\`\\r\\n- \`$orderby=prod\_ref desc\`\\r\\n \\r\\n### Pagination — $top, $skip, $skipToken\\r\\n \\r\\n- \`$top\` — maximum number of items returned.\\r\\n- \`$skip\` — number of items to skip (offset paging).\\r\\n- \`$skipToken\` — continuation-token paging. Recommended when no \`$orderby\` is applied\\r\\n (faster than offset paging).\\r\\n \\r\\nPaging applies only to the root resource (Product), never to embedded collections.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — \`CollectionRepresentation\` with the matching Product resources, pagination\\r\\nmetadata (\`Count\`, \`Skip\`, \`Top\`, \`HasNext\`, continuation token) and the cultures echoed\\r\\nfrom \`Accept-Language\`.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression or unsupported \`$orderby\`/\`$filter\` field\\r\\n (returns \`ValidationFailureRepresentation\`).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or model not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Products?$filter=contains(prod\_description,'pro')&$orderby=prod\_description asc&$top=20 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterProductsAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (Accept-Language header)
 schema:
 type: string
 \- name: $filter
 in: query
 schema:
 type: string
 \- name: $orderby
 in: query
 schema:
 type: string
 \- name: $skip
 in: query
 schema:
 type: integer
 format: int64
 \- name: $skipToken
 in: query
 schema:
 type: string
 \- name: $top
 in: query
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 post:
 tags:
 \- Products
 summary: Create Product
 description: "Creates a new Product resource from the supplied JSON body and returns its location.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nCulture used to interpret the localized field values supplied in the request body.\\r\\n- \*\*omitted / null\*\*: tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): the specified culture.\\r\\n \\r\\n## Request Body\\r\\n \\r\\nA single JSON object whose properties match the writable fields published by\\r\\n\`/Products/$metadata\`. The body is normalized before reaching the application layer:\\r\\n \\r\\n- Must be a non-empty JSON object.\\r\\n- A JSON array is accepted only if it contains exactly one element.\\r\\n- Values are coerced to CLR primitives (\`string\`, \`long\`, \`double\`, \`bool\`, \`null\`),\\r\\n nested objects and arrays.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*201 Created\*\* — The \`Location\` header points to the new resource: \`/Products({id})\`.\\r\\nNo response body.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Payload normalization or validation failure (empty body,\\r\\n multi-element array, invalid field values, etc.). Validation errors are returned\\r\\n as \`ValidationFailureRepresentation\`.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or referenced resource not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nPOST /Products HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\nContent-Type: application/json\\r\\n \\r\\n{\\r\\n \\"prod\_ref\\": \\"SKU-001\\",\\r\\n \\"prod\_description\\": \\"New product\\",\\r\\n \\"cat\_id\\": 123\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 201 Created\\r\\nLocation: /Products(456)\\r\\n\`\`\`"
 operationId: CreateProductAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: >-
 Culture for localized field values in the request body
 (Accept-Language header)
 schema:
 type: string
 requestBody:
 description: JSON object with the Product fields to create
 content:
 application/json:
 schema: {}
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Products({productIdentifier}):
 get:
 tags:
 \- Products
 summary: Get Product
 description: "Returns a single Product resource by its identifier.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for localized content.\\r\\n- \*\*omitted / null\*\*: content in the tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): content localized in the specified culture.\\r\\n- \*\*\`\*\`\*\* and q-factor weighting are currently not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\n### $select\\r\\n \\r\\nComma-separated list of root-resource property names to include in the response.\\r\\nSee \`/Products/$metadata\` for the available properties.\\r\\nSelecting properties of embedded resources is not supported.\\r\\n \\r\\nExample: \`$select=prod\_description,prod\_tags\`\\r\\n \\r\\n### $expand\\r\\n \\r\\nComma-separated list of embedded collections to include (e.g. \`Variants\`).\\r\\nBy default, embedded collections are not included.\\r\\nOnly embedded collections (not embedded resources) are supported.\\r\\n \\r\\nExample: \`$expand=Variants\`\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — \`EntityRepresentation\` with the Product resource.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression (returns \`ValidationFailureRepresentation\`).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Product with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Products(456)?$select=prod\_description,prod\_tags&$expand=Variants HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: SearchProductAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (Accept-Language header)
 schema:
 type: string
 \- name: productIdentifier
 in: path
 description: Product resource identifier
 required: true
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Products({productId}):
 patch:
 tags:
 \- Products
 summary: Update Product
 description: "Updates an existing Product resource, applying only the fields supplied in the JSON body (PATCH semantics).\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nCulture used to interpret the localized field values supplied in the request body.\\r\\n- \*\*omitted / null\*\*: tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): the specified culture.\\r\\n \\r\\n## Request Body\\r\\n \\r\\nA single JSON object with the subset of writable fields to update (PATCH semantics —\\r\\nonly the supplied fields are modified). Field names must match those published by\\r\\n\`/Products/$metadata\`. Normalization rules:\\r\\n \\r\\n- Must be a non-empty JSON object.\\r\\n- A JSON array is accepted only if it contains exactly one element.\\r\\n- Values are coerced to CLR primitives, nested objects and arrays.\\r\\n- The \`cat\_id\` field is accepted as either a single integer or an array of integers\\r\\n to assign the product to one or several categories.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Update applied.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Payload normalization or validation failure\\r\\n (returns \`ValidationFailureRepresentation\` for validation errors).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Product with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nPATCH /Products(456) HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\nContent-Type: application/json\\r\\n \\r\\n{\\r\\n \\"prod\_description\\": \\"Updated description\\",\\r\\n \\"cat\_id\\": \[123, 124\]\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\n\`\`\`"
 operationId: UpdateProductAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: >-
 Culture for localized field values in the request body
 (Accept-Language header)
 schema:
 type: string
 \- name: productId
 in: path
 description: Product resource identifier
 required: true
 schema:
 type: integer
 format: int32
 requestBody:
 description: JSON object with the Product fields to update
 content:
 application/json:
 schema: {}
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 delete:
 tags:
 \- Products
 summary: Delete Product
 description: "Deletes the Product resource identified by the given identifier.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*204 No Content\*\* — Product deleted.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Product with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nDELETE /Products(456) HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 204 No Content\\r\\n\`\`\`"
 operationId: DeleteProductAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: >-
 Accept-Language header (not used for delete, accepted for
 consistency)
 schema:
 type: string
 \- name: productId
 in: path
 description: Product resource identifier
 required: true
 schema:
 type: integer
 format: int32
 responses:
 '204':
 description: No Content
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Products({productIdentifier})/Variants:
 get:
 tags:
 \- Products
 summary: Filter Product Variants
 description: "Filters the Variant resources nested within the specified Product using OData query options and returns the matching collection.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for the localized content:\\r\\n- \*\*culture-code\*\* (e.g. \`es\`, \`en-us\`) — returns content localized in the specified culture.\\r\\n- \*\*null / not set\*\* — returns content localized in the default culture.\\r\\n- \*\*\`\*\`\*\* — currently disabled.\\r\\n \\r\\nMultiple culture codes or q-factor weighting are not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nThe endpoint supports a subset of OData v4.01 URI conventions.\\r\\nThe full list of available properties can be obtained from \`GET /Variants/$metadata\`.\\r\\n \\r\\n### \`$select\`\\r\\nComma-separated list of Variant properties (implicit or custom) to include in the result.\\r\\nSelection of properties inside embedded resources/collections is not supported.\\r\\n- Example: \`frmt\_ref\`\\r\\n- Example: \`frmt\_ref,frmt\_tags\`\\r\\n \\r\\n### \`$expand\`\\r\\nComma-separated list of embedded collections to include in the result. By default, embedded collections are not included.\\r\\nOnly embedded collections are supported (not embedded resources).\\r\\n \\r\\n### \`$filter\`\\r\\nBoolean expression applied on root resource properties. Filtering on nested resource properties is not supported.\\r\\n- Logical operators: \`eq\`, \`ne\`, \`gt\`, \`lt\`, \`ge\`, \`le\`, \`or\`, \`and\`, \`in\`\\r\\n- String functions: \`contains\`, \`startswith\`, \`endswith\`\\r\\n- Supported value types: integer, big integer, double, decimal, string, date, datetimeoffset\\r\\n \\r\\n### \`$orderby\`\\r\\nSorting expression on a single root resource property. Multiple properties and embedded properties are not supported.\\r\\nFormat: \`PROPERTY (asc\|desc)\`. Default direction is \`asc\`.\\r\\n \\r\\n### \`$top\`\\r\\nPage size. Maximum and default is 100 items.\\r\\n \\r\\n### \`$skip\`\\r\\nOffset for the \*\*limit-and-offset paging strategy\*\* (used together with \`$top\`). Recommended when \`$orderby\` is required.\\r\\n \\r\\n### \`$skipToken\`\\r\\nContinuation token for the \*\*continuation-token paging strategy\*\*. Faster than limit-and-offset but does not support \`$orderby\`.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Returns a \`CollectionRepresentation\` with the matching Variant resources associated to the Product.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression or query parameter.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Product or tenant not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Products(987)/Variants?$select=frmt\_ref&$top=10 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: es\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterVariantsInProductAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (e.g. \`es\`, \`en-us\`)
 schema:
 type: string
 \- name: productIdentifier
 in: path
 description: Product resource identifier (path parameter)
 required: true
 schema:
 type: integer
 format: int64
 \- name: $filter
 in: query
 schema:
 type: string
 \- name: $orderby
 in: query
 schema:
 type: string
 \- name: $skip
 in: query
 schema:
 type: integer
 format: int64
 \- name: $skipToken
 in: query
 schema:
 type: string
 \- name: $top
 in: query
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Products({productIdentifier})/Variants({variantIdentifier}):
 get:
 tags:
 \- Products
 summary: Get Product Variant
 description: "Returns a single Variant resource nested within the specified Product, with the published fields selected via OData query options.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for the localized content:\\r\\n- \*\*culture-code\*\* (e.g. \`es\`, \`en-us\`) — returns content localized in the specified culture.\\r\\n- \*\*null / not set\*\* — returns content localized in the default culture.\\r\\n- \*\*\`\*\`\*\* — currently disabled.\\r\\n \\r\\nMultiple culture codes or q-factor weighting are not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nThe endpoint supports a subset of OData v4.01 URI conventions.\\r\\nThe full list of available properties can be obtained from \`GET /Variants/$metadata\`.\\r\\n \\r\\n### \`$select\`\\r\\nComma-separated list of Variant properties (implicit or custom) to include in the result.\\r\\nSelection of properties inside embedded resources/collections is not supported.\\r\\n- Example: \`frmt\_ref\`\\r\\n- Example: \`frmt\_ref,frmt\_tags\`\\r\\n \\r\\n### \`$expand\`\\r\\nComma-separated list of embedded collections to include in the result. By default, embedded collections are not included.\\r\\nOnly embedded collections are supported (not embedded resources).\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Returns an \`EntityRepresentation\` with the requested Variant.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression or query parameter.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Product, Variant or tenant not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Products(987)/Variants(12345)?$select=frmt\_ref HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: es\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: SearchVariantInProductAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (e.g. \`es\`, \`en-us\`)
 schema:
 type: string
 \- name: productIdentifier
 in: path
 description: Product resource identifier (path parameter)
 required: true
 schema:
 type: integer
 format: int64
 \- name: variantIdentifier
 in: path
 description: Variant resource identifier (path parameter)
 required: true
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Products/Changelog:
 get:
 tags:
 \- Products
 summary: Get Products Changelog
 description: "Returns a paginated collection of changelog entries recording changes to Products, filterable with OData query options.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nSupports \`$filter\`, \`$orderby\`, \`$top\`, \`$skip\` over the changelog fields.\\r\\n\`$select\`, \`$expand\` and \`$skipToken\` are not supported by this endpoint.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Collection of changelog entries (\`CollectionRepresentation\`).\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Products/Changelog?$orderby=changedAt desc&$top=50 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterProductsChangelogAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: $filter
 in: query
 description: OData \`$filter\` expression
 schema:
 type: string
 \- name: $orderby
 in: query
 description: OData \`$orderby\` expression
 schema:
 type: string
 \- name: $top
 in: query
 description: OData \`$top\` page size
 schema:
 type: integer
 format: int64
 \- name: $skip
 in: query
 description: OData \`$skip\` offset
 schema:
 type: integer
 format: int64
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Products({productIdentifier})/Changelog:
 get:
 tags:
 \- Products
 summary: Get Product Changelog
 description: "Returns a paginated collection of changelog entries for a single Product, filterable with OData query options.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nSupports \`$filter\`, \`$orderby\`, \`$top\`, \`$skip\` over the changelog fields.\\r\\n\`$select\`, \`$expand\` and \`$skipToken\` are not supported by this endpoint.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Collection of changelog entries for the specified Product.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Products(123)/Changelog?$top=20 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterProductChangelogAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: productIdentifier
 in: path
 description: Product resource identifier
 required: true
 schema:
 type: integer
 format: int64
 \- name: $filter
 in: query
 description: OData \`$filter\` expression
 schema:
 type: string
 \- name: $orderby
 in: query
 description: OData \`$orderby\` expression
 schema:
 type: string
 \- name: $top
 in: query
 description: OData \`$top\` page size
 schema:
 type: integer
 format: int64
 \- name: $skip
 in: query
 description: OData \`$skip\` offset
 schema:
 type: integer
 format: int64
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Products/$metadata:
 get:
 tags:
 \- Products
 summary: Get Product Metadata
 description: "The metadata is a JSON Schema document that describes:\\r\\n- The implicit and custom properties exposed by the Product resource.\\r\\n- The associated resources (\`Category\`, \`Attribute Set\`, \`Variant\`) and their relationships.\\r\\n \\r\\nThe schema should be consulted to build requests against the other Product endpoints\\r\\n(which fields can be used in \`$select\`, \`$filter\`, \`$orderby\`, request bodies, etc.).\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Returns the JSON Schema as a \`ServiceDocumentRepresentation\`.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or model not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Products/$metadata HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: GetProductMetadataAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Variants:
 get:
 tags:
 \- Variants
 summary: Filter Variants
 description: "Filters the tenant's Variant resources using OData query options and returns the matching collection.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for the localized content:\\r\\n- \*\*culture-code\*\* (e.g. \`es\`, \`en-us\`) — returns content localized in the specified culture.\\r\\n- \*\*null / not set\*\* — returns content localized in the default culture.\\r\\n- \*\*\`\*\`\*\* — currently disabled.\\r\\n \\r\\nMultiple culture codes or q-factor weighting are not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nThe endpoint supports a subset of OData v4.01 URI conventions.\\r\\nThe full list of available properties can be obtained from \`GET /Variants/$metadata\`.\\r\\n \\r\\n### \`$select\`\\r\\nComma-separated list of Variant properties (implicit or custom) to include in the result.\\r\\nSelection of properties inside embedded resources/collections is not supported.\\r\\n- Example: \`frmt\_ref\`\\r\\n- Example: \`frmt\_ref,frmt\_tags\`\\r\\n \\r\\n### \`$expand\`\\r\\nComma-separated list of embedded collections to include in the result. By default, embedded collections are not included.\\r\\nOnly embedded collections are supported (not embedded resources).\\r\\n \\r\\n### \`$filter\`\\r\\nBoolean expression applied on root resource properties. Filtering on nested resource properties is not supported.\\r\\n- Logical operators: \`eq\`, \`ne\`, \`gt\`, \`lt\`, \`ge\`, \`le\`, \`or\`, \`and\`, \`in\`\\r\\n- String functions: \`contains\`, \`startswith\`, \`endswith\`\\r\\n- Supported value types: integer, big integer, double, decimal, string, date, datetimeoffset\\r\\n- Example: \`contains(frmt\_ref, 'abc')\`\\r\\n- Example: \`frmt\_ref in ('A','B') and price gt 10\`\\r\\n \\r\\n### \`$orderby\`\\r\\nSorting expression on a single root resource property. Multiple properties and embedded properties are not supported.\\r\\nFormat: \`PROPERTY (asc\|desc)\`. Default direction is \`asc\`.\\r\\n- Example: \`frmt\_ref asc\`\\r\\n \\r\\n### \`$top\`\\r\\nPage size. Maximum and default is 100 items.\\r\\n \\r\\n### \`$skip\`\\r\\nOffset for the \*\*limit-and-offset paging strategy\*\* (used together with \`$top\`). Recommended when \`$orderby\` is required.\\r\\n \\r\\n### \`$skipToken\`\\r\\nContinuation token for the \*\*continuation-token paging strategy\*\*. Faster than limit-and-offset but does not support \`$orderby\`.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Returns a \`CollectionRepresentation\` with the matching Variant resources.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression or query parameter.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or resource not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Variants?$select=frmt\_ref&$top=10 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: es\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterVariantsAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (e.g. \`es\`, \`en-us\`)
 schema:
 type: string
 \- name: $filter
 in: query
 schema:
 type: string
 \- name: $orderby
 in: query
 schema:
 type: string
 \- name: $skip
 in: query
 schema:
 type: integer
 format: int64
 \- name: $skipToken
 in: query
 schema:
 type: string
 \- name: $top
 in: query
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 post:
 tags:
 \- Variants
 summary: Create Variant
 description: "Creates a new Variant resource from the supplied JSON body and returns its location in the \`Location\` header.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nCulture used to interpret the localized field values supplied in the request body.\\r\\n- \*\*omitted / null\*\*: tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): the specified culture.\\r\\n \\r\\n## Request Body\\r\\n \\r\\nA single JSON object whose properties match the writable fields published by\\r\\n\`/Variants/$metadata\`. The body is normalized before reaching the application layer:\\r\\n \\r\\n- Must be a non-empty JSON object.\\r\\n- A JSON array is accepted only if it contains exactly one element.\\r\\n- Values are coerced to CLR primitives (\`string\`, \`long\`, \`double\`, \`bool\`, \`null\`),\\r\\n nested objects and arrays.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*201 Created\*\* — The \`Location\` header points to the new resource: \`/Variants({id})\`.\\r\\nNo response body.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Payload normalization or validation failure (empty body,\\r\\n multi-element array, invalid field values, etc.). Validation errors are returned\\r\\n as \`ValidationFailureRepresentation\`.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or referenced Product resource not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nPOST /Variants HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\nContent-Type: application/json\\r\\n \\r\\n{\\r\\n \\"frmt\_ref\\": \\"SKU-001-RED-M\\",\\r\\n \\"prod\_id\\": 456\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 201 Created\\r\\nLocation: /Variants(789)\\r\\n\`\`\`"
 operationId: CreateVariantAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: >-
 Culture for localized field values in the request body
 (Accept-Language header)
 schema:
 type: string
 requestBody:
 description: JSON object with the Variant fields to create
 content:
 application/json:
 schema: {}
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Variants({variantIdentifier}):
 get:
 tags:
 \- Variants
 summary: Get Variant
 description: "Returns a single Variant resource identified by its identifier, with the published fields selected via OData query options.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for the localized content:\\r\\n- \*\*culture-code\*\* (e.g. \`es\`, \`en-us\`) — returns content localized in the specified culture.\\r\\n- \*\*null / not set\*\* — returns content localized in the default culture.\\r\\n- \*\*\`\*\`\*\* — currently disabled.\\r\\n \\r\\nMultiple culture codes or q-factor weighting are not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nThe endpoint supports a subset of OData v4.01 URI conventions.\\r\\nThe full list of available properties can be obtained from \`GET /Variants/$metadata\`.\\r\\n \\r\\n### \`$select\`\\r\\nComma-separated list of Variant properties (implicit or custom) to include in the result.\\r\\nSelection of properties inside embedded resources/collections is not supported.\\r\\n- Example: \`frmt\_ref\`\\r\\n- Example: \`frmt\_ref,frmt\_tags\`\\r\\n \\r\\n### \`$expand\`\\r\\nComma-separated list of embedded collections to include in the result. By default, embedded collections are not included.\\r\\nOnly embedded collections are supported (not embedded resources).\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Returns an \`EntityRepresentation\` with the requested Variant.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression or query parameter.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Variant or tenant not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Variants(12345)?$select=frmt\_ref HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: es\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: SearchVariantAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (e.g. \`es\`, \`en-us\`)
 schema:
 type: string
 \- name: variantIdentifier
 in: path
 description: Variant resource identifier (path parameter)
 required: true
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Variants({variantId}):
 patch:
 tags:
 \- Variants
 summary: Update Variant
 description: "Updates the writable fields of an existing Variant from the supplied JSON body using PATCH semantics (only the supplied fields are modified).\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nCulture used to interpret the localized field values supplied in the request body.\\r\\n- \*\*omitted / null\*\*: tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): the specified culture.\\r\\n \\r\\n## Request Body\\r\\n \\r\\nA single JSON object with the subset of writable fields to update (PATCH semantics —\\r\\nonly the supplied fields are modified). Field names must match those published by\\r\\n\`/Variants/$metadata\`. Normalization rules:\\r\\n \\r\\n- Must be a non-empty JSON object.\\r\\n- A JSON array is accepted only if it contains exactly one element.\\r\\n- Values are coerced to CLR primitives, nested objects and arrays.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Update applied.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Payload normalization or validation failure\\r\\n (returns \`ValidationFailureRepresentation\` for validation errors).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Variant with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nPATCH /Variants(789) HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\nContent-Type: application/json\\r\\n \\r\\n{\\r\\n \\"frmt\_ref\\": \\"SKU-001-RED-L\\"\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\n\`\`\`"
 operationId: UpdateVariantAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: >-
 Culture for localized field values in the request body
 (Accept-Language header)
 schema:
 type: string
 \- name: variantId
 in: path
 description: Variant resource identifier
 required: true
 schema:
 type: integer
 format: int32
 requestBody:
 description: JSON object with the Variant fields to update
 content:
 application/json:
 schema: {}
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 delete:
 tags:
 \- Variants
 summary: Delete Variant
 description: "Deletes the Variant resource identified by its identifier.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*204 No Content\*\* — Variant deleted.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Variant with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nDELETE /Variants(789) HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 204 No Content\\r\\n\`\`\`"
 operationId: DeleteVariantAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: >-
 Accept-Language header (not used for delete, accepted for
 consistency)
 schema:
 type: string
 \- name: variantId
 in: path
 description: Variant resource identifier
 required: true
 schema:
 type: integer
 format: int32
 responses:
 '204':
 description: No Content
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Variants/Changelog:
 get:
 tags:
 \- Variants
 summary: Get Variants Changelog
 description: "Returns the changelog entries recorded across the tenant's Variants, filtered and paged via OData query options.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nSupports \`$filter\`, \`$orderby\`, \`$top\`, \`$skip\` over the changelog fields.\\r\\n\`$select\`, \`$expand\` and \`$skipToken\` are not supported by this endpoint.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Collection of changelog entries (\`CollectionRepresentation\`).\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Variants/Changelog?$orderby=changedAt desc&$top=50 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterVariantsChangelogAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: $filter
 in: query
 description: OData \`$filter\` expression
 schema:
 type: string
 \- name: $orderby
 in: query
 description: OData \`$orderby\` expression
 schema:
 type: string
 \- name: $top
 in: query
 description: OData \`$top\` page size
 schema:
 type: integer
 format: int64
 \- name: $skip
 in: query
 description: OData \`$skip\` offset
 schema:
 type: integer
 format: int64
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Variants({variantIdentifier})/Changelog:
 get:
 tags:
 \- Variants
 summary: Get Variant Changelog
 description: "Returns the changelog entries recorded for the Variant identified by its identifier, filtered and paged via OData query options.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nSupports \`$filter\`, \`$orderby\`, \`$top\`, \`$skip\` over the changelog fields.\\r\\n\`$select\`, \`$expand\` and \`$skipToken\` are not supported by this endpoint.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Collection of changelog entries for the specified Variant.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Variants(123)/Changelog?$top=20 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterVariantChangelogAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: variantIdentifier
 in: path
 description: Variant resource identifier
 required: true
 schema:
 type: integer
 format: int64
 \- name: $filter
 in: query
 description: OData \`$filter\` expression
 schema:
 type: string
 \- name: $orderby
 in: query
 description: OData \`$orderby\` expression
 schema:
 type: string
 \- name: $top
 in: query
 description: OData \`$top\` page size
 schema:
 type: integer
 format: int64
 \- name: $skip
 in: query
 description: OData \`$skip\` offset
 schema:
 type: integer
 format: int64
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /Variants/$metadata:
 get:
 tags:
 \- Variants
 summary: Get Variant Metadata
 description: "The metadata is a JSON Schema document that describes:\\r\\n- The implicit and custom properties exposed by the Variant resource.\\r\\n- The associated resources (\`Product\`) and their relationships.\\r\\n \\r\\nThe schema should be consulted to build requests against the other Variant endpoints\\r\\n(which fields can be used in \`$select\`, \`$filter\`, \`$orderby\`, request bodies, etc.).\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Returns the JSON Schema as a \`ServiceDocumentRepresentation\`.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or model not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /Variants/$metadata HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: GetVariantMetadataAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /CustomEntities('{customEntityDenominator}'):
 get:
 tags:
 \- Custom Entities
 summary: Filter Custom Entities
 description: "Filters the items of a Custom Entity type, identified by its denominator, returning the\\r\\nmatching resources as a collection. Supports OData query options for selecting, expanding,\\r\\nfiltering, ordering and paging the results.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n### Accept-Language\\r\\n \\r\\nIndicates the preferred natural language and locale for the localized content:\\r\\n- \*\*culture-code\*\* (e.g. \`es\`, \`en-us\`) — returns content localized in the specified culture.\\r\\n- \*\*null / not set\*\* — returns content localized in the default culture.\\r\\n- \*\*\`\*\`\*\* — currently disabled.\\r\\n \\r\\nMultiple culture codes or q-factor weighting are not supported.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nThe endpoint supports a subset of OData v4.01 URI conventions.\\r\\nThe full list of available properties can be obtained from \`GET /CustomEntities('{denominator}')/$metadata\`.\\r\\n \\r\\n### \`$select\`\\r\\nComma-separated list of Custom Entity properties (implicit or custom) to include in the result.\\r\\nSelection of properties inside embedded resources/collections is not supported.\\r\\n- Example: \`abcd\_description\`\\r\\n- Example: \`abcd\_description,abcd\_tags\`\\r\\n \\r\\n### \`$expand\`\\r\\nComma-separated list of embedded collections to include in the result (when applicable). By default, embedded collections are not included.\\r\\nOnly embedded collections are supported (not embedded resources).\\r\\n \\r\\n### \`$filter\`\\r\\nBoolean expression applied on root resource properties. Filtering on nested resource properties is not supported.\\r\\n- Logical operators: \`eq\`, \`ne\`, \`gt\`, \`lt\`, \`ge\`, \`le\`, \`or\`, \`and\`, \`in\`\\r\\n- String functions: \`contains\`, \`startswith\`, \`endswith\`\\r\\n- Supported value types: integer, big integer, double, decimal, string, date, datetimeoffset\\r\\n \\r\\n### \`$orderby\`\\r\\nSorting expression on a single root resource property. Multiple properties and embedded properties are not supported.\\r\\nFormat: \`PROPERTY (asc\|desc)\`. Default direction is \`asc\`.\\r\\n- Example: \`abcd\_description asc\`\\r\\n \\r\\n### \`$top\`\\r\\nPage size. Maximum and default is 100 items.\\r\\n \\r\\n### \`$skip\`\\r\\nOffset for the \*\*limit-and-offset paging strategy\*\* (used together with \`$top\`). Recommended when \`$orderby\` is required.\\r\\n \\r\\n### \`$skipToken\`\\r\\nContinuation token for the \*\*continuation-token paging strategy\*\*. Faster than limit-and-offset but does not support \`$orderby\`.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Returns a \`CollectionRepresentation\` with the matching Custom Entity resources.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression or query parameter.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or Custom Entity not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /CustomEntities('Brand')?$select=abcd\_description&$top=10 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: es\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterCustomEntitiesAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: Preferred localization culture (e.g. \`es\`, \`en-us\`)
 schema:
 type: string
 \- name: customEntityDenominator
 in: path
 description: >-
 Custom Entity denominator (natural language name as defined in the
 PIM)
 required: true
 schema:
 type: string
 \- name: $filter
 in: query
 schema:
 type: string
 \- name: $orderby
 in: query
 schema:
 type: string
 \- name: $skip
 in: query
 schema:
 type: integer
 format: int64
 \- name: $skipToken
 in: query
 schema:
 type: string
 \- name: $top
 in: query
 schema:
 type: integer
 format: int64
 \- name: $select
 in: query
 schema:
 type: string
 \- name: $expand
 in: query
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 post:
 tags:
 \- Custom Entities
 summary: Create Custom Entity
 description: "Creates a new item for a Custom Entity type, identified by its denominator, from the supplied\\r\\nJSON object. On success returns \`201 Created\` with the new resource location in the \`Location\` header.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nCulture used to interpret the localized field values supplied in the request body.\\r\\n- \*\*omitted / null\*\*: tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): the specified culture.\\r\\n \\r\\n## Request Body\\r\\n \\r\\nA single JSON object whose properties match the writable fields published by\\r\\n\`/CustomEntities('{denominator}')/$metadata\`. The body is normalized before reaching the\\r\\napplication layer:\\r\\n \\r\\n- Must be a non-empty JSON object.\\r\\n- A JSON array is accepted only if it contains exactly one element.\\r\\n- Values are coerced to CLR primitives (\`string\`, \`long\`, \`double\`, \`bool\`, \`null\`),\\r\\n nested objects and arrays.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*201 Created\*\* — The \`Location\` header points to the new resource:\\r\\n\`/CustomEntities('{denominator}')/Item({id})\`. No response body.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Payload normalization or validation failure (empty body,\\r\\n multi-element array, invalid field values, etc.). Validation errors are returned\\r\\n as \`ValidationFailureRepresentation\`.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or Custom Entity denominator not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nPOST /CustomEntities('Brand') HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\nContent-Type: application/json\\r\\n \\r\\n{\\r\\n \\"abcd\_title\\": \\"Acme\\",\\r\\n \\"abcd\_description\\": \\"Acme brand\\"\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 201 Created\\r\\nLocation: /CustomEntities('Brand')/Item(42)\\r\\n\`\`\`"
 operationId: CreateCustomEntityAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: >-
 Culture for localized field values in the request body
 (Accept-Language header)
 schema:
 type: string
 \- name: customEntityDenominator
 in: path
 description: Custom Entity denominator (natural language name from the PIM)
 required: true
 schema:
 type: string
 requestBody:
 description: JSON object with the Custom Entity item fields to create
 content:
 application/json:
 schema: {}
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /CustomEntities('{customEntityDenominator}')/item({itemId}):
 patch:
 tags:
 \- Custom Entities
 summary: Update Custom Entity
 description: "Updates an existing item of a Custom Entity type, identified by its denominator and item\\r\\nidentifier, applying PATCH semantics so that only the supplied fields are modified. Returns\\r\\n\`200 OK\` when the update is applied.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Headers\\r\\n \\r\\n### Accept-Language\\r\\n \\r\\nCulture used to interpret the localized field values supplied in the request body.\\r\\n- \*\*omitted / null\*\*: tenant's default culture.\\r\\n- \*\*culture-code\*\* (e.g. \`en-US\`, \`es\`): the specified culture.\\r\\n \\r\\n## Request Body\\r\\n \\r\\nA single JSON object with the subset of writable fields to update (PATCH semantics —\\r\\nonly the supplied fields are modified). Field names must match those published by\\r\\n\`/CustomEntities('{denominator}')/$metadata\`. Normalization rules:\\r\\n \\r\\n- Must be a non-empty JSON object.\\r\\n- A JSON array is accepted only if it contains exactly one element.\\r\\n- Values are coerced to CLR primitives, nested objects and arrays.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Update applied.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Payload normalization or validation failure\\r\\n (returns \`ValidationFailureRepresentation\` for validation errors).\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Custom Entity denominator or item with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nPATCH /CustomEntities('Brand')/item(42) HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\nAccept-Language: en-US\\r\\nContent-Type: application/json\\r\\n \\r\\n{\\r\\n \\"abcd\_description\\": \\"Updated description\\"\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\n\`\`\`"
 operationId: UpdateCustomEntityAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: >-
 Culture for localized field values in the request body
 (Accept-Language header)
 schema:
 type: string
 \- name: customEntityDenominator
 in: path
 description: Custom Entity denominator (natural language name from the PIM)
 required: true
 schema:
 type: string
 \- name: itemId
 in: path
 description: Custom Entity item identifier
 required: true
 schema:
 type: integer
 format: int32
 requestBody:
 description: JSON object with the Custom Entity item fields to update
 content:
 application/json:
 schema: {}
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 delete:
 tags:
 \- Custom Entities
 summary: Delete Custom Entity
 description: "Deletes an item of a Custom Entity type, identified by its denominator and item identifier.\\r\\nReturns \`204 No Content\` when the item has been deleted.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*204 No Content\*\* — Custom Entity item deleted.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Custom Entity denominator or item with the given identifier does not exist.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nDELETE /CustomEntities('Brand')/item(42) HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 204 No Content\\r\\n\`\`\`"
 operationId: DeleteCustomEntityAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: Accept-Language
 in: header
 description: >-
 Accept-Language header (not used for delete, accepted for
 consistency)
 schema:
 type: string
 \- name: customEntityDenominator
 in: path
 description: Custom Entity denominator (natural language name from the PIM)
 required: true
 schema:
 type: string
 \- name: itemId
 in: path
 description: Custom Entity item identifier
 required: true
 schema:
 type: integer
 format: int32
 responses:
 '204':
 description: No Content
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /CustomEntities('{customEntityDenominator}')/Changelog:
 get:
 tags:
 \- Custom Entities
 summary: Get Custom Entities Changelog
 description: "Returns the changelog entries for a Custom Entity type, identified by its denominator, as a\\r\\ncollection. Supports OData query options to filter, order and page the results.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nSupports \`$filter\`, \`$orderby\`, \`$top\`, \`$skip\` over the changelog fields.\\r\\n\`$select\`, \`$expand\` and \`$skipToken\` are not supported by this endpoint.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Collection of changelog entries for the specified Custom Entity type.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /CustomEntities('Brand')/Changelog?$top=20 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterCustomEntitiesChangelogAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: customEntityDenominator
 in: path
 description: Custom Entity denominator (natural language name from the PIM)
 required: true
 schema:
 type: string
 \- name: $filter
 in: query
 description: OData \`$filter\` expression
 schema:
 type: string
 \- name: $orderby
 in: query
 description: OData \`$orderby\` expression
 schema:
 type: string
 \- name: $top
 in: query
 description: OData \`$top\` page size
 schema:
 type: integer
 format: int64
 \- name: $skip
 in: query
 description: OData \`$skip\` offset
 schema:
 type: integer
 format: int64
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /CustomEntities('{customEntityDenominator}')/Changelog({itemIdentifier}):
 get:
 tags:
 \- Custom Entities
 summary: Get Custom Entity Changelog
 description: "Returns the changelog entries for a single Custom Entity item, identified by its denominator\\r\\nand item identifier, as a collection. Supports OData query options to filter, order and page\\r\\nthe results.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## OData Query Support\\r\\n \\r\\nSupports \`$filter\`, \`$orderby\`, \`$top\`, \`$skip\` over the changelog fields.\\r\\n\`$select\`, \`$expand\` and \`$skipToken\` are not supported by this endpoint.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Collection of changelog entries for the specified Custom Entity item.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*400 Bad Request\*\* — Invalid OData expression.\\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /CustomEntities('Brand')/Changelog(123)?$top=20 HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: FilterCustomEntityChangelogAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: customEntityDenominator
 in: path
 description: Custom Entity denominator (natural language name from the PIM)
 required: true
 schema:
 type: string
 \- name: itemIdentifier
 in: path
 description: Custom Entity item identifier
 required: true
 schema:
 type: integer
 format: int64
 \- name: $filter
 in: query
 description: OData \`$filter\` expression
 schema:
 type: string
 \- name: $orderby
 in: query
 description: OData \`$orderby\` expression
 schema:
 type: string
 \- name: $top
 in: query
 description: OData \`$top\` page size
 schema:
 type: integer
 format: int64
 \- name: $skip
 in: query
 description: OData \`$skip\` offset
 schema:
 type: integer
 format: int64
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/CollectionRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /CustomEntities('{customEntityDenominator}')/layout:
 get:
 tags:
 \- Custom Entities
 summary: Get Custom Entity Layout
 description: "Unlike the Category model — which has a single layout shared by all categories — each Custom\\r\\nEntity type has its own layout, selected by the route's customEntityDenominator.\\r\\n \\r\\nThe layout describes how the Custom Entity edit form is rendered. It is a JSON document with a\\r\\n\`sections\` array; each section has a \`title\` and a \`rows\` array; each row has a\\r\\n\`fields\` array and, optionally, a divider (\`dividerType\` and \`dividerTitle\`).\\r\\nEach field carries an \`attributeId\` and a grid \`size\` — one of \`quarter\`,\\r\\n\`half\`, \`threeQuarters\` or \`row\`. When a row has a divider its \`dividerType\`\\r\\nis one of \`normal\`, \`wide\` or \`lineBreak\`. \`dividerType\` and\\r\\n\`dividerTitle\` are omitted from a row when they have no value, so a row without a divider\\r\\ncontains only its \`fields\`.\\r\\n \\r\\nA layout must be configured for the requested Custom Entity; if none exists the request returns\\r\\n\`404 Not Found\`."
 operationId: GetCustomEntityFormLayoutAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key
 schema:
 type: string
 \- name: customEntityDenominator
 in: path
 description: Denominator of the Custom Entity type whose layout is requested.
 required: true
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/EntityRepresentation'
 '401':
 description: Unauthorized
 '404':
 description: Not Found
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 put:
 tags:
 \- Custom Entities
 summary: Update Custom Entity Layout
 description: "Each Custom Entity type has its own layout identified by \`customEntityDenominator\`. The supplied\\r\\nlayout fully overwrites the currently stored layout for that Custom Entity; it is \*\*not merged\*\*.\\r\\n \\r\\nA layout must already exist for the requested Custom Entity — this operation replaces it and does\\r\\nnot create one. If none exists the request returns \`404 Not Found\`.\\r\\n \\r\\n## ⚠️ All attributes are required\\r\\n \\r\\nThe payload must contain \*\*every attribute currently in the stored layout\*\* — no more, no less.\\r\\nOmitting an attribute removes it from the form. Adding an attribute that is not already in the\\r\\nlayout is also rejected. Use \`GET /CustomEntities('{customEntityDenominator}')/layout\` first to\\r\\nobtain the current set of attributes.\\r\\n \\r\\nThis is different from \`PATCH /v2/AttributeSets({id})\`, where layouts may contain any subset of\\r\\nthe tenant's attributes.\\r\\n \\r\\n## Layout Structure\\r\\n \\r\\nThe payload has the same shape as the \`GET /CustomEntities('{customEntityDenominator}')/layout\` response:\\r\\n \\r\\n\`\`\`json\\r\\n{\\r\\n \\"sections\\": \[\\r\\n {\\r\\n \\"title\\": \\"General\\",\\r\\n \\"rows\\": \[\\r\\n {\\r\\n \\"fields\\": \[\\r\\n { \\"attributeId\\": \\"ce\_title\\", \\"size\\": \\"half\\" },\\r\\n { \\"attributeId\\": \\"ce\_ref\\", \\"size\\": \\"half\\" }\\r\\n \]\\r\\n },\\r\\n {\\r\\n \\"dividerType\\": \\"normal\\",\\r\\n \\"dividerTitle\\": \\"Details\\",\\r\\n \\"fields\\": \[\\r\\n { \\"attributeId\\": \\"ce\_description\\", \\"size\\": \\"row\\" }\\r\\n \]\\r\\n }\\r\\n \]\\r\\n }\\r\\n \]\\r\\n}\\r\\n\`\`\`\\r\\n \\r\\n\*\*\`size\`\*\* — one of: \`quarter\`, \`half\`, \`threeQuarters\`, \`row\`.\\r\\n \\r\\n\*\*\`dividerType\`\*\* — optional; one of: \`normal\`, \`wide\`, \`lineBreak\`. \`dividerTitle\` is optional\\r\\nand only meaningful when \`dividerType\` is set. Both are omitted from rows that have no divider.\\r\\n \\r\\n## Validation Rules\\r\\n \\r\\nIf any rule is violated the request returns \`400 Bad Request\` describing each failure:\\r\\n \\r\\n- The layout must contain every attribute currently in the stored layout — no more, no less.\\r\\n- No \`attributeId\` may appear more than once.\\r\\n- Each field \`size\` must be one of: \`quarter\`, \`half\`, \`threeQuarters\`, \`row\`.\\r\\n- The sum of field sizes within any single row must not exceed a full row.\\r\\n- Every row must contain at least one field.\\r\\n- Section \`title\` values must be unique (case-insensitive).\\r\\n- When a row sets \`dividerType\` it must be one of: \`normal\`, \`wide\`, \`lineBreak\`."
 operationId: UpdateCustomEntityFormLayoutAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key
 schema:
 type: string
 \- name: customEntityDenominator
 in: path
 description: Denominator of the Custom Entity type whose layout is replaced.
 required: true
 schema:
 type: string
 requestBody:
 description: The new form layout to store
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/FormLayoutDto'
 responses:
 '204':
 description: No Content
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 type: string
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /CustomEntities/$metadata:
 get:
 tags:
 \- Custom Entities
 summary: Get Custom Entities Metadata
 description: "The metadata is a JSON Schema document that lists the Custom Entities defined in the PIM\\r\\nfor the current tenant, together with their relationships. Use the returned denominators\\r\\nto query individual Custom Entity schemas via \`GET /CustomEntities('{denominator}')/$metadata\`.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Returns the JSON Schema as a \`ServiceDocumentRepresentation\`.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /CustomEntities/$metadata HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: GetCustomEntitiesMetadataAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /CustomEntities('{customEntityDenominator}')/$metadata:
 get:
 tags:
 \- Custom Entities
 summary: Get Custom Entity Metadata
 description: "The metadata is a JSON Schema document that describes the implicit and custom properties\\r\\nexposed by the specified Custom Entity resource. The schema should be consulted to build\\r\\nrequests against the other Custom Entity endpoints (which fields can be used in \`$select\`,\\r\\n\`$filter\`, \`$orderby\`, request bodies, etc.).\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — Returns the JSON Schema as a \`ServiceDocumentRepresentation\`.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or Custom Entity not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /CustomEntities('Brand')/$metadata HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: GetCustomEntityMetadataAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 \- name: customEntityDenominator
 in: path
 description: >-
 Custom Entity denominator (natural language name as defined in the
 PIM)
 required: true
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
 /$metadata:
 get:
 tags:
 \- Metadata
 summary: Get Catalog Metadata
 description: "Returns the Catalog metadata as a JSON Schema document describing every resource\\r\\n(\`Category\`, \`Attribute Set\`, \`Product\`, \`Variant\`, \`Point of Sale\`) and the relationships\\r\\nbetween them. Use it to build requests against the rest of the API.\\r\\n \\r\\n## Authentication\\r\\n \\r\\nRequires a valid API key in the \`X-API-KEY\` header.\\r\\n \\r\\n## Response\\r\\n \\r\\n\*\*200 OK\*\* — A JSON schema document describing every resource in the Catalog\\r\\n(\`Category\`, \`Attribute Set\`, \`Product\`, \`Variant\`, \`Point of Sale\`) and the relationships\\r\\nbetween them. Use this document to build requests against the rest of the API.\\r\\n \\r\\n## Error Responses\\r\\n \\r\\n- \*\*401 Unauthorized\*\* — Missing or invalid API key.\\r\\n- \*\*404 Not Found\*\* — Tenant or model not found.\\r\\n- \*\*500 Internal Server Error\*\* — Unexpected technical error.\\r\\n \\r\\n## Example\\r\\n \\r\\n\*\*Request:\*\*\\r\\n\`\`\`http\\r\\nGET /$metadata HTTP/1.1\\r\\nX-API-KEY: your-api-key-here\\r\\n\`\`\`\\r\\n \\r\\n\*\*Response:\*\*\\r\\n\`\`\`http\\r\\nHTTP/1.1 200 OK\\r\\nContent-Type: application/json\\r\\n\`\`\`"
 operationId: GetMetadataAsync
 parameters:
 \- name: X-API-KEY
 in: header
 description: Tenant's API key (required)
 schema:
 type: string
 responses:
 '200':
 description: OK
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ServiceDocumentRepresentation'
 '400':
 description: Bad Request
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ValidationFailureRepresentation'
 '401':
 description: Unauthorized
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '404':
 description: Not Found
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ProblemDetails'
 '500':
 description: Internal Server Error
 content:
 application/json:
 schema:
 $ref: '#/components/schemas/ErrorRepresentation'
components:
 schemas:
 CollectionRepresentation:
 type: object
 properties:
 '@readLink':
 type: string
 nullable: true
 '@nextLink':
 type: string
 nullable: true
 '@deltaLink':
 type: string
 nullable: true
 '@context':
 type: string
 nullable: true
 value:
 nullable: true
 '@count':
 type: integer
 format: int64
 nullable: true
 additionalProperties: false
 ValidationFailureRepresentation:
 type: object
 properties:
 validationFailures:
 type: object
 additionalProperties:
 type: array
 items: {}
 nullable: true
 additionalProperties: false
 example:
 validationFailures:
 Layout:
 \- PropertyName: Layout
 ErrorMessage: >-
 The layout must contain exactly the attributes of the stored
 layout. Missing: tags. Unknown: extra\_field.
 AttemptedValue: null
 ProblemDetails:
 type: object
 properties:
 type:
 type: string
 nullable: true
 title:
 type: string
 nullable: true
 status:
 type: integer
 format: int32
 nullable: true
 detail:
 type: string
 nullable: true
 instance:
 type: string
 nullable: true
 additionalProperties: {}
 ErrorRepresentation:
 type: object
 properties:
 error:
 type: string
 nullable: true
 readOnly: true
 details:
 nullable: true
 readOnly: true
 additionalProperties: false
 NavigationLink:
 type: object
 properties:
 uri:
 type: string
 format: uri
 nullable: true
 additionalProperties: false
 AssociationLink:
 type: object
 properties:
 uri:
 type: string
 format: uri
 nullable: true
 additionalProperties: false
 EntityRepresentation:
 type: object
 properties:
 '@readLink':
 type: string
 nullable: true
 '@editLink':
 type: string
 nullable: true
 '@etag':
 type: string
 nullable: true
 '@navigationLinks':
 type: array
 items:
 $ref: '#/components/schemas/NavigationLink'
 nullable: true
 '@associationLinks':
 type: array
 items:
 $ref: '#/components/schemas/AssociationLink'
 nullable: true
 '@context':
 type: string
 nullable: true
 value:
 nullable: true
 additionalProperties: false
 ReadLink:
 type: object
 properties:
 uri:
 type: string
 format: uri
 nullable: true
 additionalProperties: false
 ServiceDocumentRepresentation:
 type: object
 properties:
 readLink:
 $ref: '#/components/schemas/ReadLink'
 value:
 nullable: true
 additionalProperties: false
 FormFieldDto:
 type: object
 properties:
 attributeId:
 type: string
 nullable: true
 size:
 enum:
 \- quarter
 \- half
 \- threeQuarters
 \- row
 type: string
 additionalProperties: false
 FormRowDto:
 type: object
 properties:
 fields:
 type: array
 items:
 $ref: '#/components/schemas/FormFieldDto'
 nullable: true
 dividerType:
 enum:
 \- normal
 \- wide
 \- lineBreak
 type: string
 nullable: true
 dividerTitle:
 type: string
 nullable: true
 additionalProperties: false
 FormSectionDto:
 type: object
 properties:
 title:
 type: string
 nullable: true
 rows:
 type: array
 items:
 $ref: '#/components/schemas/FormRowDto'
 nullable: true
 additionalProperties: false
 FormLayoutDto:
 type: object
 properties:
 sections:
 type: array
 items:
 $ref: '#/components/schemas/FormSectionDto'
 nullable: true
 additionalProperties: false
 example:
 sections:
 \- title: General
 rows:
 \- fields:
 \- attributeId: code
 size: half
 \- attributeId: name
 size: half
 \- fields:
 \- attributeId: parent\_ref
 size: row
 dividerType: normal
 dividerTitle: Hierarchy
 \- title: Content
 rows:
 \- fields:
 \- attributeId: status
 size: quarter
 \- attributeId: description
 size: threeQuarters
 \- fields:
 \- attributeId: image
 size: half
 \- attributeId: tags
 size: half
 CreateAttributeSetBody:
 type: object
 properties:
 name:
 type: string
 nullable: true
 productLayout:
 $ref: '#/components/schemas/FormLayoutDto'
 variantLayout:
 $ref: '#/components/schemas/FormLayoutDto'
 additionalProperties: false
 description: "Request body for M:Sl.Apps.Catalog.Host.Rest.Controllers.ApplicationController.CreateAttributeSet(Sl.Apps.Catalog.Host.Rest.Controllers.ApplicationController.CreateAttributeSetBody,System.Threading.CancellationToken). Sl.Apps.Catalog.Host.Rest.Controllers.ApplicationController.CreateAttributeSetBody.Name is required and must be\\r\\nunique; the layouts are optional. An omitted Sl.Apps.Catalog.Host.Rest.Controllers.ApplicationController.CreateAttributeSetBody.ProductLayout defaults to a standard\\r\\nlayout, while an omitted Sl.Apps.Catalog.Host.Rest.Controllers.ApplicationController.CreateAttributeSetBody.VariantLayout results in no Variant layout being created.\\r\\nThe layout shape matches the types returned by M:Sl.Apps.Catalog.Host.Rest.Controllers.ApplicationController.GetAttributeSet(System.String,System.Threading.CancellationToken)."
 UpdateAttributeSetBody:
 type: object
 properties:
 name:
 type: string
 nullable: true
 productLayout:
 $ref: '#/components/schemas/FormLayoutDto'
 variantLayout:
 $ref: '#/components/schemas/FormLayoutDto'
 additionalProperties: false
 description: "Request body for M:Sl.Apps.Catalog.Host.Rest.Controllers.ApplicationController.UpdateAttributeSet(System.String,Sl.Apps.Catalog.Host.Rest.Controllers.ApplicationController.UpdateAttributeSetBody,System.Threading.CancellationToken). All members are optional;\\r\\nomitted (\`null\`) members are left unchanged. The layout shape matches the\\r\\ntypes returned by M:Sl.Apps.Catalog.Host.Rest.Controllers.ApplicationController.GetAttributeSet(System.String,System.Threading.CancellationToken)."
