Skip to main content

Kibo Cart API Developer Guide

Understanding Cart in Kibo

In Kibo, a Cart is more than just a list of products; it’s a transactional object that represents a shopper’s entire potential purchase. It holds the items, quantities, applied coupons, and calculated totals. Kibo’s philosophy is to treat the cart as a “draft” of an order that can exist for both guest and logged-in shoppers. When a guest with a cart logs in, Kibo intelligently merges their anonymous cart with any previous cart they had, creating a seamless shopping experience. The Cart API is part of the Storefront API group, meaning it’s designed to be called securely from a front-end application.

How This Domain Fits Into Kibo

The Cart is the central hub of the shopping experience, connecting several key domains:
  • Catalog: The cart holds references to products (productCode) from the catalog. It pulls in pricing and other details.
  • Promotions: The Cart API is where you apply coupon codes, and Kibo’s promotion engine calculates the discounts directly on the cart object.
  • Customer: Carts can be associated with a customer account, allowing them to be persisted between sessions.
  • Checkout: The cart is the direct input for creating a Checkout object. The checkout process is essentially the act of gathering the remaining information (shipping, billing, payment) needed to convert the cart into an order.
  • Orders: Once the checkout is complete, the cart’s data is used to create a permanent Order record in Kibo.

Prerequisites

  • Kibo Application Key
  • Node.js 16+ with TypeScript
  • Familiarity with REST APIs and front-end development concepts

What You’ll Learn

After completing this guide, you’ll understand:
  • How Kibo structures cart data for storefront interactions (based on official API specs)
  • The key patterns for creating, managing, and converting a shopper’s cart
  • Common workflows like adding items, applying coupons, and updating quantities
  • How to avoid the most common beginner mistakes when working with carts
  • How to transition a cart into the checkout and order phases of the e-commerce lifecycle

Kibo Cart Fundamentals

How Kibo Organizes Cart Data

The core object is the Cart, which contains an array of CartItem objects.
  • Cart: The parent object. It has a unique id, a total, a list of applied coupons, and other summary information. For guest shoppers, this cart is tracked via a cookie or session. For logged-in shoppers, it’s associated with their customerAccountId.
  • CartItem: Represents a single line item in the cart. It contains a product object (with details like productCode and name), the quantity, and a total for that line.

Key Kibo Patterns You’ll See Everywhere

Authentication Pattern: Storefront APIs, including the Cart API, are secured using OAuth 2.0 Bearer tokens. This applies to both application-level and shopper-level authentication.
  1. Application Authentication:
    • When: Used for server-to-server requests or calls that are not on behalf of a specific, logged-in shopper (e.g., using explicit cartId APIs).
    • How: Your application authenticates using its credentials (e.g., Client ID and Shared Secret) via an OAuth flow to obtain an application-level Bearer token.
    • Usage: This token is passed in the request header: Authorization: Bearer <application_token>.
  2. Shopper Authentication:
    • When: Used for requests made in the context of a logged-in shopper, such as managing the /current cart.
    • How: The shopper logs in via the Customer Auth Ticket API (POST /api/commerce/customer/authtickets), which returns a jwtAccessToken.
    • Usage: This shopper-specific JWT is passed in the request header: Authorization: Bearer <shopper_jwtAccessToken>. The Kibo SDK, when configured with this token, handles this automatically.
Request/Response Structure: Most Cart API calls (addItemToCartByCartId, updateCartItemQuantityByCartId, applyCouponByCartId) are transactional. After you perform an action, the API returns the entire updated Cart object. This is a key pattern: you don’t need to re-fetch the cart after every change; the API response gives you the latest state, which you can use to update your UI. Error Handling Approach: If an operation fails (e.g., adding an out-of-stock item, applying an invalid coupon), the SDK will throw an error containing Kibo’s standard error object, including an errorCode and message. API Documentation Reference: Throughout this guide, we’ll reference specific endpoints. Find complete specs at: /api-reference/cart/get-cart-summary

Common Cart Workflows

  1. Starting a Session: Creating a cart to get a cartId.
  2. Building the Cart: Adding products, updating quantities, and applying discounts using the cartId.
  3. Finalizing the Purchase: Converting the cart into a checkout or a direct order.
Let’s explore each pattern step by step.

Add an Item to the Cart (Application Token / Explicit cartId)

This is the recommended approach for server-side integrations or when using a Kibo Application Token, where you need to explicitly manage the cart’s lifecycle.

When You Need This

You need this when a server-side process or application needs to create and manage a cart. This gives you direct control over which cart is being modified.

API Documentation Reference


Understanding the Kibo Approach

Using an explicit cart ID requires a two-step process. First, you must create a cart to get a unique cartId (see the “Create a New Cart” example below). Then, you use that cartId for all subsequent operations, like adding an item.

Code Structure Walkthrough

// We'll build this step by step:
// 1. **Configuration**: Create a central Configuration instance with our storefront API credentials.
// 2. **API Client Instantiation**: Create a dedicated client for the Storefront Cart API.
// 3. **Data Preparation**: Construct the `CartItem` object with the product code and quantity.
// 4. **API Call**: Use the client to call the `addItemToCartByCartId` method, passing the `cartId` you created.

Step-by-Step Implementation

Step 1: Setting Up the Foundation
// Essential imports for Cart operations.
// We import the Configuration class and the specific API clients we need.
import { Configuration } from "@kibocommerce/rest-sdk";
import { CartApi, CartItem, Cart } from "@kibocommerce/rest-sdk/clients/Commerce";

// Configuration setup for storefront. This uses your public Application Key.
const configuration = new Configuration({
    tenantId: process.env.KIBO_TENANT_ID,
    siteId: process.env.KIBO_SITE_ID,
    // This is your public Application Key from Dev Center
    appKey: process.env.KIBO_APP_KEY,
    authHost: process.env.KIBO_AUTH_HOST,
});
Step 2: Understanding the Data Flow We’ll create a CartItem object. This object tells the API which product to add (via its productCode) and how many. For products with options (like color or size), we would also include an options array. The API will validate this information against the catalog, check inventory, and if successful, add it to the specified cart, returning the entire updated cart object. Step 3: The Core Implementation
// Complete working example that ACTUALLY WORKS with the Kibo API.
// Assumes you have already called createCart() and have a cartId.
async function addProductToCart(cartId: string, productCode: string, quantity: number): Promise<Cart> {
    // 1. Instantiate a dedicated client for the Storefront Cart resource.
    const cartClient = new CartApi(configuration);

    // 2. Prepare the request body. This object must match the CartItem schema.
    const cartItem: CartItem = {
        quantity: quantity,
        product: {
            productCode: productCode,
            // For configurable products, you would add an options array here, e.g.,
            // options: [
            //    { attributeFQN: 'tenant~color', value: 'blue' },
            //    { attributeFQN: 'tenant~size', value: 'medium' }
            // ]
        },
    };

    try {
        // 3. Call the method on the client.
        console.log(`Adding ${quantity} of product ${productCode} to cart ${cartId}...`);
        const addedCartItem = await cartClient.addItemToCartByCartId({
            cartId: cartId,
            cartItem: cartItem
        });

        console.log("Success! ", produtCode, " added to cart.");
        return updatedCart;
    } catch (error) {
        console.error("API Error adding item to cart:", JSON.stringify(error, null, 2));
        throw error;
    }
}

What Just Happened? (Code Explanation)

  • The setup phase created a Configuration object using the public appKey, which is the correct and secure way to authenticate storefront requests.
  • The API call was made using an instance of CartApi and the addItemToCartByCartId method. This requires us to have a cartId before we can call it. This cartId is typically retrieved from a createCart call (see ‘Create a New Cart’ example).
  • The response handling leverages Kibo’s pattern of returning the full, updated Cart object upon success, providing immediate access to the new total and item count without a follow-up request.
  • Kibo will populate the rest of the product information from the data in the Catalog.

Common Beginner Mistakes

Mistake 1: Forgetting to include product options for configurable products.
// Wrong - This will fail with a validation error for a T-shirt that requires a color and size.
const item = { product: { productCode: 'TSHIRT-01' }, quantity: 1 };

// Correct - Provide the selected option values in the `options` array.
const item = {
    product: {
        productCode: 'TSHIRT-01',
        options: [
            { attributeFQN: 'tenant~color', value: 'blue' },
            { attributeFQN: 'tenant~size', value: 'medium' }
        ]
    },
    quantity: 1
};

Add an Item to the Cart (Shopper Token / /current APIs)

Kibo also provides session-based /current APIs. These are designed to be used with an authenticated shopper’s JSON Web Token (JWT). When a shopper logs in, your application should exchange their credentials for a customer auth ticket. This endpoint returns an jwtAccessToken. When you make subsequent API calls (like to the Cart API) and provide this token in the Authorization header, the Kibo platform gains the context of that specific shopper. In this authenticated context, the /current keyword in API paths becomes a powerful shortcut. It automatically resolves to the cart associated with the logged-in shopper, eliminating the need to manually track a cartId on the client side.

Example: Add an Item to the Authenticated Shopper’s Cart

This workflow assumes you have already obtained and configured the Kibo SDK to use the shopper’s accessToken. Here is the updated section, modified to use a client-side fetch example and simulate token retrieval.

API Documentation Reference

Understanding the Kibo Approach

With an authenticated shopper token, Kibo’s /current/items endpoint is seamless. If a cart doesn’t exist for that shopper, Kibo automatically creates one and associates it with their account. If they already have a cart (perhaps from a previous session), Kibo adds the item to that existing cart. You don’t need to manage the cartId manually; the shopper’s Authorization: Bearer <token> header provides all the necessary context for the Kibo platform to find and update the correct cart.

Code Implementation (Client-Side Fetch)

/**
 * Simulates retrieving the shopper's JWT.
 * In a real application, this would come from localStorage, sessionStorage,
 * or a secure cookie after the shopper logs in.
 */
async function fetchAnonShopperAuthToken(username: string, password: string): Promise<string | null> {
  console.log(`Attempting to log in as ${username}...`);

  const KIBO_API_HOST = process.env.REACT_APP_KIBO_API_HOST; // e.g., "t12345.sandbox.mozu.com"
  const appToken = getApplicationToken(); // Get the app-level auth token

  // The endpoint to exchange credentials for a shopper token
  const apiUrl = `https://://${KIBO_HOST}/api/customer/authtickets/anonymousshopper`;

  const fetchOptions = {
    method: 'GET',
    headers: {
      'Content-Type': 'application/json',
    }
  };

  try {
    const response = await fetch(apiUrl, fetchOptions);

    if (!response.ok) {
      // Handle login failures (e.g., 401 Invalid Credentials)
      const errorData = await response.json();
      console.error('Login Error:', errorData.message || 'Invalid username or password');
      return null;
    }

    const authTicket = await response.json();

    const shopperToken = authTicket.jwtAccessToken;
    
    if (shopperToken) {
      console.log("Shopper login successful. JWT retrieved.");
      // In a real app, you would now store this token securely
      // (e.g., localStorage.setItem('shopperToken', shopperToken));
      return shopperToken;
    } else {
      console.error("Login successful, but no jwtAccessToken was returned.");
      return null;
    }

  } catch (error) {
    console.error("Fetch Error during login:", error);
    return null;
  }
}

/**
 * Adds an item to the /current cart using the native Fetch API.
 * This assumes the shopper is logged in and their token is available.
 */
async function addItemToShopperCart(productCode: string, quantity: number): Promise<any> {
  const shopperToken = fetchAnonShopperAuthToken();
  
  if (!shopperToken) {
    throw new Error("Cannot add to cart. Shopper is not authenticated.");
  }

  
  const apiUrl = `/api/commerce/carts/current/items`;

  const cartItemBody = {
    quantity: quantity,
    product: {
      productCode: productCode,
      // For configurable products, you would add an options array here
      // options: [
      //   { attributeFQN: 'tenant~color', value: 'blue' }
      // ]
    },
  };

  const fetchOptions = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      // The shopper's JWT is passed as the Bearer token
      'Authorization': `Bearer ${shopperToken}`,
    },
    body: JSON.stringify(cartItemBody),
  };

  try {
    console.log(`Adding ${quantity} of ${productCode} to the /current shopper cart...`);
    const response = await fetch(apiUrl, fetchOptions);

    if (!response.ok) {
      const errorData = await response.json();
      console.error('API Error:', errorData.message || 'Unknown error');
      throw new Error(`API request failed: ${response.status} ${response.statusText}`);
    }

    const updatedCart = await response.json();
    
    console.log("Success! Shopper's cart now has", updatedCart.items?.length, "items.");
    return updatedCart;

  } catch (error) {
    console.error("Fetch Error adding item to shopper's cart:", error);
    throw error;
  }
}

Key Takeaway

  • Use explicit cartId APIs (e.g., createCart, addItemToCartByCartId) when authenticating with an Application Bearer Token (server-to-server, app-level context).
  • Use /current APIs (e.g., /api/commerce/carts/current/items) when authenticating with a Shopper JWT (client-side, logged-in shopper context).

Advanced Patterns & Multiple Examples

The following examples use the explicit cartId pattern, which is common for server-side management.

Pattern 1: Converting a Cart to a Checkout

Business Scenario: After a shopper has added items to their cart, they click the “Checkout” button. You need to transition them to the checkout process where they can enter shipping and payment information. Kibo’s Architecture Consideration: This is a handoff between two different domains. The Cart is the input used to create a new Order object. The OrderApi takes a cartId and creates a new, persistent checkout with its own unique ID. This new order object will contain all the items from the cart, plus new sections for shipping info, billing info, and payments.
import { Configuration } from "@kibocommerce/rest-sdk";
import { OrderApi, Order } from "@kibocommerce/rest-sdk/clients/Commerce";

async function convertCartToOrder(config: Configuration, cartId: string): Promise<Order> {
    const orderClient = new OrderApi(config);
    try {
        if (!cartId) {
            throw new Error("A valid cartId must be provided.");
        }
        console.log(`Submitting order from cart ${cartId}...`);

        // This uses the OrderApi, showing cross-domain integration.
        const newOrder = await orderClient.createOrder({ cartId: cartId });
        console.log(`Successfully created order ${newOrder.id}.`);
        return newOrder;
    } catch (error) {
        console.error("Failed to convert cart to order:", JSON.stringify(error, null, 2));
        throw error;
    }
}

More Real-World Examples

Example 2: Create a New Cart This is the first step for any workflow. You call createCart to get a new cart object and its ID.
import { Configuration } from "@kibocommerce/rest-sdk";
import { CartApi, Cart } from "@kibocommerce/rest-sdk/clients/Commerce";

async function createNewCart(config: Configuration): Promise<Cart> {
    const cartClient = new CartApi(config);
    try {
        console.log("Creating a new cart...");
        const cart = await cartClient.createOrCreateCart();
        console.log(`New cart created with ID: ${cart.id}`);
        return cart;
    } catch (error) {
        console.error("Failed to create cart:", JSON.stringify(error, null, 2));
        throw error;
    }
}
Example 2b: Get an Existing Cart by ID Once you have a cartId, you can retrieve it at any time.
import { Configuration } from "@kibocommerce/rest-sdk";
import { CartApi, Cart } from "@kibocommerce/rest-sdk/clients/Commerce";

async function getExistingCart(config: Configuration, cartId: string): Promise<Cart> {
    const cartClient = new CartApi(config);
    try {
        console.log(`Getting cart with ID: ${cartId}...`);
        const cart = await cartClient.getCart({ cartId: cartId });
        console.log(`Cart ${cart.id} retrieved.`);
        return cart;
    } catch (error) {
        console.error("Failed to get cart:", JSON.stringify(error, null, 2));
        throw error;
    }
}
Example 3: Apply a Promotion (Coupon) to the Cart
import { Configuration } from "@kibocommerce/rest-sdk";
import { CartApi, Cart } from "@kibocommerce/rest-sdk/clients/Commerce";

async function applyCoupon(config: Configuration, cartId: string, couponCode: string): Promise<Cart> {
    const cartClient = new CartApi(config);
    try {
        console.log(`Applying coupon "${couponCode}" to cart ${cartId}...`);
        // The API call returns the entire updated cart object with the discount applied.
        const updatedCart = await cartClient.applyCoupon({
            cartId: cartId,
            couponCode: couponCode
        });
        console.log("Coupon applied successfully. New total:", updatedCart.total);
        return updatedCart;
    } catch (error) {
        console.error("Failed to apply coupon:", JSON.stringify(error, null, 2));
        throw error;
    }
}
Example 4: Update Cart Item Quantity
import { Configuration } from "@kibocommerce/rest-sdk";
import { CartApi, Cart } from "@kibocommerce/rest-sdk/clients/Commerce";

async function updateItemQuantity(config: Configuration, cartId: string, cartItemId: string, newQuantity: number): Promise<CartItem | void> {
    const cartClient = new CartApi(config);
    try {
        console.log(`Updating item ${cartItemId} in cart ${cartId} to quantity ${newQuantity}...`);
        if (newQuantity <= 0) {
            // To remove an item, you call `deleteCartItemByCartId`.
            console.log("Quantity is zero or less, removing item...");
            return await cartClient.deleteCartItemByCartId({
                cartId: cartId,
                cartItemId: cartItemId
            });
        } else {
            const updatedCart = await cartClient.updateCartItemQuantityByCartId({
                cartId: cartId,
                cartItemId: cartItemId,
                quantity: newQuantity,
            });
            console.log("Quantity updated. New total:", updatedCart.total);
            return updatedCartItem;
        }
    } catch (error) {
        console.error("Failed to update quantity:", JSON.stringify(error, null, 2));
        throw error;
    }
}
Example 5: Submit an Order Directly from a Cart This advanced pattern user the multi-step checkout and is useful for integrations supporting multiple fulfillment destinations in the same purchase.
// Example 1: Create a Checkout from a Cart ID
import { Configuration } from "@kibocommerce/rest-sdk";
import { CheckoutApi, Checkout } from "@kibocommerce/rest-sdk/clients/Commerce";

async function convertCartToCheckout(config: Configuration, cartId: string): Promise<Checkout> {
    const checkoutClient = new CheckoutApi(config);

    try {
        if (!cartId) {
            throw new Error("A valid cartId must be provided.");
        }
        console.log(`Creating checkout from cart ${cartId}...`);

        // Now, use the cart ID to create a checkout.
        // This is a separate API call to the Checkout resource.
        const newCheckout = await checkoutClient.createCheckoutFromCart({ cartId: cartId });

        console.log(`Successfully created checkout ${newCheckout.id}.`);
        return newCheckout;
    } catch (error) {
        console.error("Failed to convert cart to checkout:", JSON.stringify(error, null, 2));
        throw error;
    }
}

Troubleshooting Your Cart Implementation

Reading Kibo Error Messages

// Actual error structure from Kibo API
interface KiboApiError {
  errorCode: string;        // e.g., "ITEM_NOT_FOUND"
  message: string;          // "The item requested could not be found."
  correlationId: string;    // For Kibo support
}
Common Error Codes for Cart:
  • VALIDATION_ERROR: The most common error. The CartItem you tried to add was invalid (e.g., missing options, invalid productCode). The error message will provide more details.
  • PRODUCT_NOT_IN_CATALOG: The product is not assigned to the catalog used by the current site.
  • NOT_STOCKED: You tried to add an item with no inventory, and the site is configured to block backorders.
  • COUPON_INVALID: The coupon code does not exist, has expired, or is not applicable to the items in the cart.

Common Development Issues

Issue 1: ‘Cart not found’ or 404 error when managing items.
  • Why it happens: You are trying to use a cartId that is invalid, expired, or doesn’t exist. This can happen if you don’t correctly store the cartId after your initial createCart call.
  • How to fix it: Ensure your application state correctly captures and re-uses the cartId returned from a createCart call.
  • API Reference: The createCart method is the starting point. All other methods like addItemToCartByCartId depend on its output.
Issue 2: A coupon won’t apply, but I know it’s valid.
  • Why it happens: The promotion might have targeting rules. It could be limited to a specific customer segment, a minimum cart value, or specific products. The Storefront API enforces all these rules automatically.
  • How to fix it: Check the promotion’s configuration in Kibo Admin. Make sure the cart’s contents and the shopper’s context (e.g., logged in or guest) meet all the discount’s requirements.
  • API Reference: /api-reference/cart/apply-coupon

Debugging Checklist

When your Cart implementation isn’t working:
  1. Verify your Configuration object uses the public appKey.
  2. If using shopper-authenticated APIs, verify your Authorization JWT is valid and not expired.
  3. Check the browser’s network tab to see the API response. The error message is often very descriptive.
  4. Ensure the productCode you’re adding is correct, active, and available on the storefront.
  5. For configurable products, double-check that the attributeFQN and value for all required options are correct.
  6. Use the correlationId from any error message when contacting Kibo support.