Skip to main content

Kibo Catalog API Developer Guide

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


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:
// 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
// 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
// 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.
// 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.
// 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:
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
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
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
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
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
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

// 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
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

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