> For the complete documentation index, see [llms.txt](https://docs.fulfillmenttools.com/documentation/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/listing.md).

# Listing

A listing is an item that's sold in a facility. It contains product information, such as price, barcodes, and attributes. A listing doesn't represent the actual (available) quantity of a product in a facility.

The listing `id` is composed of `{facilityId}_{tenantArticleId}`. For example, if the `facilityId` is `5d174533-29b9-464b-9325-94bfacefe335` and the `tenantArticleId` is `SNEAK-W-4891`, the listing `id` would be `5d174533-29b9-464b-9325-94bfacefe335_SNEAK-W-4891`.

{% hint style="warning" %}
Please note the difference between listings and [articles](/documentation/by-pillar/global-inventory-hub/articles.md).
{% endhint %}

## Listings and stocks

A listing holds master data for a product within a facility. Stock refers to one or more items in a facility that share the same attributes. Stock holds all information specific to individual pieces of a product.

Stock can technically exist without listings. However, we strongly recommend always creating listings for two reasons:

* Listings are required for order routing as they contain data relevant to routing processes. Routing to a facility isn't possible if that facility has no listings.
* Listings provide the product information displayed in fulfillmenttools clients (for example, Backoffice and Store Operations app).

See the [Stock article](/documentation/by-pillar/global-inventory-hub/stock.md) for more information.

## Listing properties and configurations

### Tenant article ID

A `tenantArticleID` is a unique identifier of an item. You can define this field as you wish. For example, you could use your product ID from your commerce system, or your SKU (Stock Keeping Unit) number. See the [URN pattern article](/documentation/apis/api-reference.md#uniform-resource-name-pattern-urn-in-path-parameters) for more details.

### Status

Listings can be active or inactive.

{% hint style="warning" %}
Deactivated listings are not considered for incoming orders.
{% endhint %}

The `LISTINGS_STATUS_CHANGED` event is emitted when the status is changed.

### Listing attributes

Attributes store listing-specific information, including:

* Descriptions
* Picking sequence
* Shop and sales price
* Insurance-related data for shipping
* Dimensions

{% hint style="info" %}
For more information, see the [article attributes article](/documentation/by-pillar/global-inventory-hub/articles/article-attributes.md).
{% endhint %}

### Scanning rule

Configuration that shows the client how items should be scanned during picking. For more information, see the [scanning configuration article](/documentation/by-pillar/store-operations/picking.md#scanning-configuration).

### Out of stock behavior <a href="#out-of-stock-behaviour" id="out-of-stock-behaviour"></a>

Defines the behavior when a customer places an order for a product that is out of stock or unavailable for immediate shipment.

A listing can be designated as backorderable, preorderable, restockable, or both preorderable and restockable.

You can configure out-of-stock behavior for specific facility groups or orders with certain tags. You can also set exceptions to these out-of-stock behaviors.

{% hint style="info" %}
See the [Preorders and backorders article](/documentation/by-pillar/advanced-order-routing/pre-and-backorders.md) for functional details. Configuration details can be found in the [Out of stock behavior and configuration article](/documentation/by-pillar/global-inventory-hub/stock/out-of-stock-behavior-and-configuration.md).
{% endhint %}

The `LISTINGS_STOCK_CONFIGURATIONS_CHANGED` event is emitted when this setting is changed.

### Availability timeframe <a href="#availability-timeframe" id="availability-timeframe"></a>

If a listing is already flagged with `outOfStockBehaviour` = "BACKORDER" and has an `availabilityTimeFrame` configured, orders containing that listing are accepted but assigned a specific facility only when the date defined in the `availabilityTimeFrame` is reached.​

### Out-of-stock configuration

{% hint style="info" %}
This functionality is only available if your tenant is configured for operating in complex networks. If you're interested, contact our Support team via [service request](https://ocfulfillment.atlassian.net/servicedesk/customer/portal/1/group/11/create/39).
{% endhint %}

The out-of-stock configuration defines behavior if a consumer places an order for an article that is currently out of stock or unavailable for immediate shipment.&#x20;

A listing can be either backorderable, preorderable, restockable, or preorderable and restockable. You can define this in the listing's `outOfStockBehaviour`.&#x20;

For preorderable, restockable, or preorderable and restockable, you must also configure an `outOfStockConfig` on the listing. If the out-of-stock behavior should apply only to specific facility groups or orders with certain tags, define an `outOfStockBehaviourByContexts`.

* Preorderable
  * The order can be picked as soon as the `availabilityTimeFrame.start` is reached.
  * If no stock is available for the order line item(s), this configuration is not considered.
* Restockable
  * The order is treated as having "infinite" stock for the respective line items (after "x days").
  * The `restockableInDays` is used for calculations in routing. If `restockableInDays` = 0, routing assumes the facility has sufficient stock.

{% hint style="info" %}
If different facility groups or orders have different out-of-stock behaviors, you can add a `context` to the [out-of-stock configuration](/documentation/by-pillar/global-inventory-hub/stock/out-of-stock-behavior-and-configuration.md).
{% endhint %}

The `LISTINGS_STOCK_CONFIGURATIONS_CHANGED` event is emitted when `outOfStockBehaviour`, `outOfStockConfig`, or `outOfStockBehaviourByContexts` are changed.

### Tags

Tags consist of a tag `id` plus allowed values for each tag. They can map very specific processes and customize entities to meet particular needs. For more information, see the [Tags](/documentation/getting-started/tags.md) and [Stickers](/documentation/getting-started/stickers.md) articles.

### Measurement units

Measurement units specify the unit used to count or measure the product. You can set them using the `measurementUnitKey` field. The default counting unit is pieces. However, you can define other units, such as grams, liters, or custom units. For more information on creating new units and their localizations, refer to the [Measurement units article](/documentation/by-pillar/global-inventory-hub/measurement-units.md).

If one product should be tracked in different units (for example, as bulk by weight and also by prepackaged quantity), two listings with different tenant article IDs need to be created, for example, "xyz-123-bulk" and "xyz-123-packaged". Since each product is kept in one measurement unit, operations like adding or moving stock don't need to validate or convert units between stocks.

### Stock properties

Stock properties allow tracking specific values on a set of items, a [stock](/documentation/by-pillar/global-inventory-hub/stock.md). A typical example of properties is the expiry date or batch number. The listing defines which properties should be tracked for stocks associated with this specific listing. Moreover, the listing can be configured to make tracking stock properties mandatory (for example, during goods receipt) and to specify whether the value is expected to be text or a date.

Often, it helps to limit and enforce which properties are tracked for each product type. You can configure this using the `stockProperties` field on `Listings`. This field does not contain key-value pairs of property values but rather `StockPropertyDefinitions`. Each defines the following:

For more information, see the [Stock properties article](/documentation/by-pillar/global-inventory-hub/stock/stock-properties.md).

The `LISTINGS_STOCK_CONFIGURATIONS_CHANGED` event is emitted when `stockProperties` is changed.

| Field          | Description                                                                                                                                          |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| `inputType`    | `DATE` or `TEXT`. The input type controls how clients should treat this property's values (for example, show a date picker instead of a text field). |
| `required`     | `boolean`. Creating a stock without providing a value for a `required` property will be forbidden and will fail.                                     |
| `defaultValue` | String or `{{NOW}}`, which will be interpolated to the current timestamp.                                                                            |

{% hint style="warning" %}
Constraints, validations, and default values are only applied when creating stocks.

This means existing stocks may still lack required properties, or have properties that are not allowed under newer rulesets.
{% endhint %}

If you don't want to enforce constraints, you can set the `stockProperties` field to `null` or `undefined`. In that case, no properties are set.

### Stock available until

The `availableUntil` field defines until when stock is included in the stock availability, which is, for example, used to communicate available stock to shop systems. For consumer orders, the availability check ensures that stock has not exceeded its `availableUntil` value until it is delivered to the customer.

In the listing, you can specify until when the corresponding stock should be available. The `availableUntil` value is set when stock is created if configured in the listing. When updating a listing with `stockAvailableUntil`, the value is added only to newly created stock.

The `LISTINGS_STOCK_CONFIGURATIONS_CHANGED` event is emitted when `stockAvailableUntil` is changed.

For more information, see the [Stock availability article](/documentation/by-pillar/global-inventory-hub/stock/stock-availability.md).

* `calculation base`: Specifies the base date for the calculation of `availableUntil`. Set the field to `EXPIRY` if the stock should become unavailable before it expires. `EXPIRY` must be configured in the [stockProperties](#stock-properties) before it can be used here. Set the field to `CREATION` if the stock should become unavailable sometime after it was created.
* `modifier`: The time span is applied to the calculation base to calculate when stock should become unavailable. Use negative values to move the date backward. Example: `-P30D` places the `availableUntil` value 30 days before the calculated date.

{% hint style="warning" %}

* `stockAvailableUntil` defaults to the expiry date. So, if no `stockAvailableUntil` is configured on the listing, a stock's `stockAvailableUntil` will be its expiry date.
* An undefined `stockAvailableUntil` on stocks (for example, no `stockAvailableUntil` and no expiry is configured) means the stock will be available indefinitely.
  {% endhint %}

### Legal

Under `legal`, you can specify a `hsCode`. HS stands for Harmonized System and is a description and coding system authorities use to classify a product. In fulfillmenttools, it's used, for example, when requesting a carrier label for sending a package.

### Categories

A listing can belong to one to many categories. The `categoryRef` on the listing lets you assign multiple listings to the same category.

{% hint style="info" %}
More information can be found under [article categories](/documentation/by-pillar/global-inventory-hub/categories.md).
{% endhint %}

{% hint style="info" %}
For detailed API specifications, see the [REST API documentation for Listings](https://fulfillmenttools.github.io/fulfillmenttools-api-reference-ui/#get-/api/facilities/-facilityId-/listings).
{% endhint %}

## Create a listing

{% hint style="warning" %}
Before creating a listing, you must create a [facility](/documentation/getting-started/facilities.md). Listings are always related to a specific facility.
{% endhint %}

To create a listing, send a `PUT` request to the following endpoint with a JSON body:

```http
PUT https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/facilities/{YOUR_FACILITY_ID}/listings
```

```json
{
  "listings": [
    {
      "imageUrl": "https://img.example.com/img/sneakw4891.jpg",
      "price": 119.00,
      "tenantArticleId": "SNEAK-W-4891",
      "titleLocalized": {
        "de_DE": "Weiße turnschuhe",
        "en_US": "White sneakers"
      }
    }
  ]
}
```

A successful request returns an `HTTP 200 OK` response.

Use the same `PUT` request to update your listings for a single facility. To update listings for multiple facilities, see the [Bulk upsert listings section](#bulk-upsert-listings).

{% hint style="info" %}
The `PUT` acts with upsert behavior. It creates a new listing or updates an existing one. It will never delete a listing. To delete a listing, see [Delete a listing](#delete-a-listing).
{% endhint %}

When you update certain fields, the `LISTINGS_INFORMATION_CHANGED` event is emitted. This applies to updates for the following fields:

* `attributes`
* `price`
* `title`
* `titleLocalized`
* `weight`
* `scannableCodes`
* `tags`
* `measurementUnitKey`
* `currency`
* `legal`
* `customAttributes`
* `categoryRefs`
* `imageUrl`

## Retrieve listings

To retrieve all listings for a specific facility, send a paginated `GET` request to the following endpoint using the `facilityId`:

```http
GET https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/facilities/{YOUR_FACILITY_ID}/listings
```

A successful request returns an `HTTP 200 OK` response containing all listings for that facility.

```json
{
    "total": 1,
    "listings": [
        {
            "id": "5d174533-29b9-464b-9325-94bfacefe335_SNEAK-W-4891",
            "version": 1,
            "status": "ACTIVE",
            "tenantArticleId": "SNEAK-W-4891",
            "created": "2026-08-22T12:19:14.129Z"
        }
    ]
}
```

Alternatively, to retrieve a specific listing by its `tenantArticleId`, use the following `GET` endpoint:

```http
GET https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/facilities/{YOUR_FACILITY_ID}/listings/{YOUR_TENANT_ARTICLE_ID}
```

The endpoint returns an `HTTP 200 OK` response with a detailed view of the specified listing:

```json
{
  "attributes": null,
  "imageUrl": "https://img.example.com/img/sneakw4891.jpg",
  "price": 119.00,
  "tenantArticleId": "SNEAK-W-4891",
  "titleLocalized": {
    "de_DE": "Weiße turnschuhe",
    "en_US": "White sneakers"
  },
  "scannableCodes": [],
  "created": "2026-08-22T12:19:14.129Z",
  "lastModified": "2026-08-22T12:19:14.129Z",
  "version": 1,
  "facilityId": "5d174533-29b9-464b-9325-94bfacefe335",
  "id": "5d174533-29b9-464b-9325-94bfacefe335_SNEAK-W-4891",
  "status": "ACTIVE"
}
```

{% hint style="info" %}
Notice that the `id` for the listing is made up of both the `facilityId` and the `tenantArticleId`.
{% endhint %}

## Bulk upsert listings

To upsert listings for multiple facilities while minimizing API calls, use the bulk upsert endpoint.

There are two options for using the endpoint:

* [`ListingForBulkUpsertBySelector`](#updating-with-listingforbulkupsertbyselector): Lets you send listing information once and update it for multiple facilities.
* [`ListingForBulkUpsertByFacility`](#updating-with-listingforbulkupsertbyfacility): Lets you send different listing information for the same `tenantArticleId` for multiple facilities.

{% hint style="info" %}
Send the listing `version` to update it. Otherwise, it creates a new listing. If a listing with the same `tenantArticleId` already exists, the entire update batch fails.
{% endhint %}

### Search for the listing version

Before updating existing listings, you must retrieve their current `version`. You can do this by searching for the listings. Then use the bulk API to update multiple listings across facilities simultaneously.

The following example shows how to search for all listings with `tenantArticleId` SNEAK-W-4891 to retrieve their current versions.

```http
POST https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/listings/search
```

```json
{
  "query": {
    "tenantArticleId": {
      "eq": "SNEAK-W-4891"
    }
  }
}
```

{% hint style="info" %}
You might need to iterate over multiple pages to get all listings with the corresponding `tenantArticleId`. More information can be found under [Pagination.](/documentation/getting-started/general-concepts.md#pagination)
{% endhint %}

The search returns the complete listings.

### Update with `ListingForBulkUpsertBySelector`

To update multiple listings, send a `PUT` request to the following endpoint with the JSON body:

```http
PUT https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/listings
```

```json
{
  "listings": [
    {
      "tenantArticleId": "SNEAK-W-4891",
      "selector": [
        {
          "facility": {
            "facilityRef": "facility1"
          },
          "version": 42
        },
        {
          "facility": {
            "facilityRef": "facility2"
          },
          "version": 43
        }
      ],
      "targetingStrategy": "MULTI_SELECTOR",
       ... // the full updated listing
    }
  ]
}
```

Each object in the `selector` array specifies a listing in a particular facility by its `tenantArticleId` and current `version`. A single batch can update up to 25 listings. You can do this by providing 25 selectors for one listing, or by providing multiple listings with their respective selectors. The endpoint returns the updated listings and a summary of the operations.

{% hint style="warning" %}
This is an all-or-nothing behavior. If one listing insert fails, all others will fail as well.
{% endhint %}

```json
{
  "listings": [
    {
      ...
    },
    ...
  ],
  "summary": {
    "created": 0,
    "updated": 2
  }
}
```

### Update with `ListingForBulkUpsertByFacility`

To update multiple listings, send a `PUT` request to the following endpoint with the JSON body:

```http
PUT https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/listings
```

```json
{
  "listings": [
    {
      "tenantArticleId": "SNEAK-W-4891",
      "facility": {
        "facilityRef": "facility1"
      },
      "targetingStrategy": "SINGLE_FACILITY",
      "version": 42,
      ... // the full updated listing
    },
    {
      "tenantArticleId": "SNEAK-W-4891",
      "facility": {
        "facilityRef": "facility2"
      },
      "targetingStrategy": "SINGLE_FACILITY",
      "version": 43,
      ... // the full updated listing
    },
    ...
  ]
}
```

The endpoint returns the updated listings and a summary of the operations.

{% hint style="warning" %}
This is an all-or-nothing behavior. If one listing insert fails, all others will fail as well.
{% endhint %}

```json
{
  "listings": [
    {
      ...
    },
    ...
  ],
  "summary": {
    "created": 0,
    "updated": 2
  }
}
```

## Delete a listing

To delete a single listing, send a `DELETE` request to this endpoint:

```http
DELETE https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/facilities/{facilityId}/listings/{tenantArticleId}
```

To delete all the listings for a facility, use the endpoint below:

```http
DELETE https://{YOUR_TENANT_NAME}.api.fulfillmenttools.com/api/facilities/{facilityId}/listings
```


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation by asking a question.

Perform an HTTP GET request on the following URL with the `ask` and `goal` query parameters:

```
GET https://docs.fulfillmenttools.com/documentation/by-pillar/global-inventory-hub/listing.md?ask=<question>&goal=<user_goal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is what the user is ultimately trying to achieve, the reason they need the answer. Sharing it helps GitBook give you a better, more relevant answer. A goal is most helpful when it describes the outcome the user wants rather than restating the question. For example, with `ask=how do I create an API token`, a goal like `automate deployments from our CI pipeline` lets GitBook tailor the answer to that use case.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
