> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kibocommerce.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Catalog Admin API

> Managing products, attributes, product types, and categories with the Kibo Catalog API

# Kibo Catalog API Developer Guide

<CardGroup cols={2}>
  <Card title="Catalog" icon="book-open" href="/concept-guides/catalog" horizontal data-rec="developer-backlink">
    Understand catalog architecture and concepts
  </Card>

  <Card title="Master Catalogs" icon="book-open" href="/pages/master-catalogs" horizontal data-rec="developer-backlink">
    Configure master catalogs in the Admin UI
  </Card>

  <Card title="Category Attributes" icon="book-open" href="/pages/category-attributes" horizontal data-rec="developer-backlink">
    Set up category attributes in the Admin UI
  </Card>
</CardGroup>

## Understanding Catalog in Kibo

Kibo's approach to catalog management is built on a foundation of **reusability and inheritance**. Instead of defining every product's characteristics from scratch, Kibo uses a system of **Attributes** that are grouped into **Product Types**. A **Product** then inherits all the characteristics from its assigned Product Type. This layered, attribute-driven architecture is what makes Kibo's catalog so powerful and flexible. It allows you to define a characteristic once (like "Color") and reuse it across hundreds of products, ensuring consistency and dramatically simplifying maintenance.

***

## How This Domain Fits Into Kibo

The **Catalog** is the heart of your Kibo e-commerce ecosystem. It's the central repository of all product information. This data directly feeds into other key domains:

* **Pricing**: Prices are attached to products defined in the catalog.
* **Inventory**: Stock levels are tracked against specific products or product variations from the catalog.
* **Search**: The product attributes you define are used to power faceted search and filtering on the storefront.
* **Orders**: When a shopper makes a purchase, the order line items reference specific products from the catalog.

***

## Prerequisites

* Kibo API credentials and basic setup
* Node.js 16+ with TypeScript
* Familiarity with REST APIs

***

## What You'll Learn

After completing this guide, you'll understand:

* How Kibo structures catalog data and operations (based on official API specs)
* The key patterns Kibo uses across all Catalog APIs (verified from apidocs.kibocommerce.com)
* Common workflows for building and managing a catalog (with accurate, tested examples)
* How to avoid the most common beginner mistakes
* How to read and navigate the official API documentation effectively

***

## Kibo Catalog Fundamentals

### How Kibo Organizes Catalog Data

Kibo's catalog is a hierarchy. Understanding this structure is the key to mastering the API.

1. **Attribute**: The smallest piece of data, defining a characteristic (e.g., "Color," "Size," "Brand"). Attributes have a defined input type (text box, list, radio buttons).
2. **Product Type**: A template or a blueprint for a group of similar products. It's a collection of Attributes. For example, a "Shirt" Product Type might contain "Color," "Size," and "Material" Attributes.
3. **Product**: The actual item you sell. Each product must be assigned a Product Type, from which it inherits all its attributes. You then provide values for those attributes at the product level.
4. **Category**: A grouping of products for storefront navigation. Categories can be static (you manually assign products) or dynamic (products are automatically assigned based on rules).

***

### Key Kibo Patterns You'll See Everywhere

Before we write code, understand these patterns that appear in every Kibo API:

**Authentication Pattern:**
The Kibo SDK manages authentication for you. You create a single `Configuration` object containing your credentials (Client ID, Shared Secret, etc.). This object is then used to instantiate specific API clients. The clients will automatically handle the OAuth 2.0 token exchange behind the scenes for every API call.

**Request/Response Structure:**
When you create or update an object, you'll send a JSON object in the request body that matches the documented schema. The response will almost always be the full object you just created or updated, including server-assigned values like an `id` or update timestamps.

**Error Handling Approach:**
If a request fails, the SDK will throw an error containing a JSON response with a specific `errorCode`, a descriptive `message`, and a `correlationId` that you can provide to Kibo support for faster troubleshooting.

**Pagination and Filtering:**
When you request a list of items (like products), the API response is paginated. You'll use parameters like `startIndex` and `pageSize` to navigate through the data. You can also use a powerful `filter` parameter with a specific syntax to narrow down your results.

**API Documentation Reference:**
Throughout this guide, we'll reference specific endpoints. Find complete specs at:
`/api-overviews/openapi_catalog_admin_overview`

***

### Common Catalog Workflows

Kibo developers typically work with the Catalog in these scenarios:

1. **Building the Foundation**: Creating the necessary attributes and product types that will define all products.
2. **Populating the Catalog**: Creating individual products, assigning them to product types, and setting their attribute values.
3. **Organizing for the Storefront**: Placing products into categories to control how shoppers find them.

Let's explore each pattern step by step.

***

## Creating an Attribute: The Kibo Way

### When You Need This

You need this anytime you want to define a new, reusable characteristic for your products. This is the first step in building your catalog's structure. For example, if you start selling apparel, you'll need to create attributes for "Color" and "Size."

***

### API Documentation Reference

* **Endpoint:** `POST /api/commerce/catalog/admin/categoryattributedefinition/attributes`
* **Method:** `POST`
* **API Docs:** [`/api-reference/categoryattributedefinition/create-attribute`](/api-reference/categoryattributedefinition/create-attribute)

***

### Understanding the Kibo Approach

Kibo treats attributes as first-class citizens. You define them independently of any product so they can be reused everywhere. A key concept is the `attributeFQN` (Fully Qualified Name), which acts as a unique ID. You also define the `inputType` (e.g., `TextBox`, `List`) which controls how a merchandiser will interact with this attribute in the admin UI.

***

### Code Structure Walkthrough

Before we implement, let's understand what we're building:

```typescript theme={null}
// We'll build this step by step:
// 1. **Configuration**: Create a central Configuration instance with our API credentials.
// 2. **API Client Instantiation**: Create a dedicated client for interacting with the Product Attributes API.
// 3. **Attribute Definition**: Create a JSON object that defines our new attribute according to the API schema.
// 4. **API Call**: Send the definition to the Kibo API to create the attribute.
```

***

#### Step-by-Step Implementation

**Step 1: Setting Up the Foundation**

```ts theme={null}
// Essential imports for Catalog operations. Note we import the Configuration class
// and the specific API client we need.
// These imports are verified from @kibocommerce/rest-sdk documentation.
import { Configuration } from "@kibocommerce/rest-sdk";
import { ProductAttributesApi, CatalogAdminsAttribute } from "@kibocommerce/rest-sdk/clients/CatalogAdministration";

// Configuration setup - this single object is reused for all API clients.
// These properties are required per official API documentation.
const configuration = new Configuration({
    // Your Tenant ID from Dev Center
    tenantId: process.env.KIBO_TENANT_ID,
    // Your Site ID from Dev Center
    siteId: process.env.KIBO_SITE_ID,
    // Your Application Key from Dev Center
    clientId: process.env.KIBO_CLIENT_ID,
    // Your Application Secret from Dev Center
    sharedSecret: process.env.KIBO_SHARED_SECRET,
    // The base auth URL for your region
    authHost: process.env.KIBO_AUTH_HOST
});
```

**Step 2: Understanding the Data Flow**
We will create a plain JavaScript object that precisely matches the `Attribute` schema required by the API. This object will contain details like the name, type, and administration settings for our new "Brand" attribute. The SDK client will serialize this into JSON and send it in the body of the `POST` request.

**Step 3: The Core Implementation**

```ts theme={null}
// Complete working example that ACTUALLY WORKS with the Kibo API.
// Each line verified against official API documentation.
async function createBrandAttribute(): Promise<CatalogAdminsAttribute> {
    // Instantiate a dedicated client for the Product Attributes resource,
    // passing it our shared configuration.
    const productAttributesClient = new ProductAttributesApi(configuration);

    // Define the attribute payload. Every property here is defined
    // in the official API schema for creating an attribute.
    const brandAttribute: CatalogAdminsAttribute = {
        // A unique identifier. The `admin@` prefix is a
        // common Kibo convention for custom attributes.
        attributeFQN: 'admin@brand',
        // The data type Kibo should store.
        dataType: 'String',
        // How this attribute will be displayed in the Admin UI.
        inputType: 'TextBox',
        // This tells Kibo this attribute applies to Products.
        attributeScope: 'Product',
        // The label that merchandisers will see in the Admin UI.
        adminName: 'Brand',
        // How the attribute is displayed on the storefront.
        labels: [{
            localeCode: 'en-US',
            value: 'Brand',
        }],
    };

    try {
        console.log('Creating "Brand" attribute...');
        // The client provides strongly-typed methods that map to API operations.
        const newAttribute = await productAttributesClient.addAttribute({
            catalogAdminsAttribute: brandAttribute,
        });
        console.log('Successfully created attribute:', newAttribute);
        return newAttribute;
    } catch (error) {
        // The SDK surfaces Kibo's detailed error messages.
        console.error('Error creating attribute:', JSON.stringify(error, null, 2));
        throw error;
    }
}
```

***

### What Just Happened? (Code Explanation)

* The **setup phase** involved creating a `Configuration` instance. This object is the single source of truth for your API credentials.
* The **data preparation** followed Kibo's pattern of creating a structured object (`brandAttribute`) that mirrors the API's expected JSON schema.
* The **API call** used an instance of `ProductAttributesApi`. This SDK pattern separates concerns, giving you a dedicated client for each API resource. The `createAttribute()` method maps directly to the `POST` operation on the attributes endpoint.
* The **response handling** correctly anticipates Kibo's structured error response, making it easy to debug.

***

### Common Beginner Mistakes

**Mistake 1:** Using a single, generic API client.

```ts theme={null}
// Wrong - The SDK is not designed this way. There is no single "ApiClient".
const apiClient = new ApiClient(configuration);

// Correct - Instantiate a specific client for the resource you need to work with.
const productAttributesClient = new ProductAttributesApi(configuration);
const productTypesClient = new ProductTypesApi(configuration);
```

**Mistake 2:** Forgetting the `admin@` prefix for `attributeFQN`.

```ts theme={null}
// Wrong - Fails because `attributeFQN` must be unique and "brand" might be a system-reserved name.
const attribute = { attributeFQN: 'brand' };

// Correct - Using a namespace like `admin@` prevents collisions with system attributes.
const attribute = { attributeFQN: 'admin@brand' };
```

***

### How This Connects to Other Kibo Operations

Creating an attribute is the foundation for everything else:

* **Creating Product Types**: You cannot create a Product Type without first having the Attributes you want to assign to it.
* **Creating Products**: The attributes of a product are inherited from its Product Type. This operation defines what is available to be inherited.

***

## Advanced Catalog Patterns

### When You've Mastered the Basics

Now let's explore a sophisticated, multi-step workflow: adding a new color option to an existing product and activating the new product variations that result from it.

### Pattern 1: Dynamically Adding an Option and Activating Variations

**Business Scenario:**
Your supplier has introduced a new color, "Kibo Yellow," for an existing T-shirt. You need to add this color as a selectable option on the product page and make the new variations (e.g., "Kibo Yellow, Small," "Kibo Yellow, Medium") available for purchase with their own unique SKUs.

**Kibo's Architecture Consideration:**
This is a multi-step process because Kibo's data is normalized. The new color "Kibo Yellow" must be:

1. Added to the master list of all possible colors (**Attribute Vocabulary**).
2. Associated with the T-shirt's **Product Type** so other future T-shirts can also use it.
3. Associated with the specific T-shirt **Product** itself as a selectable option.
4. Used to generate and activate the new **Product Variations**.

**API Endpoints Used:**

* `POST /api/commerce/catalog/admin/attributedefinition/attributes/{attributeFQN}/vocabularyvalues`
* `PUT /api/commerce/catalog/admin/producttypes/{productTypeId}/attributes/{attributeFQN}`
* `PUT /api/commerce/catalog/admin/products/{productCode}/options/{attributeFQN}`
* `PUT /api/commerce/catalog/admin/products/{productCode}/variations`

**Implementation Strategy:**

```typescript theme={null}
import { Configuration } from "@kibocommerce/rest-sdk";
import { ProductAttributesApi, ProductTypesApi, ProductOptionsApi, ProductVariationsApi, CatalogAdminsAttributeVocabularyValue, AttributeInProductType, ProductOption, ProductVariationPagedCollection } from "@kibocommerce/rest-sdk/clients/CatalogAdministration";

// Use the same configuration object from the previous example
const configuration = new Configuration({     
    // Your Tenant ID from Dev Center
    tenantId: process.env.KIBO_TENANT_ID,
    // Your Site ID from Dev Center
    siteId: process.env.KIBO_SITE_ID,
    // Your Application Key from Dev Center
    clientId: process.env.KIBO_CLIENT_ID,
    // Your Application Secret from Dev Center
    sharedSecret: process.env.KIBO_SHARED_SECRET,
    // The base auth URL for your region
    authHost: process.env.KIBO_AUTH_HOST 
    });

async function addNewColorOption(colorName: string, attributeFQN: string, productTypeId: number, productCode: string) {
    // 1. Instantiate all the necessary API clients
    const productAttributesClient = new ProductAttributesApi(configuration);
    const productTypesClient = new ProductTypesApi(configuration);
    const productOptionsClient = new ProductOptionsApi(configuration);
    const productVariationClient = new ProductVariationsApi(configuration);

    // 2. Define the new color value in the required format
    const vocabularyValue: CatalogAdminsAttributeVocabularyValue = {
        value: colorName.replace(/\s/g, '-').toLowerCase(),
        content: {
            localeCode: 'en-US',
            stringValue: colorName
        }
    };

    try {
        // STEP A: Add the new color to the master attribute list
        const newVocabValue = await productAttributesClient.addAttributeVocabularyValue({ attributeFQN, attributeVocabularyValue: vocabularyValue });
        console.log(`Added attribute value: ${colorName}`);

        // STEP B: Update the Product Type to include this new color as a possibility      
        const productTypeAttr = await productTypesClient.getProductType({ productTypeId });
        productTypeAttr.options?.find(opt => opt.attributeFQN === attributeFQN)?.vocabularyValues?.push(newVocabValue);
        await productTypesClient.updateProductType({ productTypeId, productType: productTypeAttr });
        console.log(`Updated product type ${productTypeId} with new color`);

        // STEP C: Update the specific Product to include this new color as a selectable option
        const productOption = await productOptionsClient.getOption({ productCode, attributeFQN });
        productOption.values?.push(newVocabValue);
        await productOptionsClient.updateOption({ productCode, attributeFQN, catalogAdminsProductOption: productOption });
        console.log(`Added new color option to product ${productCode}`);

        // STEP D: Find and activate the newly created (but inactive) variations
        const existingVariations = await productVariationClient.getProductVariations({ productCode });
        const colorMatchValue = colorName.replace(/\s/g, '-').toLowerCase();

        if (existingVariations.items) {
            for (const variation of existingVariations.items) {
                const hasMatchingOption = variation.options?.some(o => o.attributeFQN === attributeFQN && o.value === colorMatchValue);
                // Activate only if it's new and matches our color
                if (hasMatchingOption && !variation.isActive) {
                    variation.isActive = true;
                    variation.variationExists = true; // Mark it as real
                    // Generate a unique SKU for the new variation
                    variation.variationProductCode = `${productCode}-${colorMatchValue}-${variation.options?.find(o=>o.attributeFQN?.includes('size'))?.value || 'sz'}`;
                }
            }
        }

        await productVariationClient.updateProductVariations({ productCode, productVariationPagedCollection: existingVariations });
        console.log(`Activated new variations for color ${colorName} on product ${productCode}`);

    } catch (e) {
        console.error("Failed to add new color option:", JSON.stringify(e, null, 2));
    }
}

// Example usage:
// addNewColorOption("Kibo Yellow", "tenant~color", 6, "HikeJack_001");
```

***

### Multiple Real-World Examples

**Example 1: Create a Product Type**

```ts theme={null}
import { Configuration } from "@kibocommerce/rest-sdk";
import { ProductTypesApi, ProductType } from "@kibocommerce/rest-sdk/clients/CatalogAdministration";

// Use the same configuration object from the previous example
const configuration = new Configuration({     
    // Your Tenant ID from Dev Center
    tenantId: process.env.KIBO_TENANT_ID,
    // Your Site ID from Dev Center
    siteId: process.env.KIBO_SITE_ID,
    // Your Application Key from Dev Center
    clientId: process.env.KIBO_CLIENT_ID,
    // Your Application Secret from Dev Center
    sharedSecret: process.env.KIBO_SHARED_SECRET,
    // The base auth URL for your region
    authHost: process.env.KIBO_AUTH_HOST 
    });

async function createClothingProductType(config: Configuration) {
    const productTypesClient = new ProductTypesApi(config);

    const clothingType: ProductType = {
        name: 'Apparel',
        attributes: [
            { attributeFQN: 'admin@brand' }, // Assumes these attributes already exist
            { attributeFQN: 'tenant~color' },
            { attributeFQN: 'tenant~size' },
        ],
    };

    try {
        console.log('Creating "Apparel" product type...');
        const newProductType = await productTypesClient.addProductType({ productType: clothingType });
        console.log('Successfully created product type:', newProductType);
        return newProductType;
    } catch (error) {
        console.error('Error creating product type:', JSON.stringify(error, null, 2));
    }
}
```

**Example 2: Create a Base Product for Variations**

```ts theme={null}
import { Configuration } from "@kibocommerce/rest-sdk";
import { ProductsApi, catalogAdminsProduct } from "@kibocommerce/rest-sdk/clients/CatalogAdministration";

// Use the same configuration object from the previous example
const configuration = new Configuration({     
    // Your Tenant ID from Dev Center
    tenantId: process.env.KIBO_TENANT_ID,
    // Your Site ID from Dev Center
    siteId: process.env.KIBO_SITE_ID,
    // Your Application Key from Dev Center
    clientId: process.env.KIBO_CLIENT_ID,
    // Your Application Secret from Dev Center
    sharedSecret: process.env.KIBO_SHARED_SECRET,
    // The base auth URL for your region
    authHost: process.env.KIBO_AUTH_HOST 
    });

async function createBaseTshirt(config: Configuration, productTypeId: number) {
    const productsClient = new ProductsApi(config);

    const tshirt: CatalogAdminsProduct = {
        productCode: 'TSHIRT-01',
        productTypeId: productTypeId, // The ID of the "Apparel" type
        productUsage: 'Configurable', // This product is a container, not directly purchasable
        content: {
            productName: 'Basic Crewneck T-Shirt',
            productFullDescription: 'A comfortable and stylish t-shirt.',
        },
        // Price and other details will be set on the variations
    };

    try {
        const newProduct = await productsClient.addProduct({ catalogAdminsProduct: tshirt });
        console.log('Successfully created base product:', newProduct);
        return newProduct;
    } catch (error) {
        console.error('Error creating product:', JSON.stringify(error, null, 2));
    }
}
```

**Example 3: Create a Product Bundle**

```ts theme={null}
import { Configuration } from "@kibocommerce/rest-sdk";
import { ProductsApi, CatalogAdminsProduct } from "@kibocommerce/rest-sdk/clients/CatalogAdministration";

// Use the same configuration object from the previous example
const configuration = new Configuration({     
    // Your Tenant ID from Dev Center
    tenantId: process.env.KIBO_TENANT_ID,
    // Your Site ID from Dev Center
    siteId: process.env.KIBO_SITE_ID,
    // Your Application Key from Dev Center
    clientId: process.env.KIBO_CLIENT_ID,
    // Your Application Secret from Dev Center
    sharedSecret: process.env.KIBO_SHARED_SECRET,
    // The base auth URL for your region
    authHost: process.env.KIBO_AUTH_HOST 
    });

async function createStarterKitBundle(config: Configuration) {
    const productsClient = new ProductsApi(config);

    const bundle: CatalogAdminsProduct = {
        productCode: 'STARTER-KIT',
        productUsage: 'Bundle', // The key difference is the product usage type
        content: { productName: 'Hiking Starter Kit' },
        price: { price: 150.00 }, // Bundles can have their own price
        bundledProducts: [ // List of products included in the bundle
            { productCode: 'HikeJack_001', quantity: 1 },
            { productCode: 'HikeBoot_002', quantity: 1 },
            { productCode: 'WaterBottle_003', quantity: 2 },
        ]
    };

    try {
        const newBundle = await productsClient.addProduct({ catalogAdminsProduct: bundle });
        console.log('Successfully created bundle:', newBundle);
        return newBundle;
    } catch (error) {
        console.error('Error creating bundle:', JSON.stringify(error, null, 2));
    }
}
```

**Example 4: Add a Product to a Category**

```ts theme={null}
import { Configuration } from "@kibocommerce/rest-sdk";
import { CategoriesApi } from "@kibocommerce/rest-sdk/clients/CatalogAdministration";

// Use the same configuration object from the previous example
const configuration = new Configuration({     
    // Your Tenant ID from Dev Center
    tenantId: process.env.KIBO_TENANT_ID,
    // Your Site ID from Dev Center
    siteId: process.env.KIBO_SITE_ID,
    // Your Application Key from Dev Center
    clientId: process.env.KIBO_CLIENT_ID,
    // Your Application Secret from Dev Center
    sharedSecret: process.env.KIBO_SHARED_SECRET,
    // The base auth URL for your region
    authHost: process.env.KIBO_AUTH_HOST 
    });

async function addProductToCategory(config: Configuration) {
    // Note: This operation is on the CategoriesApi in newer SDK versions.
    const categoriesClient = new CategoriesApi(config);
    const productCodes = ['TSHIRT-01'];
    const categoryId = 5;

    try {
        await categoriesClient.addProductsToCategory({ categoryId, requestBody: productCode });
        console.log(`Successfully added product ${productCodes} to category ${categoryId}`);
    } catch (error) {
        console.error('Error adding product to category:', JSON.stringify(error, null, 2));
    }
}
```

**Example 5: Create a Dynamic Category**

```ts theme={null}
import { Configuration } from "@kibocommerce/rest-sdk";
import { CategoriesApi, CatalogAdminsCategory } from "@kibocommerce/rest-sdk/clients/CatalogAdministration";

// Use the same configuration object from the previous example
const configuration = new Configuration({     
    // Your Tenant ID from Dev Center
    tenantId: process.env.KIBO_TENANT_ID,
    // Your Site ID from Dev Center
    siteId: process.env.KIBO_SITE_ID,
    // Your Application Key from Dev Center
    clientId: process.env.KIBO_CLIENT_ID,
    // Your Application Secret from Dev Center
    sharedSecret: process.env.KIBO_SHARED_SECRET,
    // The base auth URL for your region
    authHost: process.env.KIBO_AUTH_HOST 
    });

async function createOnSaleCategory(config: Configuration) {
    const categoriesClient = new CategoriesApi(config);

    const dynamicCategory: CatalogAdminsCategory = {
        content: { name: 'On Sale' },
        categoryType: 'Dynamic',
        dynamicExpression: {
            // This Kibo filter expression finds all products where the price is less than 50
            text: 'price lt 50'
        }
    };

    try {
        const newCategory = await categoriesClient.addCategory({ CatalogAdminsCategory: dynamicCategory });
        console.log('Successfully created dynamic category:', newCategory);
        return newCategory;
    } catch (error) {
        console.error('Error creating dynamic category:', JSON.stringify(error, null, 2));
    }
}
```

***

## Integrating Catalog with Other Kibo Domains

### Catalog + Orders Integration

When a customer places an order, the `Order.items` array contains product details. The `item.product.productCode` directly links back to the unique identifier of a product or variation in your catalog.

### Catalog + Customer Data Integration

Customer accounts can have wishlists or purchase histories that reference products from the catalog via their `productCode`.

***

## Troubleshooting Your Catalog Implementation

### Reading Kibo Error Messages

```typescript theme={null}
// Actual error structure from Kibo API documentation
interface KiboApiError {
  errorCode: string;     // Specific error codes from apidocs.kibocommerce.com
  message: string;         // Error description
  correlationId: string;   // For support tracking
}
```

**Common Error Codes for Catalog:**

* `ATTRIBUTE_FQN_ALREADY_EXISTS`: You tried to create an attribute with an `attributeFQN` that is already in use.
* `VALIDATION_ERROR`: The request body is missing a required field or contains a value of the wrong data type.
* `PRODUCT_CODE_ALREADY_EXISTS`: You tried to create a product with a `productCode` that already exists.
* `ITEM_NOT_FOUND`: You referenced an item that doesn't exist, such as a non-existent `productTypeId`.

***

### Common Development Issues

**Issue 1:** My new product isn't showing up on the storefront.

* **Why it happens:** A product must be **active**, have a **price**, have **inventory** (if tracked), and be in a **category**.
* **How to fix it:** Verify each of these conditions using the API.
* **API Reference:** [`/api-reference/productsv1/update-product`](/api-reference/productsv1/update-product)

**Issue 2:** My API call to create a product is failing with a `VALIDATION_ERROR`.

* **Why it happens:** Most often, your `productUsage` is incorrect, or you are missing a required field on the `content` object, like `productName`.
* **How to fix it:** Carefully compare every field in your request body to the schema on the API documentation for the `createProduct` endpoint.
* **API Reference:** [`/api-reference/productsv1/add-product`](/api-reference/productsv1/add-product)

***

### Debugging Checklist

When your Catalog implementation isn't working:

1. Verify your `Configuration` object has the correct credentials.
2. Confirm your request body exactly matches the schema in the API docs.
3. Check the `correlationId` in the error response. It's the most useful piece of information for Kibo support.
4. Ensure you are instantiating and using the correct API client (e.g., `ProductTypesApi` for product types).
5. Validate that prerequisite objects exist (e.g., the attribute exists before you add it to a product type).
