> ## Documentation Index
> Fetch the complete documentation index at: https://docs.shipstream.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Inventory

ShipStream tracks each merchant's inventory at all times using the following statuses:

* **Expected** - Listed on open ASNs, RMAs and Other Deliveries that have not yet been received.
* **Processed** - Counted on an ASN, RMA or Other Delivery but not yet put-away.
* **Put-Away** - Has been received on an ASN, RMA or Other Delivery that has not yet been committed to the inventory. If you have auto-commit enabled this should always be 0.
* **Available** - Available for new orders. Backordered amounts are not reflected as a negative Available amount but are tracked separately as "Backordered".
* **Allocated** - Allocated to existing orders but not yet Reserved.
* **Reserved** - Reserved to a specific shelf location and waiting to be picked.
* **Picked** - Picked from the shelves but not yet shipped.
* **Backordered** - Reserved by existing orders but not in stock. Will be automatically converted to Reserved when stock is added. Backordered quantities are not reflected in the Available amount as a negative number.
* **Advertised** - The "Available" quantity plus the virtual BOM quantity. The virtual BOM quantity is controlled by a product's "Virtual Inventory" attribute.
* **Held** - On hand but placed on hold (quarantined, damaged, expired, recalled, etc.). Held inventory remains counted in the on-hand total but is excluded from the Available quantity and cannot be allocated, picked, or packed until the hold is released. See [inventory.holdReasons](#inventory-holdreasons) for the reasons visible to a merchant and [inventory.holdSearch](#inventory-holdsearch) to list individual holds.

Additionally, products have two flags that can be set which will affect whether or not they are retrieved in an inventory request.

* **Status** - Enabled/Disabled - If "Disabled", the product is effectively deleted and will not appear in responses to inventory requests.
* **Visibility** - Visible/Not Visible - If "Not Visible", the product will not appear in the inventory list but may still be ordered via the Merchant Panel.

## Methods

* [inventory.list](#inventory-list)
* [inventory.lots](#inventory-lots)
* [inventory.detailed](#inventory-detailed)
* [inventory.detailed\_packaging](#inventory-detailed-packaging)
* [inventory.holdSearch](#inventory-holdsearch)
* [inventory.holdReasons](#inventory-holdreasons)

***

## Entity Properties

* [Inventory Item](#inventory-item)
* [Inventory Lot](#lot-properties)
* [Inventory Hold](#inventory-hold-properties)
* [Hold Reason](#hold-reason-properties)

***

## `inventory.list`

`inventory.list (string|array|null $skus, int|null $warehouseId, string|null $updatedSince, bool $withHeldBreakdown = false)`

Get inventory levels for one or more products by SKU. If a warehouse is not specified the sum of all warehouse inventories will be returned, otherwise the inventory levels for the specified warehouse will be returned.

Each item includes a `qty_held` quantity. When `withHeldBreakdown` is `true`, each item also includes a `qty_held_by_reason` object that breaks the held quantity down by [hold reason](#inventory-holdreasons).

### Parameters

<ParamField path="skus" type="string | array | null">
  SKUs. If not specified then inventory for all SKUs will be returned.

  * `string` - Get inventory for a single product by SKU.
  * `array` - Get inventory for the specified products by SKU.
  * `null` - Get inventory for all products.
</ParamField>

<ParamField path="warehouseId" type="integer | null">
  Warehouse. If not specified, returned values represent sums of all warehouses.
</ParamField>

<ParamField path="updatedSince" type="string | null">
  Return only SKUs updated since the time specified in the format `2008-07-01T22:38:07+00:00`.
</ParamField>

<ParamField path="withHeldBreakdown" type="boolean" default="false">
  When `true`, each item is augmented with a `qty_held_by_reason` object keyed by parent (system) [hold reason](#inventory-holdreasons) code. Defaults to `false`, which preserves the legacy response shape and avoids the additional per-call rollup query.
</ParamField>

### Return Value

An array of [Inventory Items](#inventory-item) or an empty array if there were no matching SKUs.

### Example Request

Get inventory for two SKUs:

```json title="Request" theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "method" : "call",
    "params" : [
        "be1c13ed4e03f0ed7f1e4053dfff9658",
        "inventory.list",
        [
            ["BlueWidget-1","BlueWidget-5"]
        ]
    ]
}
```

Get all inventory:

```json title="Request" theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "method" : "call",
    "params" : [
        "be1c13ed4e03f0ed7f1e4053dfff9658",
        "inventory.list"
    ]
}
```

Get all inventory for warehouse "2":

```json title="Request" theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "method" : "call",
    "params" : [
        "be1c13ed4e03f0ed7f1e4053dfff9658",
        "inventory.list",
        [
            null,
            2
        ]
    ]
}
```

### Example Response

```json title="Response" theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "result" : [
        {
            "sku" : "BlueWidget-1",
            "qty_expected"    : "0.0000",
            "qty_processed"   : "0.0000",
            "qty_putaway"     : "50.0000",
            "qty_available"   : "22.0000",
            "qty_allocated"   : "5.0000",
            "qty_reserved"    : "16.0000",
            "qty_picked"      : "1.0000",
            "qty_held"        : "4.0000",
            "qty_backordered" : "0.0000",
            "qty_advertised"  : "22.0000",
            "qty_on_hand"     : "94.0000"
        },
        {
            "sku" : "BlueWidget-5",
            "qty_expected"    : "40.0000",
            "qty_processed"   : "0.0000",
            "qty_putaway"     : "0.0000",
            "qty_available"   : "0.0000",
            "qty_allocated"   : "0.0000",
            "qty_reserved"    : "2.0000",
            "qty_picked"      : "0.0000",
            "qty_held"        : "0.0000",
            "qty_backordered" : "5.0000",
            "qty_advertised"  : "0.0000",
            "qty_on_hand"     : "2.0000"
        }
    ]
}
```

## `inventory.lots`

`inventory.lots (null|object $filters, array $options = [])`

Retrieve list of lots by filters.

### Parameters

<ParamField path="filters" type="null | object">
  Filters to apply for the search.

  * `null` - Retrieve list of all orders.
  * `object` - Retrieve list of orders using specified "[Search Filters](/merchant-api/search-filters)".
</ParamField>

<ParamField path="options" type="null | object">
  Options to apply for the search.

  * `null` - No options will be applied.
  * `object` - Apply specified "[Search Options](/merchant-api/search-options)".
</ParamField>

### Return Value

An array of objects. Each object will contain [Lot Properties](#lot-properties).

### Example Request

```json theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "method" : "call",
    "params" : [
        "be1c13ed4e03f0ed7f1e4053dfff9658",
        "inventory.lots",
        [
            {
                "lot_id" : {
                    "in" : [1, 2]
                }
            },
            []
        ]
    ]
}
```

### Example Response

```json theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "result" : {
       "results": [
           {
               "lot_id": "1",
               "lot_number": "2018-07-09",
               "origination_date": "2018-07-09",
               "expiration_date": "2019-04-07",
               "is_active": "1",
               "group_value": "2018-07-09",
               "created_at": "2018-07-09T19:58:23+00:00",
               "sku": "product1",
               "name": "product 1",
               "locations": [
                   "location 1"
               ],
               "qty_putaway": "0.0000",
               "qty_available": "66.0000",
               "qty_reserved": "0.0000",
               "qty_held": "10.0000",
               "is_on_hold": true
           },
           {
               "lot_id": "2",
               "lot_number": "2018-07-09",
               "origination_date": "2018-07-09",
               "expiration_date": "2019-04-11",
               "is_active": "1",
               "group_value": "2018-07-09",
               "created_at": "2018-07-09T19:59:03+00:00",
               "sku": "product2",
               "name": "product 2",
               "locations": [],
               "qty_putaway": "0.0000",
               "qty_available": "0.0000",
               "qty_reserved": "0.0000",
               "qty_held": "0.0000",
               "is_on_hold": false
           }
       ],
       "totalCount": 2,
       "numPages": 1
   }
}
```

### Error Codes

| code | message                            |
| ---- | ---------------------------------- |
| 102  | Unexpected error applying filters. |

## `inventory.detailed`

`inventory.detailed (string|array|null $skus, string|null $updatedSince, bool $withHeldBreakdown = false)`

Get global and per-warehouse inventory levels for one or more products by SKU.

Each item — and each per-warehouse `detailed` entry — includes a `qty_held` quantity. When `withHeldBreakdown` is `true`, each item is additionally augmented with a `qty_held_by_reason` object (held quantity grouped by parent [hold reason](#inventory-holdreasons) code) and, when user-defined sub-reasons exist, a `qty_held_by_user_reason` object that breaks each parent reason down by its user-defined child reasons. Both rollups are reported at the item level only, not per warehouse.

### Parameters

<ParamField path="skus" type="string | array | null">
  SKUs. If not specified then inventory for all SKUs will be returned.

  * `string` - Get inventory for a single product by SKU.
  * `array` - Get inventory for the specified products by SKU.
  * `null` - Get inventory for all products.
</ParamField>

<ParamField path="updatedSince" type="string | null">
  Return only SKUs updated since the time specified in the format `2008-07-01T22:38:07+00:00`.
</ParamField>

<ParamField path="withHeldBreakdown" type="boolean" default="false">
  When `true`, each item is augmented with a `qty_held_by_reason` object and, where applicable, a `qty_held_by_user_reason` object. Defaults to `false`, which preserves the legacy response shape and avoids the additional hold rollup queries.
</ParamField>

### Return Value

An array of detailed items inventory, or an empty array if there were no matching SKUs.

### Example Request

```json theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "method" : "call",
    "params" : [
        "be1c13ed4e03f0ed7f1e4053dfff9658",
        "inventory.detailed",
        [
            ["BlueWidget-1","BlueWidget-5"],
            "2014-07-24T18:51:18+00:00",
            true
        ]
    ]
}
```

### Example Response

The example below was requested with `withHeldBreakdown` set to `true`, so each item includes the `qty_held_by_reason` (and, where user-defined sub-reasons exist, `qty_held_by_user_reason`) rollups. With the default `false`, those two fields are omitted but `qty_held` is still present on every item and warehouse entry.

```json theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "result" : [
        {
            "sku": "BlueWidget-1",
            "qty_expected": "0.0000",
            "qty_processed": "0.0000",
            "qty_putaway": "0.0000",
            "qty_available": "5.0000",
            "qty_allocated": "0.0000",
            "qty_reserved": "0.0000",
            "qty_picked": "2.0000",
            "qty_held": "3.0000",
            "qty_backordered": "0.0000",
            "qty_advertised": "5.0000",
            "qty_on_hand": "10.0000",
            "qty_held_by_reason": {
                "damaged": "2.0000",
                "qc_inspection": "1.0000"
            },
            "qty_held_by_user_reason": {
                "qc_inspection": {
                    "qc_lab_review": "1.0000"
                }
            },
            "detailed": [
                {
                    "warehouse_id": "1",
                    "qty_expected": "0.0000",
                    "qty_processed": "0.0000",
                    "qty_putaway": "0.0000",
                    "qty_available": "5.0000",
                    "qty_allocated": "0.0000",
                    "qty_reserved": "0.0000",
                    "qty_picked": "2.0000",
                    "qty_held": "3.0000",
                    "qty_advertised": "5.0000",
                    "qty_on_hand": "10.0000"
                },
                {
                    "warehouse_id": "2",
                    "qty_expected": "0.0000",
                    "qty_processed": "0.0000",
                    "qty_putaway": "0.0000",
                    "qty_available": "0.0000",
                    "qty_allocated": "0.0000",
                    "qty_reserved": "0.0000",
                    "qty_picked": "0.0000",
                    "qty_held": "0.0000",
                    "qty_advertised": "0.0000",
                    "qty_on_hand": "0.0000"
                },
                {
                    "warehouse_id": "3",
                    "qty_expected": "0.0000",
                    "qty_processed": "0.0000",
                    "qty_putaway": "0.0000",
                    "qty_available": "0.0000",
                    "qty_allocated": "0.0000",
                    "qty_reserved": "0.0000",
                    "qty_picked": "0.0000",
                    "qty_held": "0.0000",
                    "qty_advertised": "0.0000",
                    "qty_on_hand": "0.0000"
                }
            ]
        },
        {
            "sku": "BlueWidget-5",
            "qty_expected": "0.0000",
            "qty_processed": "0.0000",
            "qty_putaway": "0.0000",
            "qty_available": "98.0000",
            "qty_allocated": "0.0000",
            "qty_reserved": "0.0000",
            "qty_picked": "1.0000",
            "qty_held": "0.0000",
            "qty_backordered": "0.0000",
            "qty_advertised": "98.0000",
            "qty_on_hand": "99.0000",
            "qty_held_by_reason": {},
            "detailed": [
                {
                    "warehouse_id": "1",
                    "qty_expected": "0.0000",
                    "qty_processed": "0.0000",
                    "qty_putaway": "0.0000",
                    "qty_available": "98.0000",
                    "qty_allocated": "0.0000",
                    "qty_reserved": "0.0000",
                    "qty_picked": "1.0000",
                    "qty_held": "0.0000",
                    "qty_advertised": "98.0000",
                    "qty_on_hand": "99.0000"
                },
                {
                    "warehouse_id": "2",
                    "qty_expected": "0.0000",
                    "qty_processed": "0.0000",
                    "qty_putaway": "0.0000",
                    "qty_available": "0.0000",
                    "qty_allocated": "0.0000",
                    "qty_reserved": "0.0000",
                    "qty_picked": "0.0000",
                    "qty_held": "0.0000",
                    "qty_advertised": "0.0000",
                    "qty_on_hand": "0.0000"
                },
                {
                    "warehouse_id": "3",
                    "qty_expected": "0.0000",
                    "qty_processed": "0.0000",
                    "qty_putaway": "0.0000",
                    "qty_available": "0.0000",
                    "qty_allocated": "0.0000",
                    "qty_reserved": "0.0000",
                    "qty_picked": "0.0000",
                    "qty_held": "0.0000",
                    "qty_advertised": "0.0000",
                    "qty_on_hand": "0.0000"
                }
            ]
        }
    ]
}
```

### Error Codes

| code | message                            |
| ---- | ---------------------------------- |
| 102  | Unexpected error applying filters. |

## `inventory.detailed_packaging`

`inventory.detailed_packaging (string|array|null $skus, string|null $updatedSince, bool $withHeldBreakdown = false)`

Get global and per-warehouse inventory levels for Packaging Features by SKU. This method is similar to `inventory.detailed` but returns only Packaging Feature types (Container, Supplies, and Infill) that can have inventory. Regular products and other Packaging Feature types are excluded from the results.

As with `inventory.detailed`, each item and warehouse entry includes a `qty_held` quantity, and the optional `withHeldBreakdown` parameter adds the item-level `qty_held_by_reason` (and `qty_held_by_user_reason`) rollups.

### Parameters

<ParamField path="skus" type="string | array | null">
  SKUs. If not specified then inventory for all Packaging Feature SKUs will be returned.

  * `string` - Get inventory for a single Packaging Feature by SKU.
  * `array` - Get inventory for the specified Packaging Features by SKU.
  * `null` - Get inventory for all Packaging Features (Container, Supplies, and Infill).
</ParamField>

<ParamField path="updatedSince" type="string | null">
  Return only SKUs updated since the time specified in the format `2008-07-01T22:38:07+00:00`.
</ParamField>

<ParamField path="withHeldBreakdown" type="boolean" default="false">
  When `true`, each item is augmented with a `qty_held_by_reason` object and, where applicable, a `qty_held_by_user_reason` object. Defaults to `false`.
</ParamField>

### Return Value

An array of detailed Packaging Feature inventory, or an empty array if there were no matching SKUs. Only Packaging Feature types (Container, Supplies, and Infill) are included in the response.

### Example Request

```json theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "method" : "call",
    "params" : [
        "be1c13ed4e03f0ed7f1e4053dfff9658",
        "inventory.detailed_packaging",
        [
            ["PB1688","PB16816"],
            "2014-07-24T18:51:18+00:00"
        ]
    ]
}
```

### Example Response

```json theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "result" : [
        {
            "sku": "PB1688",
            "qty_expected": "50.0000",
            "qty_processed": "0.0000",
            "qty_putaway": "0.0000",
            "qty_available": "150.0000",
            "qty_allocated": "0.0000",
            "qty_reserved": "0.0000",
            "qty_picked": "0.0000",
            "qty_held": "0.0000",
            "qty_backordered": "0.0000",
            "qty_advertised": "150.0000",
            "qty_on_hand": "150.0000",
            "detailed": [
                {
                    "warehouse_id": "1",
                    "qty_expected": "50.0000",
                    "qty_processed": "0.0000",
                    "qty_putaway": "0.0000",
                    "qty_available": "100.0000",
                    "qty_allocated": "0.0000",
                    "qty_reserved": "0.0000",
                    "qty_picked": "0.0000",
                    "qty_held": "0.0000",
                    "qty_advertised": "100.0000",
                    "qty_on_hand": "100.0000"
                },
                {
                    "warehouse_id": "2",
                    "qty_expected": "0.0000",
                    "qty_processed": "0.0000",
                    "qty_putaway": "0.0000",
                    "qty_available": "50.0000",
                    "qty_allocated": "0.0000",
                    "qty_reserved": "0.0000",
                    "qty_picked": "0.0000",
                    "qty_held": "0.0000",
                    "qty_advertised": "50.0000",
                    "qty_on_hand": "50.0000"
                }
            ]
        },
        {
            "sku": "PB16816",
            "qty_expected": "0.0000",
            "qty_processed": "0.0000",
            "qty_putaway": "0.0000",
            "qty_available": "200.0000",
            "qty_allocated": "0.0000",
            "qty_reserved": "0.0000",
            "qty_picked": "0.0000",
            "qty_held": "0.0000",
            "qty_backordered": "0.0000",
            "qty_advertised": "200.0000",
            "qty_on_hand": "200.0000",
            "detailed": [
                {
                    "warehouse_id": "1",
                    "qty_expected": "0.0000",
                    "qty_processed": "0.0000",
                    "qty_putaway": "0.0000",
                    "qty_available": "200.0000",
                    "qty_allocated": "0.0000",
                    "qty_reserved": "0.0000",
                    "qty_picked": "0.0000",
                    "qty_held": "0.0000",
                    "qty_advertised": "200.0000",
                    "qty_on_hand": "200.0000"
                }
            ]
        }
    ]
}
```

### Error Codes

| code | message                            |
| ---- | ---------------------------------- |
| 102  | Unexpected error applying filters. |

## `inventory.holdSearch`

`inventory.holdSearch (null|object $filters, array $options = [])`

Search the merchant's active and released inventory holds. Results are always scoped to the calling merchant's own inventory — no filter combination can return another merchant's holds. The response is paginated and shaped like [inventory.lots](#inventory-lots): `{ results, totalCount, numPages }`.

For privacy, hold rows do not expose internal location identifiers or labels. Identify the held inventory using the `sku`, `lot_number`, and `reason_code` fields instead.

### Parameters

<ParamField path="filters" type="null | object">
  Filters to apply to the search. Every key is optional, and unknown keys are rejected. Combine any of:

  * `product_id` (integer) — holds on a specific product.
  * `sku` (string) — holds on a specific SKU.
  * `warehouse_id` (integer) — restrict to one warehouse. Must be a warehouse the merchant can access.
  * `reason_code` (string) — exact [hold reason](#inventory-holdreasons) code. Matches that reason only; it does **not** roll child reasons up to their parent.
  * `lot_id` (integer) — holds on a specific lot by internal lot ID.
  * `lot_number` (string) — holds on a specific lot by lot number.
  * `status` (string) — `active` (not yet released) or `released`.
  * `held_after` (string) — only holds placed on or after this ISO 8601 timestamp.
  * `held_before` (string) — only holds placed on or before this ISO 8601 timestamp.

  The ambiguous `lot` filter is not supported — use `lot_id` or `lot_number`.
</ParamField>

<ParamField path="options" type="null | object">
  Pagination and sorting:

  * `sort_field` (string) — `held_at` (default), `released_at`, or `hold_id`.
  * `sort_dir` (string) — `asc` or `desc` (default `desc`).
  * `page` (integer) — 1-based page number (default `1`).
  * `limit` (integer) — page size, capped at `100` (default `50`).
</ParamField>

### Return Value

An object with `results` (an array of [Inventory Hold](#inventory-hold-properties) objects), `totalCount`, and `numPages`.

### Example Request

Active damage holds for one SKU, newest first:

```json title="Request" theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "method" : "call",
    "params" : [
        "be1c13ed4e03f0ed7f1e4053dfff9658",
        "inventory.holdSearch",
        [
            {
                "sku": "BlueWidget-1",
                "reason_code": "damaged",
                "status": "active"
            },
            {
                "sort_field": "held_at",
                "sort_dir": "desc",
                "limit": 50
            }
        ]
    ]
}
```

### Example Response

```json title="Response" theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "result" : {
        "results": [
            {
                "hold_id": 4821,
                "sku": "BlueWidget-1",
                "product_name": "Blue Widget (single)",
                "lot_number": "2026-03-15",
                "reason_code": "damaged",
                "reason_label": "Damaged",
                "qty": "2.0000",
                "held_at": "2026-04-12T16:09:44+00:00",
                "released_at": null,
                "notes": "Crushed corner found during QC",
                "status": "active"
            }
        ],
        "totalCount": 1,
        "numPages": 1
    }
}
```

### Error Codes

| code | message                                                                                       |
| ---- | --------------------------------------------------------------------------------------------- |
| 101  | The Warehouse does not exist or the Merchant does not have access to the Warehouse specified. |
| 102  | Invalid or unsupported filter, sort field, status, or date range.                             |

## `inventory.holdReasons`

`inventory.holdReasons()`

Retrieve the list of active inventory hold reasons that are visible to the calling merchant.

### Parameters

This method takes no parameters.

### Return Value

An array of objects, each containing the [Hold Reason Properties](#hold-reason-properties).

### Example Request

```json title="Request" theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "method" : "call",
    "params" : [
        "be1c13ed4e03f0ed7f1e4053dfff9658",
        "inventory.holdReasons"
    ]
}
```

### Example Response

```json title="Response" theme={null}
{
    "jsonrpc" : 2.0,
    "id" : 1234,
    "result" : [
        { "code": "qc_inspection",    "label": "QC Inspection",            "display_group": "Hold" },
        { "code": "cycle_count",      "label": "Cycle Count",              "display_group": "Hold" },
        { "code": "damaged",          "label": "Damaged",                  "display_group": "Hold" },
        { "code": "recalled",         "label": "Recalled",                 "display_group": "Hold" },
        { "code": "expired",          "label": "Expired",                  "display_group": "Hold" },
        { "code": "near_expiry",      "label": "Near Expiry",              "display_group": "Hold" },
        { "code": "contaminated",     "label": "Contaminated",             "display_group": "Hold" },
        { "code": "bond_hold",        "label": "Customs/Bond Hold",        "display_group": "Hold" },
        { "code": "pending_disposal", "label": "Pending Disposal",         "display_group": "Hold" },
        { "code": "pending_return",   "label": "Pending Return to Vendor", "display_group": "Hold" }
    ]
}
```

## Entity Properties

### Inventory Item

<ParamField path="sku" type="string">
  A unique identifier for a product. The SKU does appear on the packing slip. It is recommended that this be human-readable and end with a per-pack quantity to facilitate proper receiving. For example, a single blue widget may be "BlueWidget-1" and a pack of 5 blue widgets may be "BlueWidget-5". Maximum character length is 64.
</ParamField>

<ParamField path="qty_expected" type="integer">
  The "Expected" quantity.
</ParamField>

<ParamField path="qty_processed" type="integer">
  The "Processed" quantity.
</ParamField>

<ParamField path="qty_putaway" type="integer">
  The "Put-Away" quantity.
</ParamField>

<ParamField path="qty_available" type="integer">
  The "Available" quantity.
</ParamField>

<ParamField path="qty_allocated" type="integer">
  The "Allocated" quantity.
</ParamField>

<ParamField path="qty_reserved" type="integer">
  The "Reserved" quantity.
</ParamField>

<ParamField path="qty_picked" type="integer">
  The "Picked" quantity.
</ParamField>

<ParamField path="qty_held" type="integer">
  The "Held" quantity — inventory placed on hold (quarantined, damaged, expired, recalled, etc.). Held inventory stays counted in `qty_on_hand` but is excluded from `qty_available` and cannot be allocated, picked, or packed until the hold is released.
</ParamField>

<ParamField path="qty_backordered" type="integer">
  The "Backordered" quantity. This quantity will not be present for single-warehouse requests since backordered amounts are not apportioned to specific warehouses.
</ParamField>

<ParamField path="qty_advertised" type="integer">
  The "Advertised" quantity. This is the "Available" quantity plus the virtual BOM quantity. The virtual BOM quantity is controlled by a product's "Virtual Inventory" attribute.
</ParamField>

<ParamField path="qty_on_hand" type="integer">
  The Quantity On Hand is `qty_processed` + `qty_putaway` + `qty_available` + `qty_allocated` + `qty_reserved` + `qty_picked` + `qty_held`
</ParamField>

<ParamField path="qty_held_by_reason" type="object">
  Present only when a request is made with `withHeldBreakdown` set to `true`. An object that breaks `qty_held` down by parent (system) [hold reason](#inventory-holdreasons) code, e.g. `{ "damaged": "2.0000", "qc_inspection": "1.0000" }`. Reasons with no held quantity are omitted; an empty object means nothing is held.
</ParamField>

<ParamField path="qty_held_by_user_reason" type="object">
  Present only on `inventory.detailed` / `inventory.detailed_packaging` requests made with `withHeldBreakdown` set to `true`, and only when user-defined sub-reasons are in use. A nested object keyed by parent reason code, each mapping to its user-defined child reason codes and their held quantities, e.g. `{ "qc_inspection": { "qc_lab_review": "1.0000" } }`.
</ParamField>

### Lot Properties

<ParamField path="lot_id" type="integer">
  The internal lot ID.
</ParamField>

<ParamField path="is_active" type="integer">
  Flag whether lot is active.
</ParamField>

<ParamField path="sku" type="string">
  The "SKU" property.
</ParamField>

<ParamField path="name" type="string">
  The "Name" property.
</ParamField>

<ParamField path="lot_number" type="string">
  The "Lot Number" property.
</ParamField>

<ParamField path="expiration_date" type="string">
  The "Expiration Date" property.
</ParamField>

<ParamField path="origination_date" type="string">
  The "Origination Date" property.
</ParamField>

<ParamField path="group_value" type="string">
  The "Group Value" property.
</ParamField>

<ParamField path="created_at" type="string">
  The "Created At" property in ISO 8601 format.
</ParamField>

<ParamField path="locations" type="array">
  A list of locations.
</ParamField>

<ParamField path="qty_putaway" type="string">
  The "Put-Away" quantity.
</ParamField>

<ParamField path="qty_available" type="string">
  The "Available" quantity.
</ParamField>

<ParamField path="qty_reserved" type="string">
  The "Reserved" quantity.
</ParamField>

<ParamField path="qty_held" type="string">
  The quantity of the lot currently on hold across all of its locations.
</ParamField>

<ParamField path="is_on_hold" type="boolean">
  `true` when the lot has at least one active (unreleased) hold, otherwise `false`.
</ParamField>

### Inventory Hold Properties

Returned by [inventory.holdSearch](#inventory-holdsearch). For privacy, hold rows do not include any location identifier or label.

<ParamField path="hold_id" type="integer">
  The internal hold ID.
</ParamField>

<ParamField path="sku" type="string | null">
  The SKU of the held product, or `null` if it cannot be resolved.
</ParamField>

<ParamField path="product_name" type="string | null">
  The name of the held product, or `null` if it cannot be resolved.
</ParamField>

<ParamField path="lot_number" type="string | null">
  The lot number of the held inventory, or `null` when the hold is not lot-specific.
</ParamField>

<ParamField path="reason_code" type="string | null">
  The [hold reason](#inventory-holdreasons) code for this hold.
</ParamField>

<ParamField path="reason_label" type="string | null">
  The human-readable hold reason label as configured in the merchant's account.
</ParamField>

<ParamField path="qty" type="string">
  The quantity placed on hold by this hold record.
</ParamField>

<ParamField path="held_at" type="string">
  When the hold was placed, in ISO 8601 format.
</ParamField>

<ParamField path="released_at" type="string | null">
  When the hold was released, in ISO 8601 format, or `null` if the hold is still active.
</ParamField>

<ParamField path="notes" type="string | null">
  Free-text notes recorded when the hold was placed, or `null`.
</ParamField>

<ParamField path="status" type="string">
  `active` when `released_at` is `null`, otherwise `released`.
</ParamField>

### Hold Reason Properties

<ParamField path="code" type="string">
  The stable machine-readable identifier for the reason. Use this value when calling other endpoints that accept a `reason_code`.
</ParamField>

<ParamField path="label" type="string">
  The human-readable label for the reason as configured in the merchant's account.
</ParamField>

<ParamField path="display_group" type="string">
  The bucket the reason is grouped under in the UI. Built-in groups are `Hold`, `Review`, `Expired`, and `Unsellable`; user-defined reasons may use any text up to 25 characters.
</ParamField>
