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

# Location Admin API

> Managing fulfillment locations, capabilities, and operational settings

# Kibo Location (Admin) API Developer Guide

<CardGroup cols={2}>
  <Card title="Fulfillment" icon="book-open" href="/concept-guides/fulfillment" horizontal data-rec="developer-backlink">
    Understand how locations fit into fulfillment
  </Card>

  <Card title="Location Types" icon="book-open" href="/pages/location-types" horizontal data-rec="developer-backlink">
    Configure location types in the Admin UI
  </Card>
</CardGroup>

## Understanding Locations in Kibo

In Kibo, a **Location** is far more than just a physical address. It's a fundamental operational entity that represents any place where inventory is stored, from which orders can be fulfilled, or where customers can pick up purchases. This could be a massive warehouse, a retail store, a third-party drop-shipper, or even a virtual holding location.

What makes Kibo's approach different is that each Location is defined by its **capabilities**. You explicitly declare what a location can *do* using `fulfillmentTypes` (e.g., `DirectShip`, `InStorePickup`) and what it *is* using `locationTypes` (e.g., `Warehouse`, `Store`). This rich data model allows Kibo's advanced order routing and fulfillment logic to make intelligent decisions about how to process customer orders efficiently.

## How This Domain Fits Into Kibo

The Location domain is the foundation of Kibo's omnichannel commerce capabilities. It is linked to several other core domains:

* **Inventory:** Inventory levels are not stored globally; they are tracked *per Location*. To know if a product is in stock, you must ask, "How many are in stock at the Austin warehouse?"
* **Fulfillment & Orders:** When an order is placed, Kibo's fulfillment engine consults the list of Locations. It checks their inventory and their `fulfillmentTypes` to determine the optimal location(s) from which to source the order's shipments.
* **Returns:** Locations can be designated as places where customers can return items purchased online.

## 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 Location data, including its types and fulfillment capabilities (based on official API specs).
* The key patterns for creating, updating, and managing your physical and virtual locations (verified from apidocs.kibocommerce.com).
* Common workflows like onboarding a new warehouse or managing holiday shipping exceptions.
* How to avoid the most common beginner mistakes, like performing a partial update incorrectly.
* How to read and navigate the official Location Administration API documentation effectively.

***

## Kibo Location Fundamentals

### How Kibo Organizes Location Data

The system revolves around a few core data structures:

* **`Location`**: The central object. It is uniquely identified by a `code` (a user-defined string like `DAL-WAREHOUSE-01`). It contains properties like `name`, `address`, `phone`, and, most importantly, arrays defining its capabilities:
  * **`fulfillmentTypes`**: An array of strings defining what the location can do. Key values verified from API docs include `DirectShip` (ship-to-home) and `InStorePickup` (BOPIS).
  * **`locationTypes`**: An array of strings defining what the location is. Key values include `Store`, `Warehouse`, and `DropShipper`.
* **`CutoffTimeOverride`**: A subordinate object linked to a `Location`. It allows you to define exceptions to the location's standard shipping cutoff times, which is essential for managing holidays or special events. It is identified by its own unique `code`.

### 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 passed to the constructor of specific API clients (e.g., `new LocationAdminApi(configuration)`). The clients will automatically handle the OAuth 2.0 token exchange behind the scenes for every API call.

**Request/Response Structure:**
When you request a collection of locations, Kibo's API provides a consistent, paginated response. The actual data is always inside the `items` array.

```json theme={null}
// Actual response schema for GET /commerce/admin/locations
{
  "startIndex": 0,
  "pageSize": 20,
  "pageCount": 2,
  "totalCount": 35,
  "items": [
    {
      "code": "AUS-01",
      "name": "Austin Downtown Store",
      "isActive": true,
      "fulfillmentTypes": [
        "DirectShip",
        "InStorePickup"
      ],
      "locationTypes": [
        "Store"
      ]
    }
  ]
}
```

**Error Handling Approach:**
If an API call fails, the SDK will throw a structured error object. This helps you programmatically handle failures instead of just getting a generic HTTP status code.

```json theme={null}
// Actual error schema from Kibo
{
    "message": "Location with code 'AUS-01' already exists.",
    "errorCode": "LOCATION_ALREADY_EXISTS",
    "correlationId": "e0b5b9b012345abcdeffe0b5b9b012345abcdef"
}
```

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

### Common Location Workflows

Kibo developers typically work with Locations in these scenarios:

1. **Onboarding a New Fulfillment Center:** Creating a new warehouse location and defining its shipping capabilities.
2. **Synchronizing Store Information:** Running a scheduled job to update details like phone numbers or addresses for a network of retail stores from an external system of record.
3. **Managing Holiday Operations:** Adding temporary overrides to shipping cutoff times for the peak holiday season to manage customer expectations.

Let's explore each pattern step by step.

***

## Add a New Location: The Kibo Way

### When You Need This

This is the foundational step for expanding your fulfillment network. You need this whenever you open a new retail store, partner with a new warehouse, or enable a new drop-shipper.

### API Documentation Reference

**Endpoint:** `POST /commerce/admin/locations`
**Method:** `POST`
**API Docs:** [Add Location](/api-reference/locationadmin/add-location)

### Understanding the Kibo Approach

Kibo treats the `code` of a location as its permanent, unique business key. You define it once during creation, and it cannot be changed. This `code` is used throughout the platform to reference this location in inventory, fulfillment, and reporting APIs. The creation process requires you to be explicit about the location's capabilities (`fulfillmentTypes`), ensuring it's immediately ready to be integrated into the order processing workflow.

### 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 Location Administration API.
// 3. **Data Preparation**: Construct the full request body object for the new Location according to the API schema.
// 4. **API Call**: Use the instantiated client to call the `addLocation` method.
```

#### Step-by-Step Implementation

**Step 1: Setting Up the Foundation**

```ts theme={null}
// Essential imports for Location operations.
// The SDK is organized by API groups; 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 { LocationAdminApi } from "@kibocommerce/rest-sdk/clients/LocationAdmin";
import { Location } from "@kibocommerce/rest-sdk/clients/LocationAdmin/models";

// 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: Understanding the Data Flow**
Our application will send a complete `Location` JSON object to the Kibo API. The API validates that the `code` is unique and the payload is correctly structured. If successful, it creates the location and returns the full `Location` object, including any server-generated values.

**Step 3: The Core Implementation**

```ts theme={null}
// Complete working example that ACTUALLY WORKS with the Kibo API
// This function adds a new retail store that can also ship orders.

async function addNewRetailStore(storeDetails: Location): Promise<Location> {
    console.log(`Adding new location with code: ${storeDetails.code}...`);

    // 1. Instantiate a dedicated client for the Location Administration API.
    const locationAdminClient = new LocationAdminApi(configuration);

    // 2. The storeDetails object is our request payload.
    //    It must match the schema defined in the Kibo API documentation.

    // 3. Call the method on the client. The method name `addLocation` corresponds to the API operation.
    try {
        const newLocation = await locationAdminClient.addLocation({
            location: storeDetails,
        });
        console.log(`Success! Location "${newLocation.name}" created.`);
        return newLocation;
    } catch (error) {
        // Handle common errors, like the location code already existing.
        console.error("API Error adding location:", JSON.stringify(error, null, 2));
        throw error;
    }
}

// Example usage:
// const newStorePayload: Location = {
//     code: "ATX-Lamar",
//     name: "Austin South Lamar Store",
//     description: "Our newest retail location in Austin.",
//     isActive: true,
//     fulfillmentTypes: [
//         { code: "DS", name: "Direct Ship" }, // Verified from API schema, this is an object
//         { code: "SP", name: "In Store Pickup" }
//     ],
//     locationTypes: [{ code: "ST", name: "Store" }],
//     address: {
//         address1: "123 S Lamar Blvd",
//         cityOrTown: "Austin",
//         stateOrProvince: "TX",
//         postalOrZipCode: "78704",
//         countryCode: "US"
//     },
//     phone: "512-555-1234"
// };
// addNewRetailStore(newStorePayload);
```

### What Just Happened? (Code Explanation)

* The **setup phase** created the standard `Configuration` object for authentication.
* The **API call** was made using an instance of `LocationAdminApi`. This client provides type-safe methods for all location management operations.
* The **payload** we prepared was a complete `Location` object. We explicitly defined its unique `code` and its `fulfillmentTypes`, making it immediately available to Kibo's fulfillment engine.
* The **response** was the newly created `Location` object, confirming its creation.

### Common Beginner Mistakes

**Mistake 1:** Trying to update a location's `code`.
The `code` is immutable. Once a location is created with `code: "STORE-A"`, you cannot change it. To "rename" it, you would need to deactivate the old location and create a new one.

**Mistake 2:** Using `PUT` for a partial update and accidentally deleting data.
The `updateLocation` endpoint (`PUT`) performs a **full replacement** of the object. If you only send `{ "phone": "new-number" }`, you will wipe out the address, fulfillment types, and everything else. The correct pattern is to `GET` the location, modify the object, then `PUT` the entire modified object back.

***

## Advanced Patterns & Multiple Examples

### Pattern 1: Idempotent Location Synchronization

**Business Scenario:** You need a script that runs daily to sync location data from an external "source of truth" into Kibo. The script must correctly create new locations and update existing ones without creating duplicates.

**Kibo's Architecture Consideration:** The API does not have a single "upsert" endpoint. The correct, idempotent pattern is to first try to `GET` the location by its unique code. If you get a `404 Not Found` error, you know it doesn't exist and you should call `POST` to create it. If the `GET` call succeeds, you know it exists and you should call `PUT` to update it.

**API Endpoints Used:**

* `GET /commerce/admin/locations/{locationCode}`
* `PUT /commerce/admin/locations/{locationCode}`
* `POST /commerce/admin/locations`

**Implementation Strategy (Example 1: The Sync Function):**

```typescript theme={null}
// Advanced example: A function to synchronize a single location's data.
async function syncLocation(locationData: Location) {
    const locationAdminClient = new LocationAdminApi(configuration);
    const locationCode = locationData.code as string;

    try {
        // 1. Try to GET the location first.
        const existingLocation = await locationAdminClient.getLocation({ locationCode });
        console.log(`Location ${locationCode} exists. Updating...`);

        // 2. If it exists, PUT the new data.
        // Important: We send the full locationData object to replace the existing one.
        await locationAdminClient.updateLocation({ locationCode, location: locationData });
        console.log(`Location ${locationCode} updated successfully.`);

    } catch (error: any) {
        // 3. If GET fails with a 404, we know we need to create it.
        if (error.status === 404) {
            console.log(`Location ${locationCode} does not exist. Creating...`);
            await locationAdminClient.addLocation({ location: locationData });
            console.log(`Location ${locationCode} created successfully.`);
        } else {
            // Re-throw any other unexpected errors.
            console.error(`An unexpected error occurred for location ${locationCode}:`, error);
            throw error;
        }
    }
}
```

### Example 2: Get a Specific Location

```ts theme={null}
// A simple function to retrieve a single location by its code.
async function getLocationByCode(locationCode: string): Promise<Location | null> {
    const locationAdminClient = new LocationAdminApi(configuration);
    try {
        console.log(`Fetching details for location: ${locationCode}`);
        const location = await locationAdminClient.getLocation({ locationCode });
        console.log("Found location:", location.name);
        return location;
    } catch (error: any) {
        if (error.status === 404) {
            console.log(`Location with code ${locationCode} not found.`);
            return null;
        }
        throw error;
    }
}
```

### Example 3: Add a Holiday Cutoff Time Override

```ts theme={null}
// Adds a special shipping cutoff time for a specific date.
async function addHolidayCutoff(id: string,locationCode: string, date: string, startTime: string, endTime:string) {
    const locationAdminClient = new LocationAdminApi(configuration);
    console.log(`Adding cutoff override for ${date} at ${locationCode}`);
    try {
        await locationAdminClient.createCutoffTimeOverride({
            cutoffTimeOverride: {
                id: id,
                locationCode,
                date, // Format: "YYYY-MM-DD"
                startTime: startTime, // Format: "HH:MM:SS"
                endTime: endTime, // Format: "HH:MM:SS"
            }
        });
        console.log("Cutoff override added successfully.");
    } catch (error) {
        console.error("Failed to add cutoff override:", JSON.stringify(error, null, 2));
        throw error;
    }
}
// Usage: addHolidayCutoff("override-1","ATX-Lamar", "2025-12-23", "14:00:00", "XMAS-EVE-2025");
```

### Example 4: Get All Cutoff Overrides for a Location

```ts theme={null}
// Retrieves all configured shipping cutoff exceptions for a location.
async function listCutoffOverrides(locationCode: string) {
    const locationAdminClient = new LocationAdminApi(configuration);
    try {
        const overrides = await locationAdminClient.getCutoffTimeOverrides({ locationCode });
        console.log(`Found ${overrides.items?.length} cutoff overrides for ${locationCode}:`, overrides);
        return overrides;
    } catch (error) {
        console.error("Failed to get cutoff overrides:", JSON.stringify(error, null, 2));
        throw error;
    }
}
```

### Example 5: Delete a Cutoff Time Override

```ts theme={null}
// Removes a specific shipping cutoff exception.
async function deleteCutoffOverride(locationCode: string, overrideId: string) {
    const locationAdminClient = new LocationAdminApi(configuration);
    console.log(`Deleting override ${overrideId} from location ${locationCode}`);
    try {
        // This call returns a 204 No Content on success.
        await locationAdminClient.deleteCutoffTimeOverride({ overrideId});
        console.log("Override deleted successfully.");
    } catch (error) {
        console.error("Failed to delete cutoff override:", JSON.stringify(error, null, 2));
        throw error;
    }
}
```

***

## Integrating Location with Other Kibo Domains

### Location + Inventory Integration

Inventory is always location-specific. You cannot ask Kibo for a product's overall stock level. You must ask for its stock level at a particular location. Any API call to update or retrieve inventory will require a `locationCode`. This direct link is what enables features like ship-from-store and in-store pickup.

### Location + Fulfillment Integration

The fulfillment process is a direct consumer of Location data. When an order needs to be shipped, the fulfillment engine queries for active locations with the `DirectShip` fulfillment type and available inventory for the ordered items. The location's address is used to calculate shipping rates, and its cutoff times determine the expected ship date.

***

## Troubleshooting Your Location Implementation

### Reading Kibo Error Messages

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

**Common Error Codes for Location:**

* `LOCATION_ALREADY_EXISTS`: You tried to call `addLocation` with a `code` that is already in use.
* `LOCATION_NOT_FOUND`: The `locationCode` you provided in a URL (e.g., for `getLocation` or `updateLocation`) does not exist.
* `VALIDATION_ERROR`: The request body is malformed. A common cause is providing an invalid `countryCode` or malformed `fulfillmentTypes` object.

### Common Development Issues

**Issue 1:** My location was created, but it never gets assigned any shipments.

* **Why it happens:** This is almost always because the `fulfillmentTypes` array is either empty or does not contain the necessary capability, like `DirectShip`. If a location cannot ship orders, the fulfillment engine will ignore it.
* **How to fix it:** `GET` the location, add the correct fulfillment type object(s) to the array (e.g., `{ code: "DS", name: "Direct Ship" }`), and then `PUT` the entire updated location object back.
* **API Reference:** [`/api-reference/locationadmin/update-location`](/api-reference/locationadmin/update-location)

**Issue 2:** I tried to update a location's name, and now its address and phone number are gone.

* **Why it happens:** The `PUT /commerce/admin/locations/{locationCode}` endpoint performs a **complete replacement** of the location object. If your request body only contains `{"name": "New Name"}`, you are telling Kibo to replace the entire existing object with that, effectively deleting all other fields.
* **How to fix it:** This is a standard REST pattern. You **must always** `GET` the full location object first, modify the properties you want to change on that object in your code, and then `PUT` the entire modified object back in the request body. See the `syncLocation` advanced example for the correct implementation.
