Skip to main content

Kibo Shipments API Developer Guide

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:
// 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.
// 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.
StepTask Name / ActionEndpoint TypeRequired Body Fields
1. Accept ShipmentAccept ShipmentTask CompletionshipmentAccepted: true
2. Validate StockValidate Items In StockTask CompletionstockLevel: "IN_STOCK" or "PARTIAL_STOCK"
3. Print Packing SlipPrint Packing SlipTask CompletionEmpty {}
4. Add TrackingNone (Direct Call)Edit PackagetrackingNumbers
5. Prepare for ShipmentPrepare for ShipmentTask Completionback: false, canceled: false
6. Mark As FulfilledNone (Direct Call)PUT /fulfilledNone (Optional Manual Step)
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.
StepTask Name / ActionEndpoint TypeRequired Body Fields
1. Accept ShipmentAccept ShipmentTask CompletionshipmentAccepted: true
2. Print Pick ListPrint Pick ListTask CompletionEmpty {}
3. Validate StockValidate Items In StockTask CompletionstockLevel: "IN_STOCK" or "PARTIAL_STOCK"
4. Provide to CustomerCustomer PickupTask CompletioncustomerAccepted: true
5. Mark As FulfilledNone (Direct Call)PUT /fulfilledNone (Optional Manual Step)
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.
StepTask Name / ActionEndpoint TypeRequired Body Fields
1. Validate StockValidate Items In StockTask CompletionstockLevel: "IN_STOCK" or "PARTIAL_STOCK"
2. Print Packing SlipPrint Packing SlipTask CompletionEmpty {}
3. Add TrackingNone (Direct Call)Edit PackagetrackingNumbers
4. Prepare for ShipmentPrepare for ShipmentTask Completionback: false, canceled: false
5. Validate Incoming TransferValidate Incoming TransferTask CompletionstockLevel: "IN_STOCK" or "PARTIAL_STOCK"
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

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

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