Skip to content

Inventory

Inventory in BenchKey is tracked as per-location stock levels. Each record ties one product (part) to one location and exposes the quantity on hand plus a configurable minimum threshold. Quantities are never summed across locations, each site is reported independently so callers can reason about stock at each location.

{
"object": "stock_level",
"product_id": 42,
"product_name": "iPhone 14 Screen Assembly",
"product_sku": "SCR-IP14-OEM",
"product_active": true,
"location_id": 1,
"location_name": "Main Shop",
"is_warehouse": false,
"location_active": true,
"qty_on_hand": 5,
"min_stock": 2,
"low_stock": false,
"updated_at": "2025-11-15T14:30:00.000Z"
}
FieldTypeDescription
product_idintegerUnique product (inventory part) ID
product_namestring|nullProduct display name
product_skustring|nullSKU, or null if not set
product_activebooleanWhether the product is active in your catalog
location_idintegerLocation ID
location_namestring|nullLocation display name
is_warehousebooleantrue if the location is a warehouse (vs. a service counter)
location_activebooleanWhether the location is active
qty_on_handintegerCurrent quantity at this location
min_stockintegerReorder threshold; 0 means no threshold set
low_stockbooleantrue when min_stock > 0 and qty_on_hand ≤ min_stock
updated_atstringISO-8601 timestamp of the last stock change

GET /api/v1/inventory

Returns a cursor-paginated list of stock level records ordered by most recently updated first. Each row represents one product at one location.

Scope required: inventory.read

ParameterTypeDescription
product_idintegerFilter to a specific product (positive integer ≤ 2,147,483,647; out-of-range values return 400 invalid_query)
location_idintegerFilter to a specific location (positive integer ≤ 2,147,483,647; out-of-range values return 400 invalid_query)
low_stockbooleanPass true to return only rows at or below min_stock. Accepted values: true/1/false/0. Any other value returns 400 invalid_query
activestringPass "all" to include stock rows for inactive (archived) products. Default is active-only. Any value other than "1" or "all" returns 400 invalid_query
limitintegerPage size, 1–100 (default: 20)
cursorstringOpaque cursor from a previous response’s next_cursor
Terminal window
curl "https://app.benchkey.com/api/v1/inventory?low_stock=true&limit=20" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa"
const res = await fetch(
"https://app.benchkey.com/api/v1/inventory?low_stock=true&limit=20",
{ headers: { Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" } }
);
const { data, has_more, next_cursor } = await res.json();
{
"object": "list",
"data": [
{
"object": "stock_level",
"product_id": 42,
"product_name": "iPhone 14 Screen Assembly",
"product_sku": "SCR-IP14-OEM",
"product_active": true,
"location_id": 1,
"location_name": "Main Shop",
"is_warehouse": false,
"location_active": true,
"qty_on_hand": 1,
"min_stock": 2,
"low_stock": true,
"updated_at": "2025-11-15T14:30:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}

See Pagination for how to page through results.


GET /api/v1/inventory/:product_id/locations

Returns all location stock rows for a single product. Useful for getting a complete picture of where a product is stocked and in what quantities.

Scope required: inventory.read

Terminal window
curl "https://app.benchkey.com/api/v1/inventory/42/locations" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa"
const res = await fetch(
"https://app.benchkey.com/api/v1/inventory/42/locations",
{ headers: { Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" } }
);
const { data } = await res.json();
{
"object": "list",
"data": [
{
"object": "stock_level",
"product_id": 42,
"product_name": "iPhone 14 Screen Assembly",
"product_sku": "SCR-IP14-OEM",
"product_active": true,
"location_id": 1,
"location_name": "Main Shop",
"is_warehouse": false,
"location_active": true,
"qty_on_hand": 1,
"min_stock": 2,
"low_stock": true,
"updated_at": "2025-11-15T14:30:00.000Z"
},
{
"object": "stock_level",
"product_id": 42,
"product_name": "iPhone 14 Screen Assembly",
"product_sku": "SCR-IP14-OEM",
"product_active": true,
"location_id": 2,
"location_name": "Warehouse",
"is_warehouse": true,
"location_active": true,
"qty_on_hand": 14,
"min_stock": 5,
"low_stock": false,
"updated_at": "2025-11-10T09:00:00.000Z"
}
],
"has_more": false,
"next_cursor": null
}

GET /api/v1/inventory/:product_id/locations/:location_id

Returns the stock level for a specific product at a specific location.

Scope required: inventory.read

Terminal window
curl "https://app.benchkey.com/api/v1/inventory/42/locations/1" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa"
const res = await fetch(
"https://app.benchkey.com/api/v1/inventory/42/locations/1",
{ headers: { Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" } }
);
const level = await res.json();

Returns a single stock_level object. Returns 404 if the product or location doesn’t exist.


POST /api/v1/inventory/:product_id/adjust

Applies a delta adjustment to a product’s stock quantity and records it in the audit log. Positive values add stock; negative values deduct. An adjustment of zero is rejected.

Scope required: inventory.write

FieldRequiredDescription
qty_changeyesInteger delta, positive adds stock, negative deducts
location_idnoLocation to adjust; omit to use the default location
reasonnoAudit log note (e.g. "Cycle count correction")
Terminal window
# Deduct 2 units from location 1 (shrinkage/breakage)
curl -X POST "https://app.benchkey.com/api/v1/inventory/42/adjust" \
-H "Authorization: Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa" \
-H "Content-Type: application/json" \
-d '{
"qty_change": -2,
"location_id": 1,
"reason": "Screen cracked during install"
}'
const res = await fetch(
"https://app.benchkey.com/api/v1/inventory/42/adjust",
{
method: "POST",
headers: {
Authorization: "Bearer bk_live_01J8X4_kvWz9nP3mRqTs7uYeBfGhDjLa",
"Content-Type": "application/json",
},
body: JSON.stringify({
qty_change: -2,
location_id: 1,
reason: "Screen cracked during install",
}),
}
);
const level = await res.json();

Returns the updated stock_level object for the adjusted location.


HTTP statusCodeMeaning
400invalid_idA path segment (product_id or location_id) is not a valid positive integer
400invalid_querylow_stock is not a recognized boolean value (true/1/false/0)
400invalid_paramA list query filter (product_id or location_id) is not a valid positive integer
400invalid_cursorcursor is malformed
400missing_fieldqty_change is absent from the request body
400invalid_fieldqty_change is zero or not an integer; reason is not a string; or location_id in the body is not a positive integer
404not_foundProduct or location does not exist
409insufficient_qtyDeduction would push qty_on_hand below zero
422adjust_failedThe stock adjustment failed for another reason
403insufficient_scopeAPI key lacks inventory.read or inventory.write

See Errors for the full error envelope format.

System status