Skip to main content

Feature preview: Physical inventory

The physical inventory feature preview gives you early access to a new set of inventory APIs in the unstable GraphQL Admin API. Use them to build against the primitives that model how merchants organize a stockroom: bins, counts, and purchase orders.

Feature preview

These APIs are under active development and are subject to change. Enable the Physical inventory feature preview on a development store to try them, and share feedback so the stable surface is the one you'd want to build on.

These APIs are additive. They introduce new inventory primitives alongside the existing inventory APIs, so your current integration keeps working while you build against them.


  • Bins. Named storage within a location, such as a shelf or a rack. Create and update bins, and read the quantities held in each one.
  • Counts. Set the on-hand quantity of an inventory item in a bin with inventoryCountCreate.
  • Purchase orders. Read purchase order data through the public API: the purchase order, its line items, and its supplier.

Anchor to How bins work with your existing location inventoryHow bins work with your existing location inventory

Today you set an item's on-hand quantity at a location with inventorySetQuantities. Bins add a finer grain inside a location: instead of one on-hand number per location, an item's on-hand can be split across the bins where it's physically stored.

The on-hand that hasn't been placed in any bin is the location's unbinned quantity. A location's total on-hand is the unbinned quantity plus the quantity in every bin:

onHand = unbinnedQuantity + (sum of all bin quantities)

This keeps the preview compatible with the existing location-level APIs:

  • Your existing inventorySetQuantities calls still work. Quantity set at the location level lands in the unbinned quantity — the bins you haven't touched are unaffected.
  • The location-level aggregates (available, committed, onHand) are unchanged. They're still reported per item at the location; bins only change how the on-hand is distributed underneath.
  • To place quantity into a specific bin, use a count (see Set a quantity in a bin).

Anchor to Enable the feature previewEnable the feature preview

Get early access by enabling the Physical inventory feature preview on a development store.

Caution

Feature previews are still under development and are subject to change.

Only stores with the preview enabled can call these APIs. Calls from a store that hasn't enabled the preview return an access error.


Anchor to Build against the APIsBuild against the APIs

Query these APIs against the unstable version of the GraphQL Admin API.

Anchor to Create and update binsCreate and update bins

Use inventoryBinUpsert to create bins under a location, or update an existing bin's barcode. Provide a name (unique within the location) and an optional barcode.

mutation {
inventoryBinUpsert(
locationId: "gid://shopify/Location/10"
inventoryBins: [
{ name: "Shelf-A1", barcode: "012345678912" }
{ name: "Shelf-A2" }
]
) {
inventoryBins {
id
name
barcode
}
userErrors {
field
message
}
}
}
{
"data": {
"inventoryBinUpsert": {
"inventoryBins": [
{ "id": "gid://shopify/InventoryBin/2", "name": "Shelf-A1", "barcode": "012345678912" },
{ "id": "gid://shopify/InventoryBin/3", "name": "Shelf-A2", "barcode": null }
],
"userErrors": []
}
}
}

Anchor to Read bin and location quantitiesRead bin and location quantities

Read from the location query. inventoryItemQuantities returns the per-item aggregates for the location, and inventoryBins returns each bin with the quantities it holds per item.

query {
location(id: "gid://shopify/Location/10") {
id
name
# Per-item aggregates for the location.
inventoryItemQuantities(first: 10) {
nodes {
inventoryItem {
id
sku
}
available
committed
onHand
unbinnedQuantity
}
}
# Each bin and the quantity it holds per item.
inventoryBins(first: 10) {
nodes {
id
name
barcode
inventoryBinItemQuantities(first: 10) {
nodes {
inventoryItem {
id
sku
}
quantity
}
}
}
}
}
}
{
"data": {
"location": {
"id": "gid://shopify/Location/10",
"name": "Warehouse A",
"inventoryItemQuantities": {
"nodes": [
{
"inventoryItem": { "id": "gid://shopify/InventoryItem/1", "sku": "sku-a" },
"available": 21,
"committed": 2,
"onHand": 23,
"unbinnedQuantity": 5
}
]
},
"inventoryBins": {
"nodes": [
{
"id": "gid://shopify/InventoryBin/2",
"name": "Shelf-A1",
"barcode": "012345678912",
"inventoryBinItemQuantities": {
"nodes": [
{ "inventoryItem": { "id": "gid://shopify/InventoryItem/1", "sku": "sku-a" }, "quantity": 10 }
]
}
},
{
"id": "gid://shopify/InventoryBin/3",
"name": "Shelf-A2",
"barcode": null,
"inventoryBinItemQuantities": {
"nodes": [
{ "inventoryItem": { "id": "gid://shopify/InventoryItem/1", "sku": "sku-a" }, "quantity": 8 }
]
}
}
]
}
}
}
}

Here onHand (23) is unbinnedQuantity (5) plus the two bins (10 + 8). available and committed stay at the location level.

Anchor to Set a quantity in a binSet a quantity in a bin

Use inventoryCountCreate to set the on-hand quantity of an item in a bin. Each line item targets an inventory item and a bin, with a quantity:

  • actualQuantity is the on-hand quantity to set for that item in that bin.
  • expectedQuantity is the quantity you last read for that item in that bin. It's used to detect a variance and to guard against overwriting a change made since you read.
mutation {
inventoryCountCreate(
locationId: "gid://shopify/Location/10"
lineItems: [
{
inventoryItemId: "gid://shopify/InventoryItem/1"
inventoryBinId: "gid://shopify/InventoryBin/2"
quantity: { actualQuantity: 10, expectedQuantity: 9 }
}
]
) {
userErrors {
field
message
}
}
}
{
"data": {
"inventoryCountCreate": {
"userErrors": []
}
}
}

After the count is created, read the bin's quantities back with the location query to confirm the new on-hand.

Anchor to Read purchase ordersRead purchase orders

Read a single purchase order with inventoryPurchaseOrder, or a list with inventoryPurchaseOrders.

query {
inventoryPurchaseOrder(id: "gid://shopify/InventoryPurchaseOrder/1") {
id
name
status
supplier {
name
}
lineItems(first: 10) {
nodes {
title
supplierSku
totalQuantity
}
}
}
}
{
"data": {
"inventoryPurchaseOrder": {
"id": "gid://shopify/InventoryPurchaseOrder/1",
"name": "#PO1001",
"status": "OPEN",
"supplier": { "name": "Acme Supply Co." },
"lineItems": {
"nodes": [
{ "title": "Widget", "supplierSku": "ACME-WIDGET-01", "totalQuantity": 100 }
]
}
}
}
}

Query many purchase orders with inventoryPurchaseOrders:

query {
inventoryPurchaseOrders(first: 10) {
nodes {
id
name
status
supplier {
name
}
}
}
}

Was this page helpful?