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

# Shipments API

> Fulfillment shipment management and order dispatch workflows

# Kibo Shipments API Developer Guide

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

  <Card title="Hold Shipments" icon="book-open" horizontal href="/pages/hold-shipments" data-rec="developer-backlink">
    Manage shipment holds in the Admin UI
  </Card>

  <Card title="Pick Lists and Sheets" icon="book-open" horizontal href="/pages/pick-lists-and-sheets" data-rec="developer-backlink">
    Configure pick lists and sheets in the Admin UI
  </Card>

  <Card title="Shipment Attributes" icon="book-open" horizontal href="pages/schema-extensible-attribute" data-rec="developer-backlink">
    Set up shipment attributes in the Admin UI
  </Card>

  <Card title="Multi Piece Shipments" icon="book-open" horizontal href="/pages/multi-piece-shipments" data-rec="developer-backlink">
    Configure multi-piece shipments in the Admin UI
  </Card>
</CardGroup>

/

### Understanding Fulfillment (Shipments) in Kibo

In Kibo, a **Shipment** is the fundamental object in the fulfillment process. It's a concrete, actionable instruction for a specific location (like a warehouse or a retail store) to pick, pack, and dispatch a set of items from an order.

The key thing to understand is the separation of concerns:

* An **Order** is the customer's request—what they bought.
* **Order Routing** is the decision—*how* the order should be fulfilled.
* A **Shipment** is the action—the specific "to-do list" sent to a fulfillment location.

An order can be broken down into **multiple shipments**, each assigned to a different location. Managing the lifecycle of these individual shipments is the core of fulfillment in Kibo.

***

### How This Domain Fits Into Kibo

The Shipment is the workhorse of the post-purchase process. It's where the digital order becomes a physical reality.

* **Order Routing**: The output of the Order Routing engine is a "suggestion" that becomes the direct input for creating one or more shipments.
* **Inventory**: When a shipment is created, Kibo firms up the inventory reservation. When it's fulfilled, the `onHand` inventory at the assigned location is finally decremented.
* **Customer**: The customer is notified about the progress of their shipments, including tracking numbers which are stored on the shipment record.
* **Returns**: If a customer wants to return an item, the return is processed against the original shipment it came from.

***

### Prerequisites

* Kibo API credentials with Fulfillment permissions.
* An understanding of Kibo's **Order** and **Location** concepts.
* 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 **Shipment** data and its state-driven lifecycle (based on official API specs).
* The key "**Task-Based**" pattern Kibo uses for all shipment modifications.
* Common workflows like fulfilling and canceling shipments (with accurate, tested examples).
* How to avoid the most common beginner mistakes.
* How to read and navigate the official API documentation for Fulfillment.

***

***

## Kibo Shipment Fundamentals

### How Kibo Organizes Fulfillment Data

Kibo's Fulfillment data is built around a **state machine**, where a **Shipment** moves through various stages. The core objects are:

* **`Shipment`**: The main object representing a fulfillment task.
  * `shipmentNumber`: A unique, Kibo-assigned number identifying the shipment.
  * `orderId`: The order this shipment belongs to.
  * `locationCode`: The specific location responsible for fulfilling this shipment.
  * `workflowState`: The current stage of the shipment (e.g., `Ready`, `Fulfilled`, `Cancelled`). This is the most important status field.
  * `items`: An array of `ShipmentItem` objects detailing the products and quantities to be fulfilled.
* **`Pickup`**: For "Buy Online, Pick Up in Store" (BOPIS) shipments, a related `Pickup` object is created to manage the customer pickup process.
* **`Task`**: This is an *action* you send. To change a shipment's state (e.g., to fulfill it), you must **execute a named task** on it, like `"Fulfill"`. This is a key Kibo pattern.

### Key Kibo Patterns You'll See Everywhere

**Task-Based Workflow:** This is the most important pattern in fulfillment. **You cannot directly modify a shipment's state**. You must use the "Fulfill" task to move a shipment from `Ready` to `Fulfilled`. The request to execute a task looks like this:

```json theme={null}
// Actual request schema for the performShipmentTask endpoint
// POST /api/commerce/fulfillment/shipments/{shipmentNumber}/tasks
{
    "_embedded": {
        "tasks": [
            {
                "name": "Accept Shipment",
                "subject": "",
                "inputs": [
                    {
                        "name": "shipmentAccepted",
                        "type": "BOOLEAN"
                    }
                ],
                "active": false,
                "completed": true,
                "completedDate": "2022-01-18T15:10:30.908Z",
                "_links": {}
            },
            {
                "name": "Validate Items In Stock",
                "subject": "",
                "inputs": [
                    {
                        "name": "stockLevel",
                        "type": "STRING"
                    }
                ],
                "active": false,
                "completed": true,
                "completedDate": "2022-01-18T15:10:31.269Z",
                "_links": {}
            },
            {
                "name": "Print Packing Slip",
                "subject": "",
                "inputs": [
                    {
                        "name": "back",
                        "type": "BOOLEAN"
                    }
                ],
                "active": false,
                "completed": true,
                "completedDate": "2022-01-18T15:10:31.631Z",
                "_links": {}
            },
            {
                "name": "Prepare for Shipment",
                "subject": "",
                "inputs": [
                    {
                        "name": "canceled",
                        "type": "BOOLEAN"
                    },
                    {
                        "name": "back",
                        "type": "BOOLEAN"
                    }
                ],
                "active": false,
                "completed": true,
                "completedDate": "2023-05-30T19:24:25.104Z",
                "_links": {}
            }
        ]
    },
    "_links": {
        "self": {
            "href": "https://t31271.sandbox.mozu.com/api/commerce/shipments/123/tasks"
        },
        "shipment": {
            "href": "https://t31271.sandbox.mozu.com/api/commerce/shipments/123"
        }
    }
}
```

**Error Handling Approach:** If an API call fails, the SDK throws a structured error. A common error is a `VALIDATION_ERROR` if you try to execute a task that isn't valid in the shipment's current `workflowState`.

**API Documentation Reference:** Find complete specs under the "Fulfillment" section at: `/api-overviews/openapi_fulfillment_overview`

***

### Common Shipment Workflows

Kibo developers typically work with Shipments in these scenarios:

1. **Backend Integration**: A Warehouse Management System (WMS) uses the API to get new shipments, and then notifies Kibo as they are packed and shipped.
2. **In-Store Operations**: Building a simple tablet application for store associates to manage BOPIS orders, marking them ready for pickup and then as collected.
3. **Customer Service Tools**: A custom UI for support agents to cancel or reassign shipments when a customer calls with an issue.

***

***

## SDK Fulfillment Workflows

The following examples use the **Task-Based Pattern** to move shipments through their lifecycle, which is the correct and auditable way to manage shipment state in Kibo.

### SDK Setup

All examples rely on a base `Configuration` and `ShipmentApi` client instance.

```typescript theme={null}
// Essential imports for Fulfillment operations.
import { Configuration } from "@kibocommerce/rest-sdk";
import { ShipmentApi, PickupApi } from "@kibocommerce/rest-sdk/clients/Fulfillment";
import { Task, Pickup, PickupItem } from "@kibocommerce/rest-sdk/models/Fulfillment";

// 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,
});

const shipmentApi = new ShipmentApi(configuration);
```

***

### 1. Ship-to-Home (STH) Fulfillment Workflow

A standard STH fulfillment involves a series of tasks.

| Step                        | Task Name / Action        | Endpoint Type    | Required Body Fields                          |
| :-------------------------- | :------------------------ | :--------------- | :-------------------------------------------- |
| **1. Accept Shipment**      | `Accept Shipment`         | Task Completion  | `shipmentAccepted: true`                      |
| **2. Validate Stock**       | `Validate Items In Stock` | Task Completion  | `stockLevel: "IN_STOCK"` or `"PARTIAL_STOCK"` |
| **3. Print Packing Slip**   | `Print Packing Slip`      | Task Completion  | Empty `{}`                                    |
| **4. Add Tracking**         | *None* (Direct Call)      | Edit Package     | `trackingNumbers`                             |
| **5. Prepare for Shipment** | `Prepare for Shipment`    | Task Completion  | `back: false`, `canceled: false`              |
| **6. Mark As Fulfilled**    | *None* (Direct Call)      | PUT `/fulfilled` | None (Optional Manual Step)                   |

```typescript theme={null}
async function processShipToHome(shipmentNumber: number, trackingNumber: string) {
    console.log(`Processing STH for Shipment #${shipmentNumber}`);

    try {
        // Step 1: Accept Shipment
        let taskBodyAccept = { "taskBody": { "shipmentAccepted": true }, "handleOption": {} } as any; 
        await shipmentApi.execute({ shipmentNumber, taskName: 'Accept Shipment', taskCompleteDto: taskBodyAccept });
        console.log("   Step 1: Accepted.");

        // Step 2: Validate Stock (assuming IN_STOCK for success case)
        let taskBodyValidate = { "taskBody": { "stockLevel": "IN_STOCK" }, "handleOption": {} } as any;
        await shipmentApi.execute({ shipmentNumber, taskName: 'Validate Items In Stock', taskCompleteDto: taskBodyValidate });
        console.log("   Step 2: Stock validated (IN_STOCK).");

        // Step 3: Print Packing Slip
        let taskBodyPrint = {}; // Empty body
        await shipmentApi.execute({ shipmentNumber, taskName: 'Print Packing Slip', taskCompleteDto: taskBodyPrint });
        console.log("   Step 3: Pick List Printed.");

        // Step 5: Prepare for Shipment (Marks it as fulfilled)
        let taskBodyPrepare = { "taskBody": { "back": false, "canceled": false } } as any;
        await shipmentApi.execute({ shipmentNumber, taskName: 'Prepare for Shipment', taskCompleteDto: taskBodyPrepare });
        console.log("   Step 5: Prepared for Shipment (Now Fulfilled).");

        console.log("STH Fulfillment Complete.");
    } catch (error: any) {
        console.error("STH Fulfillment API Error:", JSON.stringify(error, null, 2));
    }
}
```

***

### 2. Buy Online, Pick Up in Store (BOPIS) Fulfillment Workflow

BOPIS fulfillment follows a flow for in-store pickup.

| Step                       | Task Name / Action        | Endpoint Type    | Required Body Fields                          |
| :------------------------- | :------------------------ | :--------------- | :-------------------------------------------- |
| **1. Accept Shipment**     | `Accept Shipment`         | Task Completion  | `shipmentAccepted: true`                      |
| **2. Print Pick List**     | `Print Pick List`         | Task Completion  | Empty `{}`                                    |
| **3. Validate Stock**      | `Validate Items In Stock` | Task Completion  | `stockLevel: "IN_STOCK"` or `"PARTIAL_STOCK"` |
| **4. Provide to Customer** | `Customer Pickup`         | Task Completion  | `customerAccepted: true`                      |
| **5. Mark As Fulfilled**   | *None* (Direct Call)      | PUT `/fulfilled` | None (Optional Manual Step)                   |

```typescript theme={null}
async function processBopisFulfillment(shipmentNumber: number) {
    console.log(`Processing BOPIS for Shipment #${shipmentNumber}`);

    try {
        // Step 1: Accept Shipment
        let taskBodyAccept = { "taskBody": { "shipmentAccepted": true }, "handleOption": {} } as any;
        await shipmentApi.execute({ shipmentNumber, taskName: 'Accept Shipment', taskCompleteDto: taskBodyAccept });
        console.log("   Step 1: Accepted.");

        // Step 2: Print Pick List
        let taskBodyPrint = {};
        await shipmentApi.execute({ shipmentNumber, taskName: 'Print Pick List', taskCompleteDto: taskBodyPrint });
        console.log("   Step 2: Pick List Printed.");

        // Step 3: Validate Stock
        let taskBodyValidate = { "taskBody": { "stockLevel": "IN_STOCK" }, "handleOption": {} } as any;
        await shipmentApi.execute({ shipmentNumber, taskName: 'Validate Items In Stock', taskCompleteDto: taskBodyValidate });
        console.log("   Step 3: Stock validated (IN_STOCK).");

        // Step 4: Provide to Customer (Customer Pickup task)
        let taskBodyPickup = { "taskBody": { "customerAccepted": true } } as any;
        await shipmentApi.execute({ shipmentNumber, taskName: 'Customer Pickup', taskCompleteDto: taskBodyPickup });
        console.log("   Step 4: Provided to Customer. Shipment should now be Fulfilled.");

        console.log("BOPIS Fulfillment Complete.");
    } catch (error: any) {
        console.error("BOPIS Fulfillment API Error:", JSON.stringify(error, null, 2));
    }
}
```

***

### 3. Transfer Fulfillment Workflow

Transfer shipments move inventory between locations to fulfill an order.

| Step                              | Task Name / Action           | Endpoint Type   | Required Body Fields                          |
| :-------------------------------- | :--------------------------- | :-------------- | :-------------------------------------------- |
| **1. Validate Stock**             | `Validate Items In Stock`    | Task Completion | `stockLevel: "IN_STOCK"` or `"PARTIAL_STOCK"` |
| **2. Print Packing Slip**         | `Print Packing Slip`         | Task Completion | Empty `{}`                                    |
| **3. Add Tracking**               | *None* (Direct Call)         | Edit Package    | `trackingNumbers`                             |
| **4. Prepare for Shipment**       | `Prepare for Shipment`       | Task Completion | `back: false`, `canceled: false`              |
| **5. Validate Incoming Transfer** | `Validate Incoming Transfer` | Task Completion | `stockLevel: "IN_STOCK"` or `"PARTIAL_STOCK"` |

```typescript theme={null}
async function processTransferFulfillment(shipmentNumber: number) {
    console.log(`Processing Transfer for Shipment #${shipmentNumber}`);

    try {
        // Step 1: Validate Stock at Origin Location
        let taskBodyValidateOrigin = { "taskBody": { "stockLevel": "IN_STOCK" }, "handleOption": {} } as any;
        await shipmentApi.execute({ shipmentNumber, taskName: 'Validate Items In Stock', taskCompleteDto: taskBodyValidateOrigin });
        console.log("   Step 1: Origin Stock validated (IN_STOCK).");

        // Step 2: Print Packing Slip
        let taskBodyPrint = {};
        await shipmentApi.execute({ shipmentNumber, taskName: 'Print Packing Slip', taskCompleteDto: taskBodyPrint });
        console.log("   Step 2: Pick List Printed.");

        // Step 4: Prepare for Shipment (Marks it as Fulfilled/In Transit)
        let taskBodyPrepare = { "taskBody": { "back": false, "canceled": false } } as any;
        await shipmentApi.execute({ shipmentNumber, taskName: 'Prepare for Shipment', taskCompleteDto: taskBodyPrepare });
        console.log("   Step 4: Prepared for Shipment (In Transit).");

        // Step 5: Validate Incoming Transfer at Destination Location
        let taskBodyValidateIncoming = { "taskBody": { "stockLevel": "IN_STOCK" } } as any;
        await shipmentApi.execute({ shipmentNumber, taskName: 'Validate Incoming Transfer', taskCompleteDto: taskBodyValidateIncoming });
        console.log("   Step 5: Incoming Transfer validated (IN_STOCK).");

        console.log("Transfer Fulfillment Complete.");
    } catch (error: any) {
        console.error("Transfer Fulfillment API Error:", JSON.stringify(error, null, 2));
    }
}
```

***

### Additional Common Operations (Task-Based)

These examples align with Kibo's use of either the `execute` task method or direct API actions for state changes.

#### Example 1: Get a Shipment's Details

```typescript theme={null}
async function getShipmentDetails(shipmentNumber: number) {
    console.log(`Fetching details for Shipment #${shipmentNumber}`);

    try {
        const shipment = await shipmentApi.getShipment({ shipmentNumber: shipmentNumber });
        console.log("Success: Found shipment.");
        console.log("   Current State:", shipment.workflowState);
        console.log("   Fulfillment Location:", shipment.locationCode);
        return shipment;
    } catch (error: any) {
        console.error("API Error:", JSON.stringify(error, null, 2));
    }
}
```

#### Example 2: Reassign a Shipment

Reassigning a shipment is a direct action to transfer the fulfillment responsibility.

```typescript theme={null}
async function reassignShipment(shipmentNumber: number, newLocationCode: string) {
    console.log(`Reassigning Shipment #${shipmentNumber} to ${newLocationCode}`);

    try {
        // This is a direct action call
        const reassignResult = await shipmentApi.reassignShipment({
            shipmentNumber: shipmentNumber,
            reassignShipmentRequestDto: {
              fulfillmentLocationCode: newLocationCode
            }
        });
        const newShipmentNumber = reassignResult.childShipmentNumbers?.[0] || 'N/A';
        console.log(`Success: Original shipment reassigned. New shipment created: ${newShipmentNumber}`);
    } catch (error: any) {
        console.error("API Error:", JSON.stringify(error, null, 2));
    }
}
```

#### Example 3: Cancel an Item from a Shipment

Canceling items uses a specific direct API call (`/canceledItems`).

```typescript theme={null}
async function cancelItemFromShipment(shipmentNumber: number, lineIdToCancel: number, quantityToCancel: number) {
    console.log(`Canceling ${quantityToCancel} item(s) from Shipment #${shipmentNumber}`);

    try {
        // Using the SDK's direct method for canceled items (PUT /commerce/shipments/{shipmentNumber}/canceledItems)
        const canceledShipment = await shipmentApi.cancelItems({ 
            shipmentNumber: shipmentNumber, 
            canceledItemsDto: {
                items: [
                    {
                        lineId: lineIdToCancel,
                        quantity: quantityToCancel,
                        reason: { reasonCode: "Customer request" }
                    },
                ],
            }
        });
        console.log("Success: The item(s) have been canceled from the shipment. New state:", canceledShipment.workflowState);
    } catch (error: any) {
        console.error("API Error:", JSON.stringify(error, null, 2));
    }
}
```

***

***

## Troubleshooting Your Fulfillment Implementation

### Reading Kibo Error Messages

```typescript theme={null}
// Actual error structure from Kibo API documentation
interface KiboApiError {
  body: {
    message: string;
    errorCode: string;           // e.g., "VALIDATION_ERROR"
    correlationId: string;
  }
}
```

**Common Error Codes for Shipments:**

* `ITEM_NOT_FOUND`: The `shipmentNumber` or `orderId` you provided does not exist.
* `VALIDATION_ERROR`: This means you tried to do something that violates the shipment's current state.
  * Example: Trying to execute the `Fulfill` task on a shipment not in the `Ready` state.
* `TASK_NOT_FOUND`: The `name` provided in your `Task` object is not a valid task (e.g., misspelled).

### Common Development Issues

**Issue 1:** My shipment is "stuck" and I can't update it.

* **Why it happens:** The shipment object is largely read-only; its state is controlled by the **task-based workflow**. Developers mistakenly try to `PUT` an update to the shipment object to change its status.
* **How to fix it:** You must use the `performShipmentTask` (or `execute`) endpoint for all state changes. Before trying to change a shipment, ask "What *task* do I need to execute?"

**Issue 2:** The order status is still "Awaiting Shipment" even after I fulfilled one of its shipments.

* **Why it happens:** An order's status is an aggregate of all its shipments. The order will not move to a `Completed` status until **all** of its constituent shipments have been fulfilled (or canceled).
* **How to fix it:** Ensure your fulfillment process handles all shipments associated with the order.

***
