This article covers the core read/write stock endpoints: general listing, query by SKU or by location, single update, bulk update, statistics, and reports.
lowStock=true filters to records with stock < 10. This threshold is hardcoded in the service — it is not configurable per tenant or per SKU from this endpoint.
This endpoint performs a findOne({tenantId, sku}) — it returns the first record Mongo finds for that SKU, with no deterministic ordering. Since a SKU can have one inventory record per location (unique index {tenantId, sku, locationId}), this endpoint does not consolidate or sum the stock across all locations of a multi-location SKU. If you need the stock of a SKU in a specific location, use GET /inventory/location/:id/product/:sku (further down this same page).
If you send a stock value that would result in a negative number, the API responds with 500 and {"code":"internal-error","message":"Stock cannot be negative"} — not a structured 400. This is the current behavior in production: negative validation happens in a layer that doesn't distinguish a business error from an internal error. Treat it as a business error response (reject the attempt), but don't expect the usual HTTP status for validations.
A record whose stock is controlled by an integration or channel (handlerType: 'integration' | 'channel') may reject the manual write with 403 forbidden/inventory-handler.
This response is always 200 if the body is valid, even if some (or all) individual items fail. There is no root-level success flag. You must iterate the results array and check success on each element — a global 200 never guarantees your entire batch was applied.
productsLowStock uses a fixed threshold of 5 units (DEFAULT_MIN_ALERT_STOCK), different from the < 10 threshold used by the lowStock filter on GET /inventory. Don't confuse the two — they are two independent hardcoded thresholds.
The valuation report (reportType=valuation) is broken
The valuation report reads unitCost directly from the Inventory document, but that field does not exist in the inventory schema — it is always undefined. As a result, totalValue and averageUnitCost from this report are effectively 0 for any tenant. Do not use it as an inventory valuation source.
format=csv does nothing
The format parameter is accepted but ignored: the response is always JSON, regardless of the value sent.
No body is validated or read — the route responds 501 regardless of the body sent.
{}
501
{ "code": "not-implemented" }
GET /inventory (root route) is equivalent to the listing documented above. POST /inventory on that same route responds 501 not-implemented — there is no generic "create inventory" operation; inventory records are created implicitly when stock is written (PUT/bulk-update) or through internal product flows.