# GET /v1/inventory

**Service:** Inventory  
**Operation:** `InventoryService_ListInventory`

Returns a paginated list of stock entries — one per product row per colour — for every catalogue product that has inventory tracking enabled. Every entry is the stock of a single variant row, not a product total: a product with several rows appears once per row, and a single-row product yields one entry. Each entry carries its variant's identifying attributes (thickness and name/value pairs), so entries are tellable apart on their own; sum a product's entries when you need its overall position. Filterable by product name, category, and supplier. Products are ordered alphabetically by name; entries within a product follow the catalogue's row order. Non-tracked products never appear.

## Parameters

| Parameter | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `pageSize` | query | integer | no | Maximum number of stock entries to return per page. 0 uses the server default; the server may cap the value. |
| `pageToken` | query | string | no | Opaque page token from a previous response, used to fetch the next page. |
| `name` | query | string | no | Optional: only return entries for products whose name contains this text (case-insensitive substring match). |
| `categoryId` | query | string | no | Optional: only return entries for products in this category. |
| `supplierId` | query | array | no | Optional: only return entries for products linked to any of these suppliers. A product appears if it is linked to at least one of the listed suppliers. Use ListSuppliers on the SupplierService to discover valid ids. |
| `fields` | query | string | no | Comma-separated response fields to include, using camelCase JSON names (e.g. `orderId,total.amountMicros`). Dot paths reach into nested objects and map transparently across arrays. Paths are relative to the resource, not the response envelope; envelope keys like `nextPageToken` are always preserved. Only 2xx JSON responses are filtered; error bodies pass through unmodified. Unknown names are silently ignored. Takes precedence over `excludeFields` when both are provided. |
| `excludeFields` | query | string | no | Comma-separated response fields to exclude, using camelCase JSON names. Dot paths and array-transparency work the same as `fields`. Paths are relative to the resource, not the response envelope. Only 2xx JSON responses are filtered; error bodies pass through unmodified. Ignored when `fields` is also provided. |

## Responses

| Status | Schema | Description |
| --- | --- | --- |
| 200 | `ListInventoryResponse` | A successful response. |
| 400 | `Error` | The request was rejected because it was malformed — for example an unusable page token or an invalid filter value. The body is a validation-failure envelope: an overall type and message and one entry per problem (each with a stable code, a message, and a param pointing at the offending parameter). |
| 401 | `Error` | The request is missing a valid bearer token, or the token is invalid or expired. |
| 403 | `Error` | The token is valid but does not permit this action, or the resource belongs to a company the token cannot act for. The error type is permission_denied. |
| 429 | `Error` | The request was throttled (rate_limited) or exceeded a size limit (resource_exhausted). When throttled, the Retry-After header says how many seconds to wait before retrying; a resource_exhausted request will fail the same way if retried unchanged. |
| default | `Error` | Any other error. The body is the same error envelope every error uses: a short stable type identifying the kind of failure (for example "rate_limited" or "internal"), a human-readable message, and the request's idempotency key echoed back when one was supplied. |

## Returns

`ListInventoryResponse`

| Field | Type | Description |
| --- | --- | --- |
| `entries` | StockEntry[] | The stock entries in this page. |
| `entries.productId` | string | The catalogue product this entry belongs to. |
| `entries.productName` | string | The product's display name. |
| `entries.productRowId` | string | The product variant row this entry is for — the same id the catalogue product's rows carry. Look the row up there when you need more than this entry shows, such as the variant's prices or colour options. |
| `entries.colour` | string | The colour this entry is for. Empty when the product is not colour-tracked — in that case there is one entry per row. |
| `entries.thickness` | string | The variant's thickness, when its catalogue row carries one. Empty otherwise. |
| `entries.attributes` | RowAttribute[] | The attribute pairs identifying this variant, e.g. [{name:"Size", value:"A4"}] — the same attributes the catalogue product's row carries. Together with thickness and colour they label the entry; a single-row product has no attributes to distinguish, so the list may be empty. |
| `entries.attributes.name` | string | The attribute name, e.g. "Size". |
| `entries.attributes.value` | string | The attribute value, e.g. "A4". |
| `entries.onHand` | string | Quantity currently in stock (on hand). The only directly maintained value; the others are derived from it and from order/purchase data. |
| `entries.promised` | string | Quantity committed to submitted orders that have not yet been received by the customer. Computed from open order line items. |
| `entries.onTheWay` | string | Quantity on submitted purchase orders that have not yet arrived. Computed from open purchase order items. |
| `entries.available` | string | Quantity available for new orders: `onHand` minus promised. Can be negative when more stock is committed than is on hand. |
| `nextPageToken` | string | Token to pass as `pageToken` to fetch the next page; empty when there are no more results. |

---

Source: https://developer.factory.app/reference/inventory/list-inventory · Factory Sales API v1
