Getting started with PIM APIs

This document describes the step-by-step process of setting up fabric PIM using APIs. You also have the option to set up PIM using our Copilot UI, instructions for which are available here.

Product Overview

As brands and retailers grow and expand their product catalogs, it becomes necessary to enrich and manage additional product data. fabric Product Information Manager (PIM) solution alleviates the burden of managing large product data by means of a centralized cloud-based storage repository.

With PIM, you can create, import, enrich, validate, distribute, and manage complex product information, centrally. As a result, you deliver product experiences that drive sales through every channel. Your teams can collaborate on your product catalog and create compelling product experiences for your customers.

PIM helps you manage and enrich your product catalog, improve data quality, create a consistent customer experience, reduce time to market, easily integrate with external systems and storefronts, reduce management costs and risks, and scale your business faster.

Target readers

  • Solution integration partners responsible for configuring fabric products for an e-commerce business.
  • In-house developers using fabric products for their company’s commerce solution.

Key Terminologies

Let's familiarize ourselves with important PIM terminologies:

Products and Bundles

Products (also referred to as Items) are services or stand-alone items sold individually. Bundles are combo or collections of two or more products sold exclusively together or as individual products (depending on the configuration).

Product Variants

Variations of a product are referred to as Variants. For example, a Laptop that comes in three different sizes (13”, 15”, 17”) and four different colors (red, blue, grey, and white) has 12 variations.

Product Attributes

Properties of a product are referred to as product attributes. Attributes are the objective and factual descriptions of products that shoppers see when they browse through your site. Attributes may be technical specifications like size, weight, etc., design specifications like color, material, etc., or basic specifications such as name, description, ID, etc.

Also, the attributes of a product vary based on its type. For example, Attributes of a laptop may be its manufacturer, processor, GPU, RAM, storage, screen size, ports, battery backup, etc. Similarly, attributes of a headphone may be its manufacturer, connectivity, wireless transmission type, noise cancellation, microphones, etc. As you can see, Laptops and headphones have their own unique attributes that are different from each other.

Product attributes are crucial as they directly influence purchasing decisions. Well-defined attributes help shoppers find your products and services on the internet and make catalog management easier. Missing or unclear product attributes can cause drop in product sales. When you go online to buy your MacBook Pro, would you prefer to buy it without knowing the screen size? Likewise, shoppers do not make purchase decisions without knowing the required details.

Complete and correct product information help shoppers narrow down their search with minimal cognitive load. Attributes are not only used to show information but are also crucial in filtering. For example, if the size attribute is not specified for a laptop, it will not appear when a shopper tries to filter laptops by size.

Mandatory and Optional Attributes

Product attributes become mandatory only in the context of the category in which they belong. For example, Laptops under the Electronics category might have a different set of mandatory attributes than the Sofas under the Furniture category.

Attribute Groups

By grouping attributes, you can create a templatized approach to fill out information for similar products. For instance, Weight, Width, Height, and Length form the dimensions of a product. By grouping them as Dimensions can ease maintenance. Instead of assigning individual dimensions to a category, you can easily assign the attribute group Dimensions to ensure that all the above attributes are assigned correctly (and avoid accidental misses) to all products in the category.

Similar to Dimensions, you can create other attribute groups based on your requirement such as Technical attributes, Design attributes, Core attributes, etc.

Note: An attribute may belong to more than one attribute group.

Attributes Mapping

Attribute mapping provides the flexibility for merchants to create attributes with their preferred names. For example, a merchant may call a product’s unique identifier a Part Number whereas fabric may call it an SKU. With attribute mapping, it is possible to define Part Number = SKU. This way, merchants can continue useing their preferred term "Part Number" and fabric will identify Part Number as SKU across all services such as OMS and Offers.

Categories

Category (also called hierarchy or nodes) is a hierarchical structure to organize products and services into intuitive groups. Organizing products in this way simplifies product discovery and lifecycle management. Categories are most helpful when browsing to find similar items.

Shoppers are more likely to buy when your site is user-friendly and easy to navigate. Hence, categorization of products is crucial to enable “search” and “filters” functions within your website. Otherwise, shoppers will find it cumbersome to navigate through your site or find their desired products. As a result, sales will get impacted.

Also, external search engines can better understand your site by scanning it and indexing it. In addition, while using analytics and reporting, you can determine which categories are performing well and which aren't. This will help you make informed business decisions.

There are two types of categories - Primary and Alternate. They enable you to create, import, organize, and distribute product information.

Primary categories

It is the original catalog tree with nested levels of categories that place each product where it belongs, within a category. For example, Computers is a parent category with Laptops and Desktops as child categories, and MacBook Pro is a product within Laptops. This organization can be represented as Computers -> Laptops -> MacBook Pro.

Alternate categories

They serve as alternate organizations of the Primary category. Their main purpose is distribution management by displaying products on your website based on separate browsing structures required to achieve specific merchandising objectives, such as organizational requirements, multi-regional assortments, multi-channel assortments, and collections.

For example, a company that sells, repairs, and supports computers and related products will have a Primary category containing a full list of its SKUs. However, this Primary category is not granular enough to use in their storefront. Hence, multiple Alternate hierarchies are created to target specific shopper segments. For laptop consumers, they'll have an Alternate category that lists all the laptops and desktops. For large businesses, they'll have another Alternate category that lists all the commercial laptops, PCs, printers, and servers. Both of these Alternate categories are filters of the Primary category, tailored to suit specific merchandising strategies.

Note: Products are only added to the Primary category. They are then populated to Alternate categories by using Primary categories as sources.

Category attributes

They enable you to define characteristics of categories and child categories.

Note: Child categories inherit attributes of parent categories, by default.

Levels of categories

To add products to your catalog, you must first create a basic structure of the organization through categories and child categories. Products can be assigned to Level 0 and above. Typically, categories are created before products are added to them. Hence, it is crucial to visualize and build a category tree before you start adding products.

Prerequisite to setup PIM

Consider that you, as a developer, are entrusted to set up PIM for an imaginary firm CDE Corp, which sells computers and related products.

Here is a short checklist before you start with fabric PIM.

Do you have:

  • x-api-key for the environment?
  • List of product attributes to be created?
  • List of mandatory and optional product attributes?
  • Organization of the Primary category?
  • Organization of Alternate categories?
  • List of attribute groups?
  • Mapping of product attributes?
  • List of products to be added?
  • Names of bundles to be created and the products to be added within the bundles?

Many of the curl calls include x-api-key in an HTTP header. It is one of the current authentication mechanisms and API calls will be rejected with a 403 error code if it is missed.

You’ll receive two different x-api-keys from fabric support for each environment you use: one for products and one for categories. Example: For the sandbox environment, you receive two x-api-keys:

Pass the appropriate x-api-key to the API based upon the environment and path you’re calling.

Setting up PIM - A basic sample

To set up PIM for fictional CDE corp, you are given x-api-key: 5YeSOBkZK75aCxdnzJvQw5v5eJGqKMf09Ka7VUvD by fabric.inc

As per the requirement, you must build the following Primary categories for CDE Corp in PIM.

Hierarchical structure of primary categories

Level 0 Level 1 Level 2
Desktops Gaming
Workstations
Laptops Dell
Lenovo
Apple MacBook Air
MacBook Pro
Monitors 24
32
49
Storage SSD
NVMe
Disk
Networking Router
Wifi
Cables
Peripherals Keyboards
Mice
HOTAS

1. Add product attributes

As a recommended first step, add the following product attributes to PIM and mark them mandatory and optional:

Attribute name Attribute type Mandatory
SKU text True
Title text True
Published boolean, True
Image text Optional
Description text Optional
Variants options Optional
Width decimal Optional
Weight decimal Optional
Height decimal Optional
Length decimal Optional
Manufacturer text Optional
Memory text Optional
Chipset text Optional
Graphics text Optional
Processor text Optional
Storage text Optional
Operating System text Optional
Resolution text Optional
Power text Optional
Diagonal decimal Optional
Frequency decimal Optional
Audio text Optional
Bandwidth text Optional
Response Time decimal Optional
Sockets text Optional

Note: The Image attribute is a text field used for storing a URL to an image (example - http://example.com/phone.jpg).

In the future, PIM will also support Digital Asset Manager (DAM), enabling you to manage digital assets more efficiently. This will save you time and effort from storing images separately and linking them to PIM. Using DAM, you can create an image carousel of up to twenty images in a single attribute.

Here is the curl call to create all of the above attributes.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-product/v1/product/attribute/bulk' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'content-type: application/json' \
-d '[
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "SKU",
        "description": "Item SKU",
        "validation": { "required": true }
    },
    {
        "action": "CREATE",
        "type": "BOOLEAN",
        "target": "ITEM",
        "name": "Published",
        "description": "Whether this item is visible to customers",
        "validation": { "required": true }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Title",
        "description": "Title of item",
        "validation": { "required": true }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Description",
        "description": "Free-form text describing the item to customers",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "OPTIONS",
        "optionsType": "TEXT",
        "optionSelectType": "SINGLE",
        "target": "ITEM",
        "name": "Variants",
        "validation": {
          "required": false,
          "oneOf": ["Apple", "AMD", "Intel"]
        }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Image",
        "description": "URL to image of item",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Manufacturer",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "DECIMAL",
        "target": "ITEM",
        "name": "Weight",
        "description": "Weight of item in KG",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "DECIMAL",
        "target": "ITEM",
        "name": "Height",
        "description": "Height in cm",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "DECIMAL",
        "target": "ITEM",
        "name": "Width",
        "description": "Width in cm",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "DECIMAL",
        "target": "ITEM",
        "name": "Length",
        "description": "Length in cm",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Processor",
        "description": "Processor model, and other summary details",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Chipset",
        "description": "Chipset motherboard is based on",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Memory",
        "description": "Size and latency summary of RAM",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Graphics",
        "description": "Model and memory of GPU",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Storage",
        "description": "Size and latency summary of storage",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Power",
        "description": "Maximum power draw of system components supported by PSU",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Operating System",
        "description": "OS preinstalled on system",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Resolution",
        "description": "WxH of monitor",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "DECIMAL",
        "target": "ITEM",
        "name": "Diagonal",
        "description": "Length of monitor diagonal in inches",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "DECIMAL",
        "target": "ITEM",
        "name": "Frequency",
        "description": "Maximum refresh rate supported by monitor",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "DECIMAL",
        "target": "ITEM",
        "name": "Response Time",
        "description": "Gray-to-gray delay in ms",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Connector",
        "description": "Summary of input connectors supported by monitor",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Audio",
        "description": "Summary of speakers on monitor",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Bandwidth",
        "description": "Summary of interface bandwidths of item",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Sockets",
        "description": "Summary of various electrical interfaces supported by item",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "DECIMAL",
        "target": "ITEM",
        "name": "DPI",
        "description": "Physical resolution, like with mice and printers",
        "validation": { "required": false }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "ITEM",
        "name": "Layout",
        "description": "Keyboard layout",
        "validation": { "required": false }
    }
]'

Attribute - Bulk Import

To create these attributes using CSV instead of the bulk curl call, you can use API. Download the basic CSV template using the following curl call:

curl 'https://<env>.copilot.fabric.inc/api-product/v1/product/bulk/template/attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'Authorization: <...snip...>'

Path to get the template: /api-product/v1/product/bulk/template/attribute

Once the template is used to create CSV with the required attribute details, place request to get the location where the CSV should be uploaded in S3. This call returns the upload URL:

curl -XPOST 'https://<env>.copilot.fabric.inc/api-product/v1/upload-url/attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'authorization: <...snip...>'
--header 'x-api-key: <...snip...>' \
--header 'content-type: application/json' \
--data-raw '{
    "fileName": "attributes.csv"
}'

Then, upload the CSV to the returned URL:

curl -XPUT 'https://greatwall-sandbox-bulk-import-pim.s3.amazonaws.com/attribute/<...snip...>/sandbox/1646769995703-attributes.csv?X-Amz-Algorithm=AWS4-HMAC-SHA256<...snip...>' \
--header 'content-type: text/csv' \
--data-raw '@File location'

Once uploaded, PIM will process the CSV. You can check the status of the import with the following call:

curl 'https://<env>.copilot.fabric.inc/api-product/v1/product/bulk/file/1646769995703-attributes.csv/status' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>'

Here's a sample - Download File

2. Attribute Mapping

The next step is attribute mapping. That is, mapping of terms used by CDE corp with terms used in PIM. This is a one-time effort to ensure consistency and data integrity.

Here is an API call that maps five attributes we’ve created earlier (SKU, Title, Image, Published, and Variants) to the five mappings (sku, title, image, active, and isVariant):

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-product/v1/product/attribute/mapping' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'content-type: application/json' \
-d '{
  "mappings": [
    {
      "attributeName": "SKU",
      "mapping": "sku"
    },
    {
      "attributeName": "Title",
      "mapping": "title"
    },
    {
      "attributeName": "Image",
      "mapping": "image"
    },
    {
      "attributeName": "Published",
      "mapping": "active"
    },
    {
      "attributeName": "Variants",
      "mapping": "isVariant"
    }
  ]
}'

3. Create Primary category

In this step, we'll create a hierarchy of Primary categories, which we'll later use to organize products. To keep track of what we are trying to accomplish, refer to the hierarchical structure given by CDE corp.

Level 0

To begin with, we will create the first level (that is, Level 0) categories: Desktops, Laptops, Monitors, Storage, Networking, and Peripherals.

Level 0
  • SKU
  • Title
  • Description
  • Image
  • Published
  • Manufacturer
  • Weight
  • Height
  • Width
  • Length
Note: These 10 attributes are common to all the CDE products, hence these attributes are added to the first Layer - Level 0
Desktops
  • Processor
  • Chipset
  • Memory
  • Graphics
  • Storage
  • Resolution
  • Power
  • Operating System
Laptops
  • Processor
  • Chipset
  • Memory
  • Graphics
  • Storage
  • Resolution
  • Power
  • Operating System
Monitors
  • Resolution
  • Diagonal
  • Frequency
  • Response Time
  • Connector
  • Audio
  • Sockets
Storage
  • Power
  • Connector
  • Storage
  • Bandwidth
Networking
  • Power
  • Bandwidth
  • Sockets
Peripherals
  • Connector
Mice
  • DPI
Keyboards
  • Layout

The curl calls creating the layer-0 (root) categories.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Desktops"
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Laptops"
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Monitors"
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Storage"
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Networking"
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Peripherals"
}'

Level 1

After creating the root category (Level 0), we’ll now create the first set of children categories - Level 1.

In our example, there are multiple Level 0 categories, but it is not necessary to create all Level 0 categories before adding children categories. You only need to create the Level 0 categories for which children categories should be added.

Level 1 categories are as follows:

Level 1 categories Association
Gaming, Workstations Child of Desktops category
Work stations Child of Desktops category
Dell Child of Laptops category
Lenovo Child of Laptops category
Apple Child of Laptops category
24 Child of Monitors category
32 Child of Monitors category
49 Child of Monitors category
SSD Child of Storage node
NVMe Child of Storage node
Disk Child of Storage node
Switches Child of Networking category
Wifi Child of Networking category
Cables Child of Networking category
Keyboards Child of Networking category
Mice Child of Peripherals category
HOTAS Child of Peripherals category
curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Gaming",
    "parentNodeId": 2
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Workstations",
    "parentNodeId": 2
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Dell",
    "parentNodeId": 3
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Lenovo",
    "parentNodeId": 3
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Apple",
    "parentNodeId": 3
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "24",
    "parentNodeId": 4
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "32",
    "parentNodeId": 4
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \                                                                      --header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "49",
    "parentNodeId": 4
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \                                                                      --header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "SSD",
    "parentNodeId": 5
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \                                                                      --header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "NVMe",
    "parentNodeId": 5
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \                                                                      --header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Disk",
    "parentNodeId": 5
}'


curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \                                                                      --header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Switches",
    "parentNodeId": 6
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \                                                                      --header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Wifi",
    "parentNodeId": 6
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \                                                                      --header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Cables",
    "parentNodeId": 6
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \                                                                      --header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Keyboards",
    "parentNodeId": 7
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \                                                                      --header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Mice",
    "parentNodeId": 7
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \                                                                      --header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "HOTAS",
    "parentNodeId": 7
}'

Note: The parentcategoryIds comes from IDs returned by the previously-mentioned Level 0 calls.

Level 2

After creating Level 1 categories, we’ll now create children of the level 1 categories - Level 2. Going by the same example, there are just two - MacBook Air and MacBook Pro (children of the Apple category).

Curl calls to create category 2:

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "MacBook Air",
    "parentNodeId": 12
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "MacBook Pro",
    "parentNodeId": 12
}'

4. Assign product attributes

After creating product attributes and categories, we must now assign product attributes to categories. When product attributes are assigned to a category, they apply to all products within that category and its child categories. For example, if the Desktops category has the Title as a mandatory attribute, then any product added to Desktops, or a child category of Desktops must have a Title.

For CDE corp, the following attributes are mandatory for all products. We can achieve this by adding them to all Level 0 categories, although this is just one way to do it.

  • SKU
  • Title
  • Description
  • Image
  • Published
  • Manufacturer
  • Weight
  • Height
  • Width
  • Length

To reiterate and clarify mandatory and optional attributes - An attribute is mandatory or optional only in the context of the category it belongs to. For example, Resolution attribute may be mandatory for the Monitors category but not for the Networking category. Similarly, the Bandwidth attribute may be mandatory for the Networking category but not for the Monitors category.

You will see entries for this in all curl calls made below, as well as additional attributes (depending upon category).

Desktops and Laptops

For CDE Cord, the following attributes are additionally required for all products in the Desktops and Laptops categories:

  • Processor
  • Chipset
  • Memory
  • Graphics
  • Storage
  • Resolution
  • Power
  • Operating System
Adding product attributes to Desktops

Now, we have eighteen (including 10 generic attributes) product attributes to assign to the Desktops and Laptops categories.

Note: attributeId is returned in Create Attributes call and the categoryId is returned in the Create Category call.

If you do not have the attributeIds from the previous steps, you can get them by using this API call; there is also an example at the end of this document on how to use this call.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/item-attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 2,
    "itemAttributes": [
        {
            "attributeId": "62668daafbad57129fce476a",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476c",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4774",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4770",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476e",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4776",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4778",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce477a",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce4785",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce47c8",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce47cb",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47d3",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47d1",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47e2",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47cd",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47d5",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47fa",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47f8",
            "action": "SET",
            "mandatory": true
        }
    ]
}'
curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/item-attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 3,
    "itemAttributes": [
        {
            "attributeId": "62668daafbad57129fce476a",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476c",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4774",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4770",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476e",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4776",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4778",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce477a",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4785",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47c8",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47cb",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47d3",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47d1",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47e2",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47cd",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47d5",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47fa",
            "action": "SET",
            "mandatory": true
        }
    ]
}

Monitors

The following attributes must be additionally added to all Monitors:

  • Resolution
  • Diagonal
  • Frequency
  • Response Time
  • Connector
  • Audio
  • Sockets

So we have seventeen product attributes to assign to this category.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/item-attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 4,
    "itemAttributes": [
        {
            "attributeId": "62668daafbad57129fce476a",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476c",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4774",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4770",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476e",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4776",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4778",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce477a",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4785",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47c8",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47e2",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47fa",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4826",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce4828",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4824",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4820",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce482a",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce4837",
            "action": "SET",
            "mandatory": true
        }
    ]
}

Storage

The following attributes must be additionally added to Storage:

  • Power
  • Connector
  • Storage
  • Bandwidth

So, we have fourteen product attributes to assign to this category.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/item-attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 5,
    "itemAttributes": [
        {
            "attributeId": "62668daafbad57129fce476a",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476c",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4774",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4770",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476e",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4776",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4778",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce477a",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4785",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47c8",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47e2",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce4828",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47cd",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4835",
            "action": "SET",
            "mandatory": true
        }
    ]
}

Networking

The following attributes must be additionally added to all Networking:

  • Power
  • Bandwidth
  • Sockets

So we have thirteen product attributes to assign to this category.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/item-attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 6,
    "itemAttributes": [
        {
            "attributeId": "62668daafbad57129fce476a",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476c",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4774",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4770",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476e",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4776",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4778",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce477a",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4785",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47c8",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47e2",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce4837",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce4835",
            "action": "SET",
            "mandatory": true
        }
     ]
}'

Peripherals

The following attributes must be additionally added to all Peripherals:

  • Connector

So we have eleven product attributes to assign to this category.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/item-attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 7,
    "itemAttributes": [
        {
            "attributeId": "62668daafbad57129fce476a",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476c",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4774",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4770",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce476e",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4776",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4778",
            "action": "SET",
            "mandatory": false
        },
        {
            "attributeId": "62668daafbad57129fce477a",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4785",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce47c8",
            "action": "SET",
            "mandatory": true
        },
        {
            "attributeId": "62668daafbad57129fce4828",
            "action": "SET",
            "mandatory": false
        }
    ]
}'

Mice and Keyboards

All of the previously-mentioned examples are related to level 0 categories (that is Desktops and Laptops). When attributes are added to a category, all children categories of the category inherit those attributes. So, Lenovo and Apple (both children of Laptops) will have the same attributes as Laptops. In addition, child categories can have additional attributes of their own. Let’s try this out by adding DPI attribute to Mice, and Layout attribute to Keyboards categories (both child categories of Peripherals).

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/item-attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 22,
    "itemAttributes": [
        {
            "attributeId": "6267d7cc2957042b74cf8923",
            "action": "SET",
            "mandatory": true
        }
    ]
}'
curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/item-attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 23,
    "itemAttributes": [
        {
            "attributeId": "6267d7cc2957042b74cf891a",
            "action": "SET",
            "mandatory": true
        }
    ]
}'

5. Create products

Now that we have created product attributes, set up categories, and assigned product attributes to categories, we will now add products.

You can achieve this with APIs in two ways: by using JSON data in the request body or by uploading a CSV file.

Create using JSON (50 products)

A maximum of 50 products can be created per call. To fulfill our example, we must make two calls since we have 55 products to add.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-product/v1/product/bulk/insert' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'content-type: application/json' \
-d '[
    {
        "nodeName": "PRIMARY->Desktops->Workstations",
        "sku": "DELL16GBWWX",
        "attributeValues": [
            { "name": "Title",        "value": "Dell Workstation 16GB" },
            { "name": "Image",        "value": "http://example.com/dell16.jpg" },
            { "name": "Description",  "value": "A complete Dell workstation" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Dell" },
            { "name": "Weight",       "value": 10 },
            { "name": "Height",       "value": 100 },
            { "name": "Width",        "value": 100 },
            { "name": "Length",       "value": 25 },
            { "name": "Graphics",     "value": "GTX3060" },
            { "name": "Chipset",      "value": "X570" },
            { "name": "Processor",    "value": "Intel i7-11390" },
            { "name": "Power",        "value": "250W" },
            { "name": "Storage",      "value": "1024GB disk" },
            { "name": "Memory",       "value": "16GB" },
            { "name": "Resolution",   "value": "1920x1080" },
            { "name": "Operating System", "value": "Windows 10 Enterprise" }
        ]
    },
    {
        "nodeName": "PRIMARY->Desktops->Workstations",
        "sku": "DELL32GBWWX",
        "attributeValues": [
            { "name": "Title",        "value": "Dell Workstation 32GB" },
            { "name": "Image",        "value": "http://example.com/dell32.jpg" },
            { "name": "Description",  "value": "A large Dell workstation" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Dell" },
            { "name": "Weight",       "value": 10 },
            { "name": "Height",       "value": 100 },
            { "name": "Width",        "value": 100 },
            { "name": "Length",       "value": 25 },
            { "name": "Graphics",     "value": "GTX3070" },
            { "name": "Chipset",      "value": "X580" },
            { "name": "Processor",    "value": "Intel i7-11850" },
            { "name": "Power",        "value": "350W" },
            { "name": "Storage",      "value": "1024GB NVMe" },
            { "name": "Memory",       "value": "32GB" },
            { "name": "Resolution",   "value": "2560x1440 2ms" },
            { "name": "Operating System", "value": "Windows 10 Enterprise" }
        ]
    },
    {
        "nodeName": "PRIMARY->Desktops->Workstations",
        "sku": "DELL64GBWZ",
        "attributeValues": [
            { "name": "Title",        "value": "Dell Workstation 64GB" },
            { "name": "Image",        "value": "http://example.com/dell64.jpg" },
            { "name": "Description",  "value": "A master Dell workstation" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Dell" },
            { "name": "Weight",       "value": 10 },
            { "name": "Height",       "value": 100 },
            { "name": "Width",        "value": 100 },
            { "name": "Length",       "value": 25 },
            { "name": "Graphics",     "value": "GTX3090" },
            { "name": "Chipset",      "value": "X580" },
            { "name": "Processor",    "value": "Intel i9-12900K" },
            { "name": "Power",        "value": "500W" },
            { "name": "Storage",      "value": "4096GB NVMe" },
            { "name": "Memory",       "value": "64GB" },
            { "name": "Resolution",   "value": "3840x2160 1ms" },
            { "name": "Operating System", "value": "Windows 10 Enterprise" }
        ]
    },
    {
        "nodeName": "PRIMARY->Desktops->Gaming",
        "sku": "ALI24B",
        "attributeValues": [
            { "name": "Title",        "value": "The BEAST" },
            { "name": "Image",        "value": "http://example.com/beast24.jpg" },
            { "name": "Description",  "value": "Beat the competition!" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Alienware" },
            { "name": "Weight",       "value": 15 },
            { "name": "Height",       "value": 100 },
            { "name": "Width",        "value": 100 },
            { "name": "Length",       "value": 100 },
            { "name": "Graphics",     "value": "AMD 6700XT" },
            { "name": "Chipset",      "value": "X590" },
            { "name": "Processor",    "value": "AMD 5600" },
            { "name": "Power",        "value": "500W" },
            { "name": "Storage",      "value": "1024GB NVMe" },
            { "name": "Memory",       "value": "24GB" },
            { "name": "Resolution",   "value": "2560x1440 2ms 144Hz" },
            { "name": "Operating System", "value": "Windows 10 Pro" }
        ]
    },
    {
        "nodeName": "PRIMARY->Desktops->Gaming",
        "sku": "ALI32B",
        "attributeValues": [
            { "name": "Title",        "value": "The Mega BEAST" },
            { "name": "Image",        "value": "http://example.com/beast32.jpg" },
            { "name": "Description",  "value": "Beat the competition with an ax!" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Alienware" },
            { "name": "Weight",       "value": 15 },
            { "name": "Height",       "value": 100 },
            { "name": "Width",        "value": 100 },
            { "name": "Length",       "value": 100 },
            { "name": "Graphics",     "value": "AMD 6900XT" },
            { "name": "Chipset",      "value": "X590" },
            { "name": "Processor",    "value": "AMD 5800X3D" },
            { "name": "Power",        "value": "600W" },
            { "name": "Storage",      "value": "2048GB NVMe" },
            { "name": "Memory",       "value": "32GB" },
            { "name": "Resolution",   "value": "3840x2160 2ms 144Hz" },
            { "name": "Operating System", "value": "Windows 10 Home" }
        ]
    },
    {
        "nodeName": "PRIMARY->Desktops->Gaming",
        "sku": "ALI64B",
        "attributeValues": [
            { "name": "Title",        "value": "The BEAST times 9000" },
            { "name": "Image",        "value": "http://example.com/beast32.jpg" },
            { "name": "Description",  "value": "What competition? Bow down!" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Alienware" },
            { "name": "Weight",       "value": 15 },
            { "name": "Height",       "value": 100 },
            { "name": "Width",        "value": 100 },
            { "name": "Length",       "value": 100 },
            { "name": "Graphics",     "value": "AMD 6900XT" },
            { "name": "Chipset",      "value": "X590" },
            { "name": "Processor",    "value": "AMD Threadripper PRO 5975WX" },
            { "name": "Power",        "value": "800W" },
            { "name": "Storage",      "value": "4x2048GB NVMe EVO" },
            { "name": "Memory",       "value": "64GB" },
            { "name": "Resolution",   "value": "3840x2160 1ms 144Hz" },
            { "name": "Operating System", "value": "Windows 10 Pro" }
        ]
    },
    {
        "nodeName": "PRIMARY->Laptops->Apple->MacBook Air",
        "sku": "APLAIR8GB",
        "attributeValues": [
            { "name": "Title",        "value": "MacBook Air 8GB/256GB 13inch" },
            { "name": "Image",        "value": "http://example.com/appleair8GB.jpg" },
            { "name": "Description",  "value": "The smallest, lightest laptop from Apple" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Apple" },
            { "name": "Weight",       "value": 1.29 },
            { "name": "Height",       "value": 1.61 },
            { "name": "Width",        "value": 30.41 },
            { "name": "Length",       "value": 21.24 },
            { "name": "Graphics",     "value": "Integrated" },
            { "name": "Chipset",      "value": "M1" },
            { "name": "Processor",    "value": "M1" },
            { "name": "Power",        "value": "30W" },
            { "name": "Storage",      "value": "256GB NVMe" },
            { "name": "Memory",       "value": "8GB" },
            { "name": "Resolution",   "value": "2560x1600" }
        ]
    },
    {
        "nodeName": "PRIMARY->Laptops->Apple->MacBook Air",
        "sku": "APLAIR16GB",
        "attributeValues": [
            { "name": "Title",        "value": "MacBook Air 16GB/1024GB 13inch" },
            { "name": "Image",        "value": "http://example.com/appleair16GB.jpg" },
            { "name": "Description",  "value": "The smallest, lightest laptop from Apple" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Apple" },
            { "name": "Weight",       "value": 1.29 },
            { "name": "Height",       "value": 1.61 },
            { "name": "Width",        "value": 30.41 },
            { "name": "Length",       "value": 20.24 },
            { "name": "Graphics",     "value": "Integrated" },
            { "name": "Chipset",      "value": "M1" },
            { "name": "Processor",    "value": "M1" },
            { "name": "Power",        "value": "30W" },
            { "name": "Storage",      "value": "1024GB NVMe" },
            { "name": "Memory",       "value": "16GB" },
            { "name": "Resolution",   "value": "2560x1600" }
       ]
    },
    {
        "nodeName": "PRIMARY->Laptops->Apple->MacBook Pro",
        "sku": "APLPRO32GB",
        "attributeValues": [
            { "name": "Title",        "value": "MacBook Pro 32GB 15inch" },
            { "name": "Image",        "value": "http://example.com/applepro32GB.jpg" },
            { "name": "Description",  "value": "The smallest, lightest laptop from Apple" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Apple" },
            { "name": "Weight",       "value": 1.4 },
            { "name": "Height",       "value": 1.56 },
            { "name": "Width",        "value": 30.41 },
            { "name": "Length",       "value": 20.24 },
            { "name": "Graphics",     "value": "Integrated" },
            { "name": "Chipset",      "value": "M1" },
            { "name": "Processor",    "value": "M1" },
            { "name": "Power",        "value": "67W" },
            { "name": "Storage",      "value": "2048GB NVMe" },
            { "name": "Memory",       "value": "32GB" },
            { "name": "Resolution",   "value": "2560x1600" }
        ]
    },
    {
        "nodeName": "PRIMARY->Laptops->Apple->MacBook Pro",
        "sku": "APLPROMAX",
        "attributeValues": [
            { "name": "Title",        "value": "MacBook Pro Max" },
            { "name": "Image",        "value": "http://example.com/applepromax.jpg" },
            { "name": "Description",  "value": "The most powerful laptop from Apple" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Apple" },
            { "name": "Weight",       "value": 1.6 },
            { "name": "Height",       "value": 1.55 },
            { "name": "Width",        "value": 31.26 },
            { "name": "Length",       "value": 22.12 },
            { "name": "Graphics",     "value": "Integrated" },
            { "name": "Chipset",      "value": "M1" },
            { "name": "Processor",    "value": "M1 Max" },
            { "name": "Power",        "value": "96W" },
            { "name": "Storage",      "value": "8192GB NVMe" },
            { "name": "Memory",       "value": "64GB" },
            { "name": "Resolution",   "value": "3024x1964" }
        ]
    },
    {
        "nodeName": "PRIMARY->Laptops->Dell",
        "sku": "DELL54708G",
        "attributeValues": [
            { "name": "Title",        "value": "Precision 5470 8GB" },
            { "name": "Image",        "value": "http://example.com/dellprecision8GB.jpg" },
            { "name": "Description",  "value": "A Precision laptop for everyday life" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Dell" },
            { "name": "Weight",       "value": 1.48 },
            { "name": "Height",       "value": 1.9 },
            { "name": "Width",        "value": 30.06 },
            { "name": "Length",       "value": 21.03 },
            { "name": "Graphics",     "value": "Integrated Graphics UMA" },
            { "name": "Chipset",      "value": "Gen 3" },
            { "name": "Processor",    "value": "Intel i5-12500H" },
            { "name": "Power",        "value": "90W" },
            { "name": "Storage",      "value": "256GB NVMe" },
            { "name": "Memory",       "value": "8GB DDR5" },
            { "name": "Resolution",   "value": "1920x1200" }
        ]
    },
    {
        "nodeName": "PRIMARY->Laptops->Dell",
        "sku": "DELL547032G",
        "attributeValues": [
            { "name": "Title",        "value": "Precision 5470 32GB" },
            { "name": "Image",        "value": "http://example.com/dellprecision32GB.jpg" },
            { "name": "Description",  "value": "A Precision laptop for intense workloads" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Dell" },
            { "name": "Weight",       "value": 1.48 },
            { "name": "Height",       "value": 1.9 },
            { "name": "Width",        "value": 30.06 },
            { "name": "Length",       "value": 21.03 },
            { "name": "Graphics",     "value": "RTX A1000 4GB" },
            { "name": "Chipset",      "value": "Gen 3" },
            { "name": "Processor",    "value": "Intel i7-12800H" },
            { "name": "Power",        "value": "130W" },
            { "name": "Storage",      "value": "1024GB NVMe" },
            { "name": "Memory",       "value": "32GB DDR5" },
            { "name": "Resolution",   "value": "1920x1200" }
        ]
    },
    {
        "nodeName": "PRIMARY->Laptops->Lenovo",
        "sku": "THINKPADP15",
        "attributeValues": [
            { "name": "Title",        "value": "ThinkPad P15 8GB/512GB" },
            { "name": "Image",        "value": "http://example.com/thinkpad16GB.jpg" },
            { "name": "Description",  "value": "Durable work laptop with a proud heritage" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Lenovo" },
            { "name": "Weight",       "value": 1.76 },
            { "name": "Height",       "value": 1.91 },
            { "name": "Width",        "value": 36.58 },
            { "name": "Length",       "value": 24.80 },
            { "name": "Graphics",     "value": "NVIDIA T500 4GB" },
            { "name": "Chipset",      "value": "Gen 11" },
            { "name": "Processor",    "value": "i7-1185G7" },
            { "name": "Power",        "value": "65W" },
            { "name": "Storage",      "value": "512GB NVMe" },
            { "name": "Memory",       "value": "16GB" },
            { "name": "Resolution",   "value": "1920x1080" }
        ]
    },
    {
        "nodeName": "PRIMARY->Laptops->Lenovo",
        "sku": "THINKPADX1",
        "attributeValues": [
            { "name": "Title",        "value": "ThinkPad X1" },
            { "name": "Image",        "value": "http://example.com/thinkpad32GB.jpg" },
            { "name": "Description",  "value": "Cutting-edge work laptop" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Lenovo" },
            { "name": "Weight",       "value": 1.13 },
            { "name": "Height",       "value": 1.49 },
            { "name": "Width",        "value": 31.45 },
            { "name": "Length",       "value": 22.16 },
            { "name": "Graphics",     "value": "Intel Iris Xe" },
            { "name": "Chipset",      "value": "Gen 11" },
            { "name": "Processor",    "value": "i7-1165G7" },
            { "name": "Power",        "value": "65W" },
            { "name": "Storage",      "value": "2048GB NVMe" },
            { "name": "Memory",       "value": "32GB" },
            { "name": "Resolution",   "value": "3840x2400" }
        ]
    },
    {
        "nodeName": "PRIMARY->Monitors->24",
        "sku": "SAMSUNGS4",
        "attributeValues": [
            { "name": "Title",        "value": "24S40VA" },
            { "name": "Image",        "value": "http://example.com/samsungs4.jpg" },
            { "name": "Description",  "value": "Multimedia display good for videoconferencing" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Samsung" },
            { "name": "Weight",       "value": 5.8 },
            { "name": "Height",       "value": 47.47 },
            { "name": "Width",        "value": 54.17 },
            { "name": "Length",       "value": 19.52 },
            { "name": "Power",        "value": "18-40W" },
            { "name": "Resolution",   "value": "1920x1080" },
            { "name": "Response time", "value": 5 },
            { "name": "Connector",    "value": "1xHDMI 1.4, 1xDP 1.3" },
            { "name": "Diagonal",     "value": 24 },
            { "name": "Frequency",    "value": 75 },
            { "name": "Audio",        "value": "One speaker" },
            { "name": "Sockets",      "value": "3xUSB 3.0, audio in & out" }
        ]
    },
    {
        "nodeName": "PRIMARY->Monitors->32",
        "sku": "SAMSUNGS32",
        "attributeValues": [
            { "name": "Title",        "value": "S32A600" },
            { "name": "Image",        "value": "http://example.com/samsungs32.jpg" },
            { "name": "Description",  "value": "QHD monitor for crisp text and video" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Samsung" },
            { "name": "Weight",       "value": 6.9 },
            { "name": "Height",       "value": 58.05 },
            { "name": "Width",        "value": 71.62 },
            { "name": "Length",       "value": 21.14 },
            { "name": "Power",        "value": "0.5WW DPMS" },
            { "name": "Resolution",   "value": "2560x1440" },
            { "name": "Response time", "value": 5 },
            { "name": "Connector",    "value": "1xHDMI 1.4, 1xDP 1.3" },
            { "name": "Diagonal",     "value": 32 },
            { "name": "Frequency",    "value": 75 },
            { "name": "Sockets",      "value": "4xUSB 3.0" }
        ]
    },
    {
        "nodeName": "PRIMARY->Monitors->32",
        "sku": "AOC32",
        "attributeValues": [
            { "name": "Title",        "value": "Q32P2" },
            { "name": "Image",        "value": "http://example.com/aoc32.jpg" },
            { "name": "Description",  "value": "" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "AOC" },
            { "name": "Weight",       "value": 9.5 },
            { "name": "Height",       "value": 65.07 },
            { "name": "Width",        "value": 73.02 },
            { "name": "Length",       "value": 27.51 },
            { "name": "Power",        "value": "35W" },
            { "name": "Resolution",   "value": "2560x1440" },
            { "name": "Response time", "value": 4 },
            { "name": "Connector",    "value": "2xHDMI 1.4, 1xDP 1.2" },
            { "name": "Diagonal",     "value": 31.5 },
            { "name": "Frequency",    "value": 75 },
            { "name": "Sockets",      "value": "4xUSB, audio jack" }
        ]
    },
    {
        "nodeName": "PRIMARY->Monitors->32",
        "sku": "LG32",
        "attributeValues": [
            { "name": "Title",        "value": "32UN880-B" },
            { "name": "Image",        "value": "http://example.com/lg32.jpg" },
            { "name": "Description",  "value": "Respectable mid-range monitor" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "LG" },
            { "name": "Weight",       "value": 10.3 },
            { "name": "Height",       "value": 64 },
            { "name": "Width",        "value": 71.37 },
            { "name": "Length",       "value": 40.64 },
            { "name": "Power",        "value": "16-55W" },
            { "name": "Resolution",   "value": "3840x2160" },
            { "name": "Response time", "value": 5 },
            { "name": "Connector",    "value": "2xHDMI, 1xDP, 1xUSB-C" },
            { "name": "Diagonal",     "value": 31.5 },
            { "name": "Frequency",    "value": 60 },
            { "name": "Sockets",      "value": "2xUSB, audio jack" }
        ]
    },
    {
        "nodeName": "PRIMARY->Monitors->49",
        "sku": "SAMSUNGS49",
        "attributeValues": [
            { "name": "Title",        "value": "S49AG95" },
            { "name": "Image",        "value": "http://example.com/samsungs49.jpg" },
            { "name": "Description",  "value": "Exceptional high-performance large monitor" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Samsung" },
            { "name": "Weight",       "value": 14.5 },
            { "name": "Height",       "value": 53.72 },
            { "name": "Width",        "value": 114.95 },
            { "name": "Length",       "value": 41.83 },
            { "name": "Power",        "value": "not available" },
            { "name": "Resolution",   "value": "5120x1440" },
            { "name": "Response time", "value": 1 },
            { "name": "Connector",    "value": "2xHDMI 2.1, 1xDP 1.4" },
            { "name": "Diagonal",     "value": 49 },
            { "name": "Frequency",    "value": 240 },
            { "name": "Sockets",      "value": "2xUSB 3.0" }
        ]
    },
    {
        "nodeName": "PRIMARY->Monitors->49",
        "sku": "LG49",
        "attributeValues": [
            { "name": "Title",        "value": "49WL95C-WE" },
            { "name": "Image",        "value": "http://example.com/lg49.jpg" },
            { "name": "Description",  "value": "Beautiful large monitor" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "LG" },
            { "name": "Weight",       "value": 15.2 },
            { "name": "Height",       "value": 54.36 },
            { "name": "Width",        "value": 121.4 },
            { "name": "Length",       "value": 30.73 },
            { "name": "Power",        "value": "80W" },
            { "name": "Resolution",   "value": "5120x1440" },
            { "name": "Response time", "value": 5 },
            { "name": "Connector",    "value": "2xHDMI 2.1, 1xDP 1.4" },
            { "name": "Diagonal",     "value": 49 },
            { "name": "Frequency",    "value": 60 },
            { "name": "Audio",        "value": "Two 10W speakers" },
            { "name": "Sockets",      "value": "4xUSB 3.0" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->SSD",
        "sku": "WDBLUE500GBSSD",
        "attributeValues": [
            { "name": "Title",        "value": "Blue 500GB SSD" },
            { "name": "Image",        "value": "http://example.com/wdblue500.jpg" },
            { "name": "Description",  "value": "500GB SSD drive in standard 7mm form factor" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Western Digital" },
            { "name": "Height",       "value": 0.7 },
            { "name": "Width",        "value": 7 },
            { "name": "Length",       "value": 10 },
            { "name": "Storage",      "value": "500GB" },
            { "name": "Bandwidth",    "value": "560MB/s seq read, 530MB/s seq write" },
            { "name": "Connector",    "value": "SATA" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->SSD",
        "sku": "WDBLUE1000GBSSD",
        "attributeValues": [
            { "name": "Title",        "value": "Blue 1000GB SSD" },
            { "name": "Image",        "value": "http://example.com/wdblue1000.jpg" },
            { "name": "Description",  "value": "1000GB SSD drive in standard 7mm form factor" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Western Digital" },
            { "name": "Height",       "value": 0.7 },
            { "name": "Width",        "value": 7 },
            { "name": "Length",       "value": 10 },
            { "name": "Storage",      "value": "1000GB" },
            { "name": "Bandwidth",    "value": "560MB/s seq read, 530MB/s seq write" },
            { "name": "Connector",    "value": "SATA" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->SSD",
        "sku": "WDBLUE2000GBSSD",
        "attributeValues": [
            { "name": "Title",        "value": "Blue 2000GB SSD" },
            { "name": "Image",        "value": "http://example.com/wdblue2000.jpg" },
            { "name": "Description",  "value": "2000GB SSD drive in standard 7mm form factor" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Western Digital" },
            { "name": "Height",       "value": 0.7 },
            { "name": "Width",        "value": 7 },
            { "name": "Length",       "value": 10 },
            { "name": "Storage",      "value": "2000GB" },
            { "name": "Bandwidth",    "value": "560MB/s seq read, 530MB/s seq write" },
            { "name": "Connector",    "value": "SATA" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->SSD",
        "sku": "WDBLUE4000GBSSD",
        "attributeValues": [
            { "name": "Title",        "value": "Blue 4000GB SSD" },
            { "name": "Image",        "value": "http://example.com/wdblue4000.jpg" },
            { "name": "Description",  "value": "4000GB SSD drive in standard 7mm form factor" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Western Digital" },
            { "name": "Height",       "value": 0.7 },
            { "name": "Width",        "value": 7 },
            { "name": "Length",       "value": 10 },
            { "name": "Storage",      "value": "4000GB" },
            { "name": "Bandwidth",    "value": "560MB/s seq read, 530MB/s seq write" },
            { "name": "Connector",    "value": "SATA" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->NVMe",
        "sku": "WDBLACK500GBNVME",
        "attributeValues": [
            { "name": "Title",        "value": "Black SN850 500GB NVMe" },
            { "name": "Image",        "value": "http://example.com/wdblack500.jpg" },
            { "name": "Description",  "value": "500GB NVMe solid-state storage" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Western Digital" },
            { "name": "Height",       "value": 0.23 },
            { "name": "Width",        "value": 2.21 },
            { "name": "Length",       "value": 8 },
            { "name": "Storage",      "value": "500GB" },
            { "name": "Bandwidth",    "value": "7000MB/s seq read, 4100MB/s seq write" },
            { "name": "Connector",    "value": "NVMe M.2 PCIe Gen4 x4" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->NVMe",
        "sku": "WDBLACK1000GBNVME",
        "attributeValues": [
            { "name": "Title",        "value": "Black SN850 1000GB NVMe" },
            { "name": "Image",        "value": "http://example.com/wdblack1000.jpg" },
            { "name": "Description",  "value": "1000GB NVMe solid-state storage" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Western Digital" },
            { "name": "Height",       "value": 0.23 },
            { "name": "Width",        "value": 2.21 },
            { "name": "Length",       "value": 8 },
            { "name": "Storage",      "value": "1000GB" },
            { "name": "Bandwidth",    "value": "7000MB/s seq read, 5300MB/s seq write" },
            { "name": "Connector",    "value": "NVMe M.2 PCIe Gen4 x4" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->NVMe",
        "sku": "WDBLACK2000GBNVME",
        "attributeValues": [
            { "name": "Title",        "value": "Black SN850 2000GB NVMe" },
            { "name": "Image",        "value": "http://example.com/wdblack2000.jpg" },
            { "name": "Description",  "value": "2000GB NVMe solid-state storage" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Western Digital" },
            { "name": "Height",       "value": 0.23 },
            { "name": "Width",        "value": 2.21 },
            { "name": "Length",       "value": 8 },
            { "name": "Storage",      "value": "2000GB" },
            { "name": "Bandwidth",    "value": "7000MB/s seq read, 5100MB/s seq write" },
            { "name": "Connector",    "value": "NVMe M.2 PCIe Gen4 x4" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->NVMe",
        "sku": "SAMSUNG970EVO250GB",
        "attributeValues": [
            { "name": "Title",        "value": "970 EVO Plus 250GB NVMe" },
            { "name": "Image",        "value": "http://example.com/samsungevo250.jpg" },
            { "name": "Description",  "value": "250GB NVMe solid-state storage" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Western Digital" },
            { "name": "Height",       "value": 0.28 },
            { "name": "Width",        "value": 2.21 },
            { "name": "Length",       "value": 8 },
            { "name": "Storage",      "value": "250GB" },
            { "name": "Bandwidth",    "value": "3500MB/s seq read, 2300MB/s seq write" },
            { "name": "Connector",    "value": "NVMe M.2 PCIe Gen3 x4" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->NVMe",
        "sku": "SAMSUNG970EVO500GB",
        "attributeValues": [
            { "name": "Title",        "value": "970 EVO Plus 500GB NVMe" },
            { "name": "Image",        "value": "http://example.com/samsungevo500.jpg" },
            { "name": "Description",  "value": "500GB NVMe solid-state storage" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Western Digital" },
            { "name": "Height",       "value": 0.28 },
            { "name": "Width",        "value": 2.21 },
            { "name": "Length",       "value": 8 },
            { "name": "Storage",      "value": "500GB" },
            { "name": "Bandwidth",    "value": "3500MB/s seq read, 3200MB/s seq write" },
            { "name": "Connector",    "value": "NVMe M.2 PCIe Gen3 x4" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->NVMe",
        "sku": "SAMSUNG970EVO1000GB",
        "attributeValues": [
            { "name": "Title",        "value": "970 EVO Plus 100GB NVMe" },
            { "name": "Image",        "value": "http://example.com/samsungevo1000.jpg" },
            { "name": "Description",  "value": "1000GB NVMe solid-state storage" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Western Digital" },
            { "name": "Height",       "value": 0.28 },
            { "name": "Width",        "value": 2.21 },
            { "name": "Length",       "value": 8 },
            { "name": "Storage",      "value": "1000GB" },
            { "name": "Bandwidth",    "value": "3500MB/s seq read, 3300MB/s seq write" },
            { "name": "Connector",    "value": "NVMe M.2 PCIe Gen3 x4" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->NVMe",
        "sku": "SAMSUNG970EVO2000GB",
        "attributeValues": [
            { "name": "Title",        "value": "970 EVO Plus 2000GB NVMe" },
            { "name": "Image",        "value": "http://example.com/samsungevo2000.jpg" },
            { "name": "Description",  "value": "2000GB NVMe solid-state storage" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Western Digital" },
            { "name": "Height",       "value": 0.28 },
            { "name": "Width",        "value": 2.21 },
            { "name": "Length",       "value": 8 },
            { "name": "Storage",      "value": "2000GB" },
            { "name": "Bandwidth",    "value": "3500MB/s seq read, 3300MB/s seq write" },
            { "name": "Connector",    "value": "NVMe M.2 PCIe Gen3 x4" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->Disk",
        "sku": "SEAGATE500GB",
        "attributeValues": [
            { "name": "Title",        "value": "Barracuda 500GB disk" },
            { "name": "Image",        "value": "http://example.com/seagate500.jpg" },
            { "name": "Description",  "value": "500GB 2.5inch 5400rpm spinning disk" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Seagate" },
            { "name": "Height",       "value": 0.7 },
            { "name": "Width",        "value": 7 },
            { "name": "Length",       "value": 10 },
            { "name": "Storage",      "value": "500GB" },
            { "name": "Bandwidth",    "value": "140MB/s seq read, 140MB/s seq write" },
            { "name": "Connector",    "value": "SATA" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->Disk",
        "sku": "SEAGATE1000GB",
        "attributeValues": [
            { "name": "Title",        "value": "Barracuda 1000GB disk" },
            { "name": "Image",        "value": "http://example.com/seagate1000.jpg" },
            { "name": "Description",  "value": "1000GB 2.5inch 5400rpm spinning disk" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Seagate" },
            { "name": "Height",       "value": 0.7 },
            { "name": "Width",        "value": 7 },
            { "name": "Length",       "value": 10 },
            { "name": "Storage",      "value": "1000GB" },
            { "name": "Bandwidth",    "value": "140MB/s seq read, 140MB/s seq write" },
            { "name": "Connector",    "value": "SATA" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->Disk",
        "sku": "SEAGATE2000GB",
        "attributeValues": [
            { "name": "Title",        "value": "Barracuda 2000GB disk" },
            { "name": "Image",        "value": "http://example.com/seagate2000.jpg" },
            { "name": "Description",  "value": "2000GB 2.5inch 5400rpm spinning disk" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Seagate" },
            { "name": "Height",       "value": 0.7 },
            { "name": "Width",        "value": 7 },
            { "name": "Length",       "value": 10 },
            { "name": "Storage",      "value": "2000GB" },
            { "name": "Bandwidth",    "value": "140MB/s seq read, 140MB/s seq write" },
            { "name": "Connector",    "value": "SATA" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->Disk",
        "sku": "SEAGATE3000GB",
        "attributeValues": [
            { "name": "Title",        "value": "Barracuda 3000GB disk" },
            { "name": "Image",        "value": "http://example.com/seagate3000.jpg" },
            { "name": "Description",  "value": "3000GB 2.5inch 5400rpm spinning disk" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Seagate" },
            { "name": "Height",       "value": 0.7 },
            { "name": "Width",        "value": 7 },
            { "name": "Length",       "value": 10 },
            { "name": "Storage",      "value": "3000GB" },
            { "name": "Bandwidth",    "value": "140MB/s seq read, 140MB/s seq write" },
            { "name": "Connector",    "value": "SATA" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->Disk",
        "sku": "SEAGATE4000GB",
        "attributeValues": [
            { "name": "Title",        "value": "Barracuda 4000GB disk" },
            { "name": "Image",        "value": "http://example.com/seagate4000.jpg" },
            { "name": "Description",  "value": "4000GB 2.5inch 5400rpm spinning disk" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Seagate" },
            { "name": "Height",       "value": 0.7 },
            { "name": "Width",        "value": 7 },
            { "name": "Length",       "value": 10 },
            { "name": "Storage",      "value": "4000GB" },
            { "name": "Bandwidth",    "value": "140MB/s seq read, 140MB/s seq write" },
            { "name": "Connector",    "value": "SATA" }
        ]
    },
    {
        "nodeName": "PRIMARY->Storage->Disk",
        "sku": "SEAGATE5000GB",
        "attributeValues": [
            { "name": "Title",        "value": "Barracuda 5000GB disk" },
            { "name": "Image",        "value": "http://example.com/seagate5000.jpg" },
            { "name": "Description",  "value": "5000GB 2.5inch 5400rpm spinning disk" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Seagate" },
            { "name": "Height",       "value": 0.7 },
            { "name": "Width",        "value": 7 },
            { "name": "Length",       "value": 10 },
            { "name": "Storage",      "value": "5000GB" },
            { "name": "Bandwidth",    "value": "140MB/s seq read, 140MB/s seq write" },
            { "name": "Connector",    "value": "SATA" }
        ]
    },
    {
        "nodeName": "PRIMARY->Networking->Wifi",
        "sku": "DLINKAC1750",
        "attributeValues": [
            { "name": "Title",        "value": "AC1750 802.11ac/n/g router" },
            { "name": "Image",        "value": "http://example.com/dlinkac1750.jpg" },
            { "name": "Description",  "value": "Wireless IEEE 802.11ac/n/g router" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "D-Link" },
            { "name": "Weight",       "value": 0.3 },
            { "name": "Height",       "value": 3.8 },
            { "name": "Width",        "value": 19 },
            { "name": "Length",       "value": 15 },
            { "name": "Bandwidth",    "value": "450Mbps (2.4GHz) / 1300Mbps (5GHz)" },
            { "name": "Sockets",      "value": "1x1Gbps WAN, 4x1Gbps LAN" }
        ]
    },
    {
        "nodeName": "PRIMARY->Networking->Wifi",
        "sku": "TPLINKAX55",
        "attributeValues": [
            { "name": "Title",        "value": "AX55 802.11ax/ac/n/g router" },
            { "name": "Image",        "value": "http://example.com/tplinkax55.jpg" },
            { "name": "Description",  "value": "Wireless IEEE 802.11ax/ac/n/g router" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "TP-Link" },
            { "name": "Height",       "value": 4.1 },
            { "name": "Width",        "value": 26.1 },
            { "name": "Length",       "value": 13.5 },
            { "name": "Power",        "value": "4W" },
            { "name": "Bandwidth",    "value": "574Mbps (2.4GHz) / 2402Mbps (5GHz)" },
            { "name": "Sockets",      "value": "1x1Gbps WAN, 4x1Gbps LAN" }
        ]
    },
    {
        "nodeName": "PRIMARY->Networking->Wifi",
        "sku": "TPLINKC50",
        "attributeValues": [
            { "name": "Title",        "value": "C50 802.11n/g/b router" },
            { "name": "Image",        "value": "http://example.com/tplinkc50.jpg" },
            { "name": "Description",  "value": "Wireless IEEE 802.11n/g/b router" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "TP-Link" },
            { "name": "Height",       "value": 3.5 },
            { "name": "Width",        "value": 23 },
            { "name": "Length",       "value": 14.4 },
            { "name": "Power",        "value": "12W" },
            { "name": "Bandwidth",    "value": "300Mbps (2.4GHz) / 867Mbps (5GHz)" },
            { "name": "Sockets",      "value": "1x100Mbps WAN, 4x100Mbps LAN" }
        ]
    },
    {
        "nodeName": "PRIMARY->Networking->Switches",
        "sku": "TPLINKSG105",
        "attributeValues": [
            { "name": "Title",        "value": "TL-SG105 V6 five-port gigabit switch" },
            { "name": "Image",        "value": "http://example.com/tplinksg105.jpg" },
            { "name": "Description",  "value": "IEEE 802.3i/u/ab/x five-port gigabit switch" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "TP-Link" },
            { "name": "Height",       "value": 2.5 },
            { "name": "Width",        "value": 10 },
            { "name": "Length",       "value": 9.8 },
            { "name": "Power",        "value": "2.3W" },
            { "name": "Bandwidth",    "value": "10/100/1000Mbps" },
            { "name": "Sockets",      "value": "5xRJ-45" }
        ]
    },
    {
        "nodeName": "PRIMARY->Networking->Switches",
        "sku": "TPLINKLS1008G",
        "attributeValues": [
            { "name": "Title",        "value": "LS1008G V2 eight-port gigabit switch" },
            { "name": "Image",        "value": "http://example.com/tplinkls1008g.jpg" },
            { "name": "Description",  "value": "IEEE 802.3i/u/ab/x eight-port gigabit switch" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "TP-Link" },
            { "name": "Height",       "value": 2.3 },
            { "name": "Width",        "value": 12.7 },
            { "name": "Length",       "value": 6.65 },
            { "name": "Power",        "value": "2.7W" },
            { "name": "Bandwidth",    "value": "10/100/1000Mbps" },
            { "name": "Sockets",      "value": "8xRJ-45" }
        ]
    },
    {
        "nodeName": "PRIMARY->Networking->Switches",
        "sku": "TPLINKLSSG116",
        "attributeValues": [
            { "name": "Title",        "value": "SG116 16-port gigabit switch" },
            { "name": "Image",        "value": "http://example.com/tplinklssg116.jpg" },
            { "name": "Description",  "value": "IEEE 802.3i/u/ab/x 16-port gigabit switch" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "TP-Link" },
            { "name": "Height",       "value": 2.5 },
            { "name": "Width",        "value": 28.6 },
            { "name": "Length",       "value": 11.2 },
            { "name": "Power",        "value": "10W" },
            { "name": "Bandwidth",    "value": "10/100/1000Mbps" },
            { "name": "Sockets",      "value": "16xRJ-45" }
        ]
    },
    {
        "nodeName": "PRIMARY->Networking->Cables",
        "sku": "ELITE6E10",
        "attributeValues": [
            { "name": "Title",        "value": "10m cat6e cable" },
            { "name": "Image",        "value": "http://example.com/elite6e10.jpg" },
            { "name": "Description",  "value": "10m of cat6e networking cable" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Elite" },
            { "name": "Height",       "value": 0.5 },
            { "name": "Width",        "value": 0.5 },
            { "name": "Length",       "value": 1000 },
            { "name": "Bandwidth",    "value": "Supports 10Gbps" }
        ]
    },
    {
        "nodeName": "PRIMARY->Networking->Cables",
        "sku": "ELITE6E25",
        "attributeValues": [
            { "name": "Title",        "value": "25m cat6e cable" },
            { "name": "Image",        "value": "http://example.com/elite6e25.jpg" },
            { "name": "Description",  "value": "25m of cat6e networking cable" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Elite" },
            { "name": "Height",       "value": 0.5 },
            { "name": "Width",        "value": 0.5 },
            { "name": "Length",       "value": 2500 },
            { "name": "Bandwidth",    "value": "Supports 7Gbps" }
        ]
    },
    {
        "nodeName": "PRIMARY->Networking->Cables",
        "sku": "ELITE6E100",
        "attributeValues": [
            { "name": "Title",        "value": "100m cat6e cable" },
            { "name": "Image",        "value": "http://example.com/elite6e100.jpg" },
            { "name": "Description",  "value": "100m of cat6e networking cable" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Elite" },
            { "name": "Height",       "value": 0.5 },
            { "name": "Width",        "value": 0.5 },
            { "name": "Length",       "value": 10000 },
            { "name": "Bandwidth",    "value": "Supports 1Gbps" }
        ]
    },
    {
        "nodeName": "PRIMARY->Networking->Cables",
        "sku": "ELITE6E100",
        "attributeValues": [
            { "name": "Title",        "value": "100m cat6e cable" },
            { "name": "Image",        "value": "http://example.com/elite6e100.jpg" },
            { "name": "Description",  "value": "100m of cat6e networking cable" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Elite" },
            { "name": "Height",       "value": 0.5 },
            { "name": "Width",        "value": 0.5 },
            { "name": "Length",       "value": 10000 },
            { "name": "Bandwidth",    "value": "Supports 1Gbps" }
        ]
    }
]'
curl -sXPOST 'https://<env>.copilot.fabric.inc/api-product/v1/product/bulk/insert' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'content-type: application/json' \
-d '[
    {
        "nodeName": "PRIMARY->Peripherals->HOTAS",
        "sku": "VIRPILALPHAL",
        "attributeValues": [
            { "name": "Title",        "value": "Left-handed Constellation flight stick" },
            { "name": "Image",        "value": "http://example.com/virpilalphal.jpg" },
            { "name": "Description",  "value": "Left-handed flight stick" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Virpil" },
            { "name": "Weight",       "value": 0.51 },
            { "name": "Height",       "value": 21.4 },
            { "name": "Width",        "value": 14.0 },
            { "name": "Length",       "value": 10.5 }
        ]
    },
    {
        "nodeName": "PRIMARY->Peripherals->HOTAS",
        "sku": "VIRPILALPHAR",
        "attributeValues": [
            { "name": "Title",        "value": "Right-handed Constellation flight stick" },
            { "name": "Image",        "value": "http://example.com/virpilalphar.jpg" },
            { "name": "Description",  "value": "Right-handed flight stick" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Virpil" },
            { "name": "Weight",       "value": 0.51 },
            { "name": "Height",       "value": 21.4 },
            { "name": "Width",        "value": 14.0 },
            { "name": "Length",       "value": 10.5 }
        ]
    },
    {
        "nodeName": "PRIMARY->Peripherals->HOTAS",
        "sku": "VIRPILMONGOOSE",
        "attributeValues": [
            { "name": "Title",        "value": "MongoosT-50CM2 Base" },
            { "name": "Image",        "value": "http://example.com/virpilmongoose.jpg" },
            { "name": "Description",  "value": "High-end flight stick base" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Virpil" },
            { "name": "Weight",       "value": 1.37 },
            { "name": "Height",       "value": 15.6 },
            { "name": "Width",        "value": 8.7 },
            { "name": "Length",       "value": 13.3 },
            { "name": "Connector",    "value": "USB" }
        ]
    },
    {
        "nodeName": "PRIMARY->Peripherals->HOTAS",
        "sku": "VIRPILWARBRD",
        "attributeValues": [
            { "name": "Title",        "value": "WarBRD Base" },
            { "name": "Image",        "value": "http://example.com/virpilwarbrd.jpg" },
            { "name": "Description",  "value": "Mid-range flight stick base" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Virpil" },
            { "name": "Weight",       "value": 1.17 },
            { "name": "Height",       "value": 10.5 },
            { "name": "Width",        "value": 23 },
            { "name": "Length",       "value": 22 },
            { "name": "Connector",    "value": "USB" }
        ]
    },
    {
        "nodeName": "PRIMARY->Peripherals->HOTAS",
        "sku": "VIRPILTHROTTLE",
        "attributeValues": [
            { "name": "Title",        "value": "MongoosT-50CM3 Throttle" },
            { "name": "Image",        "value": "http://example.com/virpilthrottle.jpg" },
            { "name": "Description",  "value": "Dual-axis aircraft throttle" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Virpil" },
            { "name": "Weight",       "value": 2.45 },
            { "name": "Height",       "value": 19.5 },
            { "name": "Width",        "value": 23.5 },
            { "name": "Length",       "value": 20 },
            { "name": "Connector",    "value": "USB" }
        ]
    },
    {
        "nodeName": "PRIMARY->Peripherals->Mice",
        "sku": "LOGITECHM317",
        "attributeValues": [
            { "name": "Title",        "value": "M317 Mouse" },
            { "name": "Image",        "value": "http://example.com/logitechm317.jpg" },
            { "name": "Description",  "value": "Three-button wireless optical mouse" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Logitech" },
            { "name": "Weight",       "value": 0.08 },
            { "name": "Height",       "value": 3.86 },
            { "name": "Width",        "value": 5.5 },
            { "name": "Length",       "value": 9.5 },
            { "name": "DPI",          "value": 300 },
            { "name": "Connector",    "value": "USB" }
        ]
    },
    {
        "nodeName": "PRIMARY->Peripherals->Mice",
        "sku": "RAZERMINI",
        "attributeValues": [
            { "name": "Title",        "value": "Viper Mini Mouse" },
            { "name": "Image",        "value": "http://example.com/razermini.jpg" },
            { "name": "Description",  "value": "High-performance wired optical mouse" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Razer" },
            { "name": "Weight",       "value": 0.06 },
            { "name": "Height",       "value": 3.83 },
            { "name": "Width",        "value": 5.35 },
            { "name": "Length",       "value": 11.83 },
            { "name": "DPI",          "value": 600 },
            { "name": "Connector",    "value": "USB" }
        ]
    },
    {
        "nodeName": "PRIMARY->Peripherals->Keyboards",
        "sku": "WOOTINGONE",
        "attributeValues": [
            { "name": "Title",        "value": "Wooting One Keyboard" },
            { "name": "Image",        "value": "http://example.com/wootingone.jpg" },
            { "name": "Description",  "value": "High-end mechanical optical tenkeyless keyboard" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Wooting" },
            { "name": "Weight",       "value": 0.8 },
            { "name": "Height",       "value": 4.1 },
            { "name": "Width",        "value": 36.9 },
            { "name": "Length",       "value": 16.1 },
            { "name": "Layout",       "value": "ANSI" },
            { "name": "Connector",    "value": "USB" }
        ]
    },
    {
        "nodeName": "PRIMARY->Peripherals->Keyboards",
        "sku": "LOGITECHERGO",
        "attributeValues": [
            { "name": "Title",        "value": "Ergo K860 Keyboard" },
            { "name": "Image",        "value": "http://example.com/logitechergo.jpg" },
            { "name": "Description",  "value": "Ergonomic wireless keyboard" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Logitech" },
            { "name": "Weight",       "value": 1.16 },
            { "name": "Height",       "value": 4.8 },
            { "name": "Width",        "value": 45.6 },
            { "name": "Length",       "value": 23.3 },
            { "name": "Layout",       "value": "ANSI" },
            { "name": "Connector",    "value": "USB" }
        ]
    }
]'

Create using CSV (bulk import)

We can create products using CSV instead of using JSON. For that, we must first download the CSV template using the following API curl.

curl 'https://<env>.copilot.fabric.inc/api-product/v1/product/bulk/template/<...snip...>/619d177f22e7b46b0070ddd6' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'Authorization: <...snip...>'

The path to get the template is /api-product/v1/product/bulk/template/&lt;account ID>/&lt;category ID>.

Once the CSV template is filled out with all the details (add products under particular categories), we must request the location where the CSV should be uploaded in S3.

This call gets the upload URL:

curl -XPOST 'https://<env>.copilot.fabric.inc/api-product/v1/upload-url' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'authorization: <...snip...>'
--header 'x-api-key: <...snip...>' \
--header 'content-type: application/json' \
--data-raw '{
    "nodeId": "611eef8b81f92b882d4f9741",
    "fileName": "items.csv"
}'

Now, upload the CSV to the returned URL:

curl -XPUT 'https://greatwall-sandbox-bulk-import-pim.s3.amazonaws.com/item/<...snip...>/sandbox/1646769995703-items.csv?X-Amz-Algorithm=AWS4-HMAC-SHA256<...snip...>' \
--header 'content-type: text/csv' \
--data-raw '@File location'

Once uploaded, PIM will process all the products in the CSV. You can check the status of the import using the following API Curl:

curl 'https://<env>.copilot.fabric.inc/api-product/v1/product/bulk/file/1646769995703-items.csv/status' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>'

Here’s a sample - Download File

6. Update products

From an API perspective, the Update product operation is similar to Create product, except the URLs differ. URL for update product ends in /update whereas URL for Create product ends in /insert:

Here is an example of a curl call with values to be updated for a keyboard.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-product/v1/product/bulk/update' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'content-type: application/json' \
-d '[
    {
        "nodeName": "PRIMARY->Peripherals->Keyboards",
        "sku": "WOOTINGONE",
        "attributeValues": [
            { "name": "Title",        "value": "Wooting One Keyboard" },
            { "name": "Image",        "value": "http://example.com/wootingonetenkeyless.jpg" },
            { "name": "Description",  "value": "High-end mechanical optical tenkeyless keyboard" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Wooting" },
            { "name": "Weight",       "value": 0.8 },
            { "name": "Height",       "value": 4.1 },
            { "name": "Width",        "value": 36.9 },
            { "name": "Length",       "value": 16.1 },
            { "name": "Layout",       "value": "ANSI" },
            { "name": "Connector",    "value": "USB" }
        ]
    }
]'

7. Create bundles

A Bundle includes more than two products along with their quantities.

To demonstrate bundles, we will create a bundle called HOTAS within the Peripherals -> HOTAS category. HOTAS is a joystick and throttle used by gamers in flight and space simulators. In this example, we will be bundling a handle (the top part of the joystick), a sensor (the bottom part of the joystick), and the throttle together. Shopper can then buy this bundle and receive all three products (instead of buying them individually). Another potential example of bundling (not demonstrated here) is combining monitor, desktop, keyboard, mouse, speakers, and printer.

Curl for creation of the HOTAS bundle under the HOTAS node:

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-product/v1/product/bulk/insert' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'content-type: application/json' \
-d '[
    {
        "nodeName": "PRIMARY->Peripherals->HOTAS",
        "sku": "VIRPILBUNDLE",
        "type": "BUNDLE",
        "attributeValues": [
            { "name": "Title",        "value": "HOTAS bundle" },
            { "name": "Image",        "value": "http://example.com/virpilalphal.jpg" },
            { "name": "Description",  "value": "Everything you need for a top-end HOTAS setup" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Virpil" },
            { "name": "Weight",       "value": 0 },
            { "name": "Height",       "value": 0 },
            { "name": "Width",        "value": 0 },
            { "name": "Length",       "value": 0 }
        ],
        "bundleItems": [
          { "sku": "VIRPILMONGOOSE", "quantity": 1 },
          { "sku": "VIRPILALPHAR", "quantity": 1 },
          { "sku": "VIRPILTHROTTLE", "quantity": 1 }
        ]
    }
]'

8. Update Bundles

Update bundle individually

Curl example where we replace the right-handed joystick in the bundle with a left-handed one.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-product/v1/product/bulk/update' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'content-type: application/json' \
-d '[
    {
        "nodeName": "PRIMARY->Peripherals->HOTAS",
        "sku": "VIRPILBUNDLE",
        "type": "BUNDLE",
        "attributeValues": [
            { "name": "Title",        "value": "HOTAS bundle" },
            { "name": "Image",        "value": "http://example.com/virpilalphal.jpg" },
            { "name": "Description",  "value": "Everything you need for a top-end HOTAS setup" },
            { "name": "Published",    "value": true },
            { "name": "Manufacturer", "value": "Virpil" },
            { "name": "Weight",       "value": 0 },
            { "name": "Height",       "value": 0 },
            { "name": "Width",        "value": 0 },
            { "name": "Length",       "value": 0 }
        ],
        "bundleItems": [
          { "sku": "VIRPILMONGOOSE", "quantity": 1 },
          { "sku": "VIRPILALPHAL", "quantity": 1 },
          { "sku": "VIRPILTHROTTLE", "quantity": 1 }
        ]
    }
]'

Note: Structure of the call is identical to the call for Create Bundle, except that we changed the SKU of the joystick in the bundle and the URL we call ends with /update (instead of /insert for creation).

Bundles - Bulk import

The process for importing bundles is similar to importing products, except the URLs differ.

The URL for bulk import products is POST /api-product/v1/product/bulk/template/:accountId/:nodeId

and the URL for bulk import bundles is POST /api-product/v1/product/bulk/template/bundle/:accountId/:categoryId

In addition, the CSV template has an additional column Items to be filled out with a “;”-separated list of SKUs, with Counts as an optional column. Note: When count is not specified, 1 is considered as default value.

While bundling three products, two SKUs for mouse and one SKU for keyboard, the Items column would have the value as mouse=2;keyboard=1.

Since an SKU without a count is treated as a single product, an alternative approach is mouse=2;keyboard.

Here is a sample - Download File

9. Create Alternate hierarchies

Let's create an Alternate hierarchy named Website Catalog, which includes the following:

  • Desktops
  • Monitors
  • Storage
  • Peripherals

Consider that networking equipment is currently unavailable. So, we will omit Networking category from our Alternate hierarchy even though we have information on them in our Primary hierarchy.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Website Catalogue",
    "type": "ALTERNATE"
}'

Under this category (in this example it is nodeId 31) we create the previously-mentioned four categories.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Desktops",
    "parentNodeId": 31
}'
curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Monitors",
    "parentNodeId": 31
}'
curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Storage",
    "parentNodeId": 31
}'
curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "name": "Peripherals",
    "parentNodeId": 31
}'

We now have a structure that looks like this:

Website Catalogue
  ⌞ Desktops
  ⌞ Monitors
  ⌞ Storage
  ⌞ Peripherals

10. Populate Alternate hierarchy with Products

Products are added to Primary categories first, then populated into Alternate categories by defining Primary categories as sources. Primary categories are therefore the source of products appearing in Alternate categories.

Note: Sources behave similarly to symlinks.

Sources

To understand the concept of sources better let’s take the Alternate category Website Catalog we just created. As of now, it does not contain any products. If we indicate that Desktops in the Website Catalog has Desktops and Laptops in the primary hierarchy as sources, all the products belonging to Desktops or Laptops (or any of their descendant categories) will show up under Desktops.

Note: An alternate hierarchy category can have one or more sources.

In the Computers category, we will give both the Laptops and Desktops categories as sources.

This curl call is to add categories as sources to another category. If you do not know the needed categoryIds, you can look them up using this call; alternatively, there is an example of how to do so at the end of this document.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/source' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 33,
    "sources": [
        {
            "action": "SET",
            "nodeId": 2
        },
        {
            "action": "SET",
            "nodeId": 3
        }
    ]
}'

We will give the Website Catalog's Monitors the primary hierarchy's Monitors as a source:

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/source' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 36,
    "sources": [
        {
            "action": "SET",
            "nodeId": 4
        }
    ]
}'

We will give the Website Catalog's Storage the primary hierarchy's Storage as a source:

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/source' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 37,
    "sources": [
        {
            "action": "SET",
            "nodeId": 5
        }
    ]
}'

We will give the Website Catalog's Peripherals the primary hierarchy's Peripherals as a source:

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/source' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 38,
    "sources": [
        {
            "action": "SET",
            "nodeId": 7
        }
    ]
}'
Exclusions

There might be requirements to exclude one or more groups of products from an alternate hierarchy after using a source.

For example: Assume that HOTAS source is temporarily unable to fulfill orders, we can omit all HOTAS products from appearing in the Alternate peripherals. To reiterate, Peripherals in the Alternate hierarchy get all their products from the Peripherals in the Primary hierarchy. Now, we want to remove a subset of those products, specifically all products belonging to HOTAS (or any child categories).

This curl call excludes all HOTAS products from the alternate Peripherals category:

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/source/exclusion' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 38,
    "sourceExclusions": [
        {
            "action": "SET",
            "nodeId": 24
        }
    ]
}'

Similarly, assume that our relationship with Apple is temporarily halted due to negotiation difficulties with one of the suppliers.

Here is the Curl example if we still want to show all the laptops and desktops under the Desktops category, with the exception of Apple laptops.

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/source/exclusion' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 33,
    "sourceExclusions": [
        {
            "action": "SET",
            "nodeId": 12
        }
    ]
}'
Product Attribute Conditions

Both sources and source exclusions apply to all products within a category. However, it’s also possible to conditionally include or exclude products based on product attribute values.

Let us assume that we temporarily do not want Wooting keyboard listed in our Website Catalogue at the moment.

Currently, there is a Wooting keyboard under the Website Catalogue -> Peripherals category (categoryId 38). One way to remove the keyboard is to make this category exclude all products that have a Manufacturer (attribute ID 62668daafbad57129fce4776) equal to Wooting:

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/item-attribute/condition' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'authorization: <...snip...>' \
--header 'content-type: application/json' \
-d '{
    "nodeId": 38,
    "itemAttributeConditions": [
        {
            "action": "SET",
            "attributeId": "62668daafbad57129fce4776",
            "condition": {
                "type": "DOES_NOT_CONTAINS",
                "value": "Wooting"
            }
        }
    ]
}'

{
  "id": "62683707c54c1935e6abd6c9",
  "nodeId": 38,
  "name": "Peripherals",
  "itemAttributeConditions": [
    {
      "attributeId": "62668daafbad57129fce4776",
      "name": "Manufacturer",
      "type": "TEXT",
      "condition": {
        "type": "DOES_NOT_CONTAINS",
        "value": "Wooting"
      }
    }
  ]
}

Now, the Wooting keyboard will no longer show up in this category.

You can view additonal details about product conditions here, since there are several conditions available beyond just CONTAINS and DOES_NOT_CONTAIN.

11. Formula Attributes

You can also create an attribute with a formula. This is useful when attributes are dynamic in nature.

For example:

  1. You can configure product's display name to be something like Title + by + Manufacturer. Instead of having to name each product and variant individually, this formula will automatically create display names for all products and variants. With Title attribute as Wireless Headphones and Manufacturer attribute: Apple, the output of formula-based title will be Wireless headphones by Apple.
  2. Similarly, the formula can be applied to calculate the area of a computer product by multiplying Width and Length.

Frequently used formulas:

Divide await attribute("Height") / 0.39
Multiply await attribute("Width") * await attribute("Length")
Sum await attribute("Weight") + 1
Subtract 304.8 - await attribute("Height")
Concatenate await attribute("SKU") + ‘.jpg’

Note: Formula can be applied to all attributes except Serial type of data.

In our example, we will populate the image of the item by pulling it from a website based on its SKU. The value of SKU will be dynamically populated using the formula that fetches the value of the SKU attribute.

Here, we are updatng the Image attribute using a curl call. We’re putting the JSON in a separate file to avoid problems with shell escaping:

cat update.json
[
    {
        "action": "UPDATE",
        "id": "6267d7cc2957042b74cf8858",
        "type": "TEXT",
        "textSubType": "HTML",
        "target": "ITEM",
        "name": "Image",
        "description": "URL to image of item",
        "validation": { "required": false },
        "formula": "(async () => '<img src=\"http://example.com/' + await attribute('SKU') + '.jpg\">')()"
    }
]

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-product/v1/product/attribute/bulk' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'x-api-key: <...snip...>' \
--header 'content-type: application/json' \
-d @update.json

12. Attribute Groups

Generally, subsets of attributes have conceptual relationships, so grouping attributes streamlines product enrichment. For example, Weight, Width, Height, and Length are all related to the dimensions of a product.

Note: Attribute Groups are increasingly useful with RBAC and workflows as well.

Here is an example to create a group of core attributes that all products must have. We are calling it the “Primary Details” attribute group.

This is Curl to create Attribute Groups:

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-product/v1/product/attribute-group' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'Content-Type: application/json' \
-d '{
    "transactional": true,
    "attributeGroup": [
        {
            "action": "CREATE",
            "type": "COLLECTION",
            "description": "Attributes that all items should have",
            "name": "Primary Details",
            "target": "ITEM",
            "priorityOrder": 1,
            "editableAttributes": [
                {
                    "action": "ADD",
                    "id": "62668daafbad57129fce4776",
                    "order": 0
                },
                {
                    "action": "ADD",
                    "id": "62668daafbad57129fce476a",
                    "order": 1
                },
                {
                    "action": "ADD",
                    "id": "62668daafbad57129fce476c",
                    "order": 2
                }
            ]
        }
    ]
}'

The above example assigns Manufacturer, SKU, and Title (in that order) to the Primary Details group.

13. Category Attributes

Similar to products, attributes can also be added to categories. This allows categories to be enriched with additional information.

We want to attach two additional pieces of information to some of the top-most categories in the Primary hierarchy: Department and Notes. Both are text fields.

Here is API Curl to add category attributes

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/attribute/bulk' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'Content-Type: application/json' \
-d '[
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "NODE",
        "name": "Department",
        "validation": {
            "required": false
        }
    },
    {
        "action": "CREATE",
        "type": "TEXT",
        "textSubType": "SMALL_TEXT",
        "target": "NODE",
        "name": "Notes",
        "validation": {
            "required": false
        }
    }
]'

After creating category attributes, we must assign values to them. For now, we create a blank Notes field for all Level 0 categories, but we assign actual department names to Department.

Because Desktops and Laptops are big-ticket products, they are handled by just one department: Computers.

In our example, the Department attribute returned an ID of 62bb0885ecbe9445e998b0eb, and the Notes attribute return 62bb0885ecbe9445e998b0ed as the ID; we use both these IDs below:

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'Content-Type: application/json' \
-d '{
    "nodeId": 2,
    "attributes": [
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0eb",
            "value": "Desktops"
        },
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0ed",
            "value": ""
        }
    ]
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'Content-Type: application/json' \
-d '{
    "nodeId": 3,
    "attributes": [
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0eb",
            "value": "Desktops"
        },
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0ed",
            "value": ""
        }
    ]
}'

All the other Level 0 categories (Storage, Monitors, Networking and Peripherals) are handled by a separate department, which we amusingly name as Parts:

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'Content-Type: application/json' \
-d '{
    "nodeId": 4,
    "attributes": [
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0eb",
            "value": "Parts"
        },
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0ed",
            "value": ""
        }
    ]
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'Content-Type: application/json' \
-d '{
    "nodeId": 5,
    "attributes": [
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0eb",
            "value": "Parts"
        },
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0ed",
            "value": ""
        }
    ]
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'Content-Type: application/json' \
-d '{
    "nodeId": 6,
    "attributes": [
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0eb",
            "value": "Parts"
        },
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0ed",
            "value": ""
        }
    ]
}'

curl -sXPOST 'https://<env>.copilot.fabric.inc/api-category/v1/category/attribute' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}' \
--header 'Content-Type: application/json' \
-d '{
    "nodeId": 7,
    "attributes": [
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0eb",
            "value": "Parts"
        },
        {
            "action": "SET",
            "attributeId": "62bb0885ecbe9445e998b0ed",
            "value": ""
        }
    ]
}'

14. Getting Details

Other than creating categories and adding products to them (or updating them), most PIM operations are usually read-only, such as getting lists and details of products and categories.

  • Click here for getting information about categories.

  • Click here to get SKUs belonging to a category and for fetching products associated with those SKUs click here.

Examples of each are as follows:

Get a list of categories

The objective is to get all primary categories in a paginated format. This call is often useful for rendering menus since it gets categories (and the relationships between them).

Note that the above example is fetching categories from the PRIMARY hierarchy. While the PRIMARY hierarchy is useful for the merchant, it is not required for the shoppers. For that, you search for categories from the ALTERNATE hierarchy instead, by setting the type=ALTERNATE as query argument.

curl -sG 'https://<env>.copilot.fabric.inc/api-category/v1/category?page=1&size=10&type=PRIMARY' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}'

{
  totalSize: 10,
  pageSize: 10,
  pages: 1,
  categories: [
    {
      id: '6247628658cc26138f686897',
      nodeId: 2,
      name: 'PRIMARY',
      isActive: true,
      createdOn: '2022-04-01T20:37:26.887Z',
      modifiedOn: '2022-04-01T20:37:26.887Z',
      hierarchy: 'PRIMARY',
      attributes: [],
      breadcrumbs: [],
      children: [...]
    }
  ],
  [...]
}

Get SKUs attached to a specific category

The objective is to get all SKUs of HOTAS category (in this case it’s categoryId: 24) in a paginated form. This call is often useful for Product Listing Page (PLP), first by navigating ALTERNATE hierarchy categories and then providing the categoryId in the following call:

Note Be informed that PLPs should use Algolia results (instead of CAPIO).

$ curl -sG 'https://<env>.copilot.fabric.inc/api-category/v1/category/sku?page=1&size=100&nodeId=24' \
--header 'x-site-context: {"stage":"<env>","account":"<...snip...>","date":"2021-09-28T21:27:29.806Z","channel":12}'

{
  "totalSize":5,
  "pageSize":100,
  "pages":1,
  "id":"62668e4dfbad57129fce4a08",
  "nodeId":24,
  "name":"HOTAS",
  "skus": [
    "VIRPILTHROTTLE",
    "VIRPILWARBRD",
    "VIRPILMONGOOSE",
    "VIRPILALPHAR",
    "VIRPILALPHAL"
  ]
}

Get product details

There are more than one ways to search for products. Here, will are looking up for specific SKUs (the SKUs returned by the above call). This call is useful for rendering both PLPs and PDPs.

Note: Due to size limits, avoid querying more than twenty SKUs at a time, unless you know your products are small.

curl -sG 'https://<env>.copilot.fabric.inc/api-product/v1/product' \
--header 'x-site-context: {"stage":"<env>","account":"...","date":"2022-04-06T10:14:13.855Z","channel":12}' \
--data-urlencode 'skus=["VIRPILTHROTTLE", "VIRPILWARBRD", "VIRPILMONGOOSE", "VIRPILALPHAR", "VIRPILALPHAL"]'

{
  "pageSize": 1,
  "totalSize": 5,
  "pages": 1,
  "products": [
    {
      "_id": "626717f9c0b85624a38e79e8",
      "sku": "VIRPILTHROTTLE",
      "itemId": 195,
      "children": [],
      "type": "ITEM",
      "status": true,
      "bundleItems": [],
      ...
    },
    ...
  ]
}

Get Product Attributes

This is not used generally used in production. However, it's handy when setting up a site. This call fetches all the attributes that will be used by any products under a given category (once assigned).

$ curl -sG 'https://<env>.copilot.xyx.inc/api-category/v1/category/item-attribute?size=100&page=1' \
--header --header 'x-site-context: {"stage":"<env>","account":"...","date":"2022-04-06T10:14:13.855Z","channel":12}'

{
  "pageSize": 100,
  "totalSize": 30,
  "pages": 1,
  "itemAttributes": [
    {
      "id": "62668daafbad57129fce476c",
      "mapping": "title",
      "name": "Title",
      "type": "TEXT",
      "required": true
    },
    {
      "id": "62668daafbad57129fce476e",
      "mapping": "active",
      "name": "Published",
      "type": "BOOLEAN",
      "required": true
    },
    ...
  ]
}

15. PIM Event Publishing - Get a notification when a product is modified

When a product is changed in PIM, an event is sent to the PIM Delta Bus through Amazon EventBridge. Using the PIM Event Publishing feature, you can receive notifications when a product is created, updated, or deleted. To set up a notification, fabric creates a rule on the PIM delta bus to redirect a “copy” of the event to a particular target provided by merchants. Each rule in the bus delivers events to specific targets such as an HTTP endpoint, an SNS, a lambda function, and others (Amazon EventBridge targets - Amazon EventBridge)

Sample PIM event - Update product

{
  "version": "0",
  "id": "53dc6c62-8188-3592-5c31-fa797ef1e83a",
  "detail-type": "PRODUCT",
  "source": "sandbox-copilot-product",
  "account": "752314070272",
  "time": "2022-06-07T18:51:42Z",
  "region": "us-east-1",
  "resources": [],
  "detail": {
    "eventName": "ITEM_UPDATED",
    "entityType": "PRODUCT",
    "entityId": 4175,
    "entityIdType": "itemId",
    "accountId": "62604f4fec26950009532a3e",
    "stage": "<env>",
    "callbackUrl": "https://<env>.copilot.¸.inc",
    "attributes": {
      "itemId": 4175,
      "sku": "2847925",
      "title": "Perforated Poly Back and Upholstered Seat Stack Chair - 400 lb. Capacity"
    }
  }
}

Every property in this object can be used as a filter to your rule, so the target receives only the events based on the filter Amazon EventBridge event patterns - Amazon EventBridge

These properties are fixed, so the event does not contain the entire data that a product owns, but as the event contains the ID and the SKU of the product, you can use either one to call our product API and get additional data, if required.

If you want to receive events from PIM, raise a JIRA ticket to fabric Support.