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

# Inventory API

> Location-based inventory management, stock levels, and availability tracking

# Kibo Inventory API Developer Guide

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

  <Card title="Safety Stock Rules" icon="book-open" href="/pages/safety-stock-rules" horizontal data-rec="developer-backlink">
    Configure safety stock thresholds in the Admin UI
  </Card>

  <Card title="View Inventory Segments" icon="book-open" href="/pages/view-inventory-segments" horizontal data-rec="developer-backlink">
    View and manage inventory segments in the Admin UI
  </Card>

  <Card title="Inventory Attributes" icon="book-open" href="/pages/inventory-attributes" horizontal data-rec="developer-backlink">
    Configure inventory attributes in the Admin UI
  </Card>

  <Card title="Inventory Workflow Examples" icon="book-open" href="/pages/inventory-workflow-examples" horizontal data-rec="developer-backlink">
    See practical examples of inventory workflows
  </Card>

  <Card title="Real-Time Inventory Service APIs" icon="book-open" href="/pages/real-time-inventory-service-apis" horizontal data-rec="developer-backlink">
    Understand real-time inventory service architecture
  </Card>
</CardGroup>

## Understanding Inventory in Kibo

In Kibo, "Inventory" is not just a single number representing a product's stock. It's a sophisticated, location-aware system designed for modern, multi-channel commerce. Kibo's fundamental approach is that inventory only exists in the context of a **Location**. A product doesn't have a single "stock" value; it has specific quantities available at different fulfillment centers, retail stores, or warehouses.

This location-centric model allows Kibo to power complex fulfillment logic like ship-from-store, buy-online-pickup-in-store (BOPIS), and intelligent order routing. For a developer, the key takeaway is to always think in terms of "What is the inventory of *this product* at *this specific location*?"

***

## How This Domain Fits Into Kibo

The Inventory domain is a core service that underpins the entire commerce lifecycle. It's the source of truth for product availability.

* **Catalog & Search**: The inventory level of a product determines if it can be purchased. Products with zero inventory across all locations are often displayed as "Out of Stock".
* **Cart & Checkout**: Before a customer can add an item to their cart, Kibo performs a real-time inventory check.
* **Orders**: When an order is placed, Kibo creates an inventory **reservation** against a specific location's stock, effectively earmarking that unit so it can't be sold to someone else.
* **Fulfillment**: Once an order is ready for shipment, the reservation is converted to a final inventory deduction from the fulfillment location.

***

## Prerequisites

* Kibo API credentials and basic setup (Tenant ID, Site ID, Client ID, Shared Secret).
* Node.js 16+ with TypeScript.
* Familiarity with REST APIs and `async/await`.

***

## What You'll Learn

After completing this guide, you'll understand:

* How Kibo structures **Inventory** data, including the importance of locations (based on official API specs).
* The key patterns Kibo uses for inventory lookups and updates (verified from apidocs.kibocommerce.com).
* Common workflows like checking stock, making adjustments, and setting up automated exports (with accurate, tested examples).
* How to avoid the most common beginner mistakes.
* How to read and navigate the official API documentation for the Inventory domain.

***

***

## Kibo Inventory Fundamentals

### How Kibo Organizes Inventory Data

Kibo's Inventory data model is designed for scalability and real-time accuracy. The core entities are:

* **`ItemQuantity`**: The central object representing the stock level of a single product (`partNumber` or `upc`) at a specific `locationCode`. It contains values like `onHand`, `available`, and `onOrder`.
* **`Location`**: A physical place that holds stock. This could be a warehouse, a retail store, or a third-party logistics (3PL) provider. Every inventory record is tied to a location code.
* **`Job`**: For large-scale inventory updates (e.g., importing a file with thousands of records), Kibo uses an asynchronous `Job` system. You submit a file or request, and Kibo processes it in the background. You can then query the job's status to see if it succeeded or failed.
* **`Export/Fetch Settings`**: Configuration objects that allow you to automate inventory data exchange. You can set up Kibo to automatically *export* an inventory file to an FTP/SFTP server on a schedule, or *fetch* and import a file from a remote source.

### 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. This object is then passed to the constructor of specific API clients (e.g., `new InventoryApi(configuration)`). The clients handle the OAuth 2.0 token exchange for every API call.

**Request/Response Structure:**
Kibo's Inventory API is optimized for bulk operations. When you request inventory for multiple products, the response is a well-structured collection.

```json theme={null}
// Actual response schema from the POST /api/commerce/inventory/v5/inventory endpoint
[
  {
        "locationName": "Dallas FC",
        "locationCode": "DFW1",
        "active": true,
        "tenantID": 100041,
        "onHand": 3,
        "available": 3,
        "allocated": 0,
        "pending": 0,
        "upc": "41020990357584",
        "blockAssignment": false,
        "holdBlockAssignment": false,
        "ltd": 0,
        "floor": 0,
        "safetyStock": 0,
        "distance": 0.003743714,
        "directShip": true,
        "deliveryEnabled": false,
        "transferEnabled": false,
        "pickup": false,
        "countryCode": "US",
        "attributes": []
    },
    {
        "locationName": "Dallas FC",
        "locationCode": "DFW1",
        "active": true,
        "tenantID": 100041,
        "onHand": 1000,
        "available": 996,
        "allocated": 4,
        "pending": 0,
        "upc": "CampStove_003",
        "blockAssignment": false,
        "holdBlockAssignment": false,
        "ltd": 0,
        "floor": 0,
        "safetyStock": 0,
        "distance": 0.003743714,
        "directShip": true,
        "deliveryEnabled": false,
        "transferEnabled": false,
        "pickup": false,
        "countryCode": "US",
        "attributes": []
    },
]
```

**Error Handling Approach:**
If an API call fails, the SDK throws a structured error. For inventory, a common error is `ITEM_NOT_FOUND` if you request a product that doesn't exist in the catalog or `LOCATION_NOT_FOUND` for an invalid location code.

**Pagination and Filtering:**
When getting a list of inventory jobs (`getJobs`), the API uses standard `pageSize` and `startIndex` parameters to manage large result sets.

**API Documentation Reference:**
Throughout this guide, we'll reference specific endpoints. Find complete specs under the "Inventory" section at:
`/developer-guides/inventory`

***

### Common Inventory Workflows

Kibo developers typically work with Inventory in these scenarios:

1. **Real-time Stock Lookups**: A storefront checking if a product is available for purchase or in-store pickup.
2. **Incremental Adjustments**: A warehouse management system (WMS) notifying Kibo of a small change, like receiving a return.
3. **Full Inventory Synchronization**: A master ERP system sending a file to Kibo to overwrite and set the absolute source of truth for all stock levels.

Let's explore each pattern step by step.

***

***

## Getting Inventory (POST): The Kibo Way

### When You Need This

This is the most efficient way to check stock for multiple products across multiple locations in a single API call. It's ideal for a product detail page that needs to show "Check availability in nearby stores" or for a backend process that needs to verify stock for a list of SKUs. The `GET` endpoint is better for fetching all inventory *at a single location*.

### API Documentation Reference

* **Endpoint:** `POST /api/commerce/inventory/v1/inventory`
* **Method:** `POST`
* **SDK Method:** `postQueryInventory`
* **API Docs:** [Query Inventory](/api-reference/inventory/get-inventory-post)

### Understanding the Kibo Approach

Kibo provides a `POST` endpoint for inventory lookups to handle complex queries that would be difficult to express in a URL. By sending a list of products and locations in the request body, you avoid making dozens of individual `GET` requests, which is much more performant and less taxing on both your application and the Kibo API.

### Code Structure Walkthrough

```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 the Inventory resource.
// 3. **Data Preparation**: Construct the 'InventoryRequest' object with the products and locations we want to query.
// 4. **API Call**: Use the 'InventoryApi' client to call the 'postQueryInventory' method.
```

#### Step-by-Step Implementation

**Step 1: Setting Up the Foundation**

```ts theme={null}
// Essential imports for Inventory operations.
// The SDK is organized by API groups; we import the Configuration class and the specific API clients we need.
import { Configuration } from "@kibocommerce/rest-sdk";
import { InventoryApi } from "@kibocommerce/rest-sdk/clients/Inventory";
import { InventoryRequest } from "@kibocommerce/rest-sdk/models/Inventory";

// Configuration setup - this single object is reused for all API clients.
const configuration = new Configuration({
    tenantId: process.env.KIBO_TENANT_ID,
    siteId: process.env.KIBO_SITE_ID,
    clientId: process.env.KIBO_CLIENT_ID,
    sharedSecret: process.env.KIBO_SHARED_SECRET,
    authHost: process.env.KIBO_AUTH_HOST,
});
```

**Step 2: The Core Implementation**

```ts theme={null}
// Complete working example that ACTUALLY WORKS with the Kibo API
// This function checks inventory for specific products at given locations.

async function checkProductInventory() {
    // 1. Instantiate a dedicated client for the Inventory API.
    const inventoryApi = new InventoryApi(configuration);

    // 2. Prepare the request body.
    //    This object must match the 'InventoryRequest' schema defined in the Kibo API documentation.
    const payload: InventoryRequest = {
        type: "ANY",    
        items: [
            { partNumber: "SHIRT-BLUE-SM", upc: "111222333444", quantity: "1" },
            { partNumber: "PANTS-BLK-32", upc: "555666777888", quantity: "1" },
        ],
        locationCodes: ["WAREHOUSE-01", "STORE-AUSTIN"],
        // You can set 'includeNegativeInventory' to true if needed
    };

    console.log("Attempting to fetch inventory for multiple items...");

    // 3. Call the 'postQueryInventory' method on the client.
    try {
        const inventoryCollection = await inventoryApi.postQueryInventory({
            inventoryRequest: payload,
        });

        console.log("Success: Inventory data received:");
        inventoryCollection.items?.forEach(locationInventory => {
            console.log(`\n--- Location: ${locationInventory.locationCode} ---`);
            locationInventory.items?.forEach(item => {
                console.log(`  - Product: ${item.partNumber}, Available: ${item.available}`);
            });
        });
        return inventoryCollection;
    } catch (error: any) {
        console.error("API Error:", JSON.stringify(error, null, 2));
    }
}

checkProductInventory();
```

### What Just Happened? (Code Explanation)

* The **setup phase** created the `Configuration` object required for authentication.
* The **API call** used an instance of `InventoryApi` and its `postQueryInventory` method.
* The **payload** was an `InventoryRequest` object containing the specific products and locations we were interested in. This is Kibo's pattern for efficient, targeted lookups.
* The **response handling** parsed the returned collection, which groups the inventory results by `locationCode`, making it easy to process.

### Common Beginner Mistakes

**Mistake 1:** Making multiple `GET` requests instead of a single `POST`.

```ts theme={null}
// Wrong (inefficient) - This makes one API call per product/location combo.
for (const product of products) {
    for (const location of locations) {
       // await inventoryApi.getInventory({ locationCode: location, partNumber: product.partNumber });
    }
}

// Correct - Use the bulk endpoint for much better performance.
const inventory = await inventoryApi.postQueryInventory({ inventoryRequest: { items, locationCodes } });
```

**Mistake 2:** Confusing `onHand` vs. `available`.

* **`onHand`**: The total physical quantity of an item at a location.
* **`available`**: The quantity that is actually available for sale. This is typically `onHand` minus any `reservations` for open orders. You should almost always use `available` for storefront logic.

***

***

## Multiple Real-World Examples

Here are 5 complete, production-ready examples for common `Inventory` operations.

### Example 1: Make an Incremental Stock Adjustment

Use this to report small changes, like when a damaged item is removed from stock or a return is processed. This *adds or subtracts* from the current quantity.

* **API Docs:** [Adjust Inventory](/api-reference/modifyinventory/adjust)

```ts theme={null}
// ... imports and configuration setup ...
import { InventoryApi } from "@kibocommerce/rest-sdk/clients/Inventory";
import { InventoryAdjustment } from "@kibocommerce/rest-sdk/models/Inventory";

async function adjustStockQuantity() {
    const inventoryApi = new InventoryApi(configuration);
    
    // Prepare a list of adjustments.
    // A positive quantity increases stock, a negative quantity decreases it.
    const adjustments: InventoryAdjustment[] = [{
       "locationCode": "WAREHOUSE-01",
       "items": [
          {
            "upc": "PANTS-BLK-32", //mandatory field
            "quantity": 10, //+ve adjustment as a result of cyclecount
            "safetyStock": 2 //increasing safety stock by 2
          },
          {
            "upc": "PANTS-BLK-33",
            "quantity": -2, //negative adjustment, found damaged product
            "safetyStock": 0 // no change in safety stock
          }
       ]
    }];

    console.log("Submitting inventory adjustment...");
    try {
        await inventoryApi.adjust({ inventoryAdjustment: adjustments });
        console.log("Success: Inventory adjustment completed.");
    } catch (error: any)
    {
        console.error("API Error:", JSON.stringify(error, null, 2));
    }
}

// adjustStockQuantity();
```

### Example 2: Set the Absolute Stock Quantity (Refresh)

Use this when you want to set the absolute stock level from a master system, overriding whatever value Kibo currently has. This is a "set" operation, not an "add/subtract".

* **API Docs:** [Refresh Inventory](/api-reference/modifyinventory/refresh)

<Info>
  For variable batch sizes, consider using the [Smart Adjust](/api-reference/modifyinventory/smart-adjust-inventory) and [Smart Refresh](/api-reference/modifyinventory/smart-refresh-inventory) APIs which automatically route requests to synchronous or asynchronous processing based on payload size. See the [Smart Inventory APIs guide](/pages/smart-inventory-apis) for more details.
</Info>

```ts theme={null}
// ... imports and configuration setup ...
import { InventoryApi } from "@kibocommerce/rest-sdk/clients/Inventory";
import { RefreshRequest } from "@kibocommerce/rest-sdk/models/Inventory";

async function refreshStockLevels() {
    const inventoryApi = new InventoryApi(configuration);

    // Prepare a refresh request. This will SET the onHand quantity to the specified value.
    const payload: RefreshRequest = {
        locationCode: "WAREHOUSE-01",
        items: [{
            partNumber: "PANTS-BLK-32",
            upc: "PANTS-BLK-32",
            sku: "PANTS-BLK-32",
            ltd: 0,
            floor: 0,
            quantity: 250, // Our ERP says we have exactly 250 units.
            safetyStock: 0, //Represents qty for balancing minimum qty at location
            condition: "", //Any particular tags used for inventory like damaged
            deliveryDate: "", //Date at which particular qty is expected, often used along with condition
            externalID: "", //Any reference number like purchase order 
        }]
    };
    
    console.log("Refreshing inventory from source of truth...");
    try {
        await inventoryApi.refresh({ refreshRequest: payload });
        console.log("Success: Inventory refresh completed.");
    } catch (error: any) {
        console.error("API Error:", JSON.stringify(error, null, 2));
    }
}

// refreshStockLevels();
```

### Example 3: Create an Automated Daily Inventory Export

This sets up a recurring job in Kibo to automatically generate an inventory report and upload it to an FTP/SFTP server.

<Tip>
  If you need to sync only recently changed inventory records to a downstream system on a frequent schedule (e.g., every 30 minutes), see the [Inventory Delta Export Feed](/pages/inventory-delta-export-feed) — a Kibo-managed export that delivers incremental CSV files without requiring API configuration.
</Tip>

* **API Docs:** [Create Export Settings](/api-reference/exportinventory/create-export-settings)

```ts theme={null}
// ... imports and configuration setup ...
import { ExportSettingsApi } from "@kibocommerce/rest-sdk/clients/Inventory";
import { ExportSettings } from "@kibocommerce/rest-sdk/models/Inventory";

async function createDailyExport() {
    // Note: We use the dedicated 'ExportSettingsApi' for this.
    const exportApi = new ExportSettingsApi(configuration);

    const exportConfig: ExportSettings = {
        exportSettings: {
        name: "Daily_ERP_Inventory_Sync", // Must be unique
        fileFormat: "CSV", //supported format are XML, CSV
        exportType: "AGGREGATE", //Type can be LOCATION, AGGREGATE
        ftpInformation: {
          name: "client ftp"
          ftpServer: "ftp.my-erp.com",
          ftpPort: "22",
          ftpUser: "kibo-ftp-user",
          ftpPassword: "SecurePassword123", // Use secrets management in production
          ftpDirectory: "/incoming/inventory/"
        }
        }
    };
    console.log(`Creating export settings: ${exportConfig.name}`);
    try {
        const newExport = await exportApi.createExportSettings({ exportSettings: exportConfig });
        console.log("Success: Created new export settings with name:", newExport.name);
        return newExport;
    } catch (error: any) {
        console.error("API Error:", JSON.stringify(error, null, 2));
    }
}

// createDailyExport();
```

### Example 4: Check the Status of Inventory Jobs

After an export runs (or you submit a large import), you can check the status of the background job.

* **API Docs:** [Get Jobs](/api-reference/inventoryjob/get-jobs)

```ts theme={null}
// ... imports and configuration setup ...
import { JobApi } from "@kibocommerce/rest-sdk/clients/Inventory";

async function checkRecentJobs() {
    // Note: We use the 'JobApi' for this operation.
    const jobApi = new JobApi(configuration);
    
    console.log("Fetching recent inventory jobs...");
    try {
        const jobCollection = await jobApi.getJobs({ pageSize: 5 }); // Get the 5 most recent
        
        console.log(`Success: Found ${jobCollection.totalCount} total jobs.`);
        jobCollection.items?.forEach(job => {
            console.log(`
  - Job ID: ${job.jobID}, Type: ${job.type}, Status: ${job.status}
            `);
        });
        return jobCollection;
    } catch (error: any) {
        console.error("API Error:", JSON.stringify(error, null, 2));
    }
}

// checkRecentJobs();
```

### Example 5: Configure an Automated Inventory Fetch Job

This tells Kibo to periodically check an SFTP server for a file, download it, and import it. This is the inverse of an export.

* **API Docs:** [Save Fetch File Config](/api-reference/inventoryfetchfileconfig/save-fetch-config)

```ts theme={null}
// ... imports and configuration setup ...
import { FetchFileConfigApi } from "@kibocommerce/rest-sdk/clients/Inventory";
import { FetchFileConfig } from "@kibocommerce/rest-sdk/models/Inventory";

async function setupInventoryImport() {
    const fetchApi = new FetchFileConfigApi(configuration);
    
    const fetchConfig: FetchFileConfig = {
        active: "true",
        ftpServer: "sftp.my-wms.com",
        ftpUsername: "kibo-sftp",
        ftpPassword: "123*",
        ftpPort: "22",
        // In a real scenario, you'd use SFTP private key authentication
        ftpRemotePath: "/outgoing/kibo-updates/*.csv",
        ftpRemotePathArchive: "/outgoing/kibo-updates/archive/",
        lockName: "inventory.lock",
        postProcessAction: "1", //1 - move to archive, 2 - delete, 0 - do nothing

    };

    console.log("Saving fetch file configuration...");
    try {
        const newConfig = await fetchApi.saveFetchFileConfig({ fetchFileConfig: fetchConfig });
        console.log("Success: Configuration saved.", newConfig);
        return newConfig;
    } catch (error: any) {
        console.error("API Error:", JSON.stringify(error, null, 2));
    }
}

// setupInventoryImport();
```

***

***

## Integrating Inventory with Other Kibo Domains

### Inventory + Orders Integration

This is the primary integration. When a customer places an order, Kibo's order management system automatically creates an inventory reservation for each item in the order against a specific location's stock. This `available` quantity is immediately reduced. When the order is fulfilled (shipped), the `onHand` quantity is then decremented. This ensures you never oversell a product.

### Inventory + Catalog Integration

The inventory level directly impacts how products are displayed on the storefront. You can configure your Kibo site theme to:

* Show "Out of Stock" badges.
* Hide the "Add to Cart" button.
* Display low stock warnings ("Only 3 left!").
  This is typically handled by checking the `available` count of a product returned from the Catalog APIs, which internally query the Inventory service.

***

***

## Troubleshooting Your Inventory Implementation

### Reading Kibo Error Messages

```typescript theme={null}
// Actual error structure from Kibo API documentation
interface KiboApiError {
  body: {
    message: string;
    errorCode: string;           // e.g., "ITEM_NOT_FOUND"
    correlationId: string;
    // For some errors, additional context is provided
    items?: Array<{
        name: string;
        errorCode: string;
        message: string;
    }>
  }
}
```

**Common Error Codes for Inventory:**

* `ITEM_NOT_FOUND`: The `partNumber` or `upc` you sent does not exist in the Kibo catalog.
* `LOCATION_NOT_FOUND`: The `locationCode` is invalid or not active.
* `VALIDATION_ERROR`: The request body is malformed. The `items` array in the error response will often pinpoint the exact field that is wrong.
* `JOB_ALREADY_EXISTS`: When creating an export setting, the `name` you provided is already in use.

### Common Development Issues

**Issue 1:** Inventory updates seem delayed or are not appearing.

* **Why it happens:** Large inventory updates via file import are processed asynchronously by Kibo's job system. It can take a few minutes for the job to be picked up and processed, especially in a busy environment.
* **How to fix it:** After submitting an import, use the `getJobs` endpoint to monitor the status of the job. Don't assume the update is instantaneous. Look for the job to reach a `COMPLETED` status.
* **API Reference:** [Get Jobs](/api-reference/inventoryjob/get-jobs)

**Issue 2:** What is the difference between `Adjust` and `Refresh`?

* **Why it happens:** This is a common point of confusion. Using the wrong one can lead to incorrect inventory levels.
* **How to fix it:**
  * Use **`Adjust`** for **incremental changes**. It's a `+` or `-` operation. Example: "Received 5 new units," or "Removed 1 damaged unit."
  * Use **`Refresh`** for **absolute changes**. It's a `set` operation. Example: "Our master system says there are exactly 100 units. Make Kibo match this number, regardless of what it was before."
* **How to avoid it:** For daily syncs from an ERP or master system, always use `Refresh`. For real-time updates from a WMS based on individual events (like receiving a shipment), use `Adjust`.

### Debugging Checklist

1. **Check Location Codes:** Are the `locationCode` strings you're sending an exact match for the codes set up in Kibo Admin?
2. **Check Product Identifiers:** Do the `partNumber` or `upc` values exist in the Master Catalog?
3. **Monitor Jobs:** For file-based imports/exports, are you checking the `JobApi` for the status? Look for `FAILED` jobs and inspect their details.
4. **Verify Payloads:** `console.log` your request body before sending it. Does it exactly match the schema shown in the API documentation?
5. **Check `available` vs. `onHand`:** Are you looking at the correct inventory field for your use case? (Storefronts use `available`, backend reports might use `onHand`).
6. **Review Cron Expressions:** For scheduled jobs, double-check your cron syntax. An invalid expression will prevent the job from ever running.
