Applies to: Inventory API | Catalog API
Learn how to enable selling a product in different measurement units with a specified stock conversion.
When a business receives, stocks, and sells a product in the same unit of measurement, basic inventory is sufficient to track inventory state transitions of item variations. For example, when a wine store receives, stocks, and sells by the bottle, it can use basic inventory to monitor its daily operations.
When a business receives or stocks a product in one unit of measurement and sells the product in multiple units, its inventory tracking must be able to account for conversions. For example, when a restaurant stocks its wine selection by the bottle, but serves the customer by the bottle or by the glass, its inventory system must be able to track inventory adjustments that account for different units of measurement to yield consistent results.
Important
To use stock conversion, you must have a Square for Retail Plus subscription.
A seller often stocks a product in the received or stocking unit and sells the product in different sale units. For example, a restaurant purchases and stocks a wine in bottles, but sells the wine by the bottle or by the glass. In this example, a bottle is the stocking unit and also a sale unit. On the other hand, a glass is only another sale unit.
To enable such business scenarios, the seller must determine the conversion between different units of measurement, according to the business requirements. For example, suppose that one bottle of wine can be converted into five glasses. When a customer orders one bottle of the wine, the wine's inventory counts should be decremented by 1
bottle or by 5
glasses. When a customer orders two glasses of the wine, the inventory counts should be decremented by 2/5
of a bottle or by 2
glasses. The stockable inventory count corresponds to quantities used for physical counts, whereas the non-stockable (in this case, a sellable-only) inventory count is computed based on its stock conversion specification.
You can use the the Catalog API to create items with item variations in different units of measurement.
The following example uses the Catalog API to create a Red Wine
item for sale with a Bottle
variation to manage the stockable (and also sellable) inventory and a Glass
variation to manage the sellable-only inventory count. The inventory quantities of the Bottle
and Glass
variations are synchronized according to the rule stipulated in the stockable_conversion
object. In this example, one bottle equals five glasses.
The example request assumes that you have a CatalogTax object created for all your seller locations and this CatalogTax
object is referenced by the ID KBPWWOXZHOGNOSQ2LIVS4H27
. If your seller location has no sales tax, you can ignore the tax specification in the input.
The category of the item, as referenced by {"category_id": "JXVXTYYDLZRPXMQ7SMNJXVVG"}
, refers to wine for sale at the seller locations.
In addition, you must have two different CatalogMeasurementUnit objects created, one (referenced by the {"measurement_unit_id" : "SQKOHTEZUX2QWIZXMH3Z5WGW"}
) as the measurement unit of the stockable variation (Bottle
) and the other (referenced by {"measurement_unit_id": "DPCQ2HA44EN3EIJT3WEXN5FE"
) as the measurement unit of the sellable-only variation (Glass
) as the non-stockable. If a desired measurement unit doesn't exist, you can call UpsertCatalogObject separately to create it before making the following call. Alternatively, you can call BatchUpsertCatalogObjects to have the required measurement units and the items with stockable and non-stockable variations created all together.
Upsert catalog object
Make sure that the two item variations subject to the stock conversion are assigned the same SKU
value. Otherwise, you get two separate stockable variations.
When the request succeeds, a 200 OK
response is returned with the body similar to the following:
{
"catalog_object": {
"type": "ITEM",
"id": "WWXPVSBT3TUXKNXT3VSXQXMX",
"updated_at": "2021-06-11T03:16:49.531Z",
"version": 1623381409531,
"is_deleted": false,
"present_at_all_locations": true,
"item_data": {
"name": "Vin",
"description": "Vin Rouge",
"category_id": "JXVXTYYDLZRPXMQ7SMNJXVVG",
"tax_ids": [
"KBPWWOXZHOGNOSQ2LIVS4H27"
],
"variations": [
{
"type": "ITEM_VARIATION",
"id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
"updated_at": "2021-06-11T03:16:49.531Z",
"version": 1623381409531,
"is_deleted": false,
"present_at_all_locations": true,
"item_variation_data": {
"item_id": "WWXPVSBT3TUXKNXT3VSXQXMX",
"name": "Bottle",
"sku": "wine-123-r",
"ordinal": 0,
"pricing_type": "FIXED_PRICING",
"price_money": {
"amount": 2500,
"currency": "USD"
},
"track_inventory": true,
"measurement_unit_id": "SQKOHTEZUX2QWIZXMH3Z5WGW",
"stockable": true
}
},
{
"type": "ITEM_VARIATION",
"id": "IUD2QMXX4K62W35HW5CVQGL6",
"updated_at": "2021-06-11T03:16:49.531Z",
"version": 1623381409531,
"is_deleted": false,
"present_at_all_locations": true,
"item_variation_data": {
"item_id": "WWXPVSBT3TUXKNXT3VSXQXMX",
"name": "Glass",
"sku": "wine-123-r",
"ordinal": 1,
"pricing_type": "FIXED_PRICING",
"price_money": {
"amount": 800,
"currency": "USD"
},
"track_inventory": true,
"measurement_unit_id": "DPCQ2HA44EN3EIJT3WEXN5FE",
"stockable": false,
"composition_id": "LO3T2SO2RCEZXXJARZJJKPWI",
"stockable_conversion": {
"stockable_item_variation_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
"stockable_quantity": "1",
"nonstockable_quantity": "5"
}
}
}
],
"product_type": "REGULAR"
}
},
"id_mappings": [
{
"client_object_id": "#wine",
"object_id": "WWXPVSBT3TUXKNXT3VSXQXMX"
},
{
"client_object_id": "#bottle",
"object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ"
},
{
"client_object_id": "#glass",
"object_id": "IUD2QMXX4K62W35HW5CVQGL6"
}
]
}
The ID of the stockable variation (#bottle
) is PMUUU2EFXNRBKTUAMTC5SQTZ
and the ID of the sellable-only variation (#glass
) is IUD2QMXX4K62W35HW5CVQGL6
. They're used later to adjust inventory counts when a bottle or glass is ordered.
In the example, a bottle is the unit of the stockable variation. When the seller takes delivery of N bottles of the wine, the quantity must be added to the seller's inventory. The associated inventory state changes from NONE
to IN_STOCK
.
Note
You can add the stockable variation to the inventory in the Items library in the Square Dashboard. Look for Adjust Inventory or Manage stock.
To add a delivery of 24
bottles of wine to the inventory, call the BatchChangeInventory endpoint of the Inventory API on the stockable variation (PMUUU2EFXNRBKTUAMTC5SQTZ
). This is shown in the following example request:
Batch change inventory
If the request is successful, a 200 OK
response returns the results in the body similar to the following. The result includes the two component inventory counts, one for the stockable variation measured in bottles and the other for the sellable-only variation measured in glasses. The stockable variation count (24
bottles) is the physical count. The sellable-only variation count (120
glasses) is derived from the stockable variation count based on the specified stock conversion of 1 bottle = 5 glasses
.
{
"counts": [
{
"catalog_object_id": "IUD2QMXX4K62W35HW5CVQGL6",
"catalog_object_type": "ITEM_VARIATION",
"state": "IN_STOCK",
"location_id": "SNTR5190QMFGM",
"quantity": "120",
"calculated_at": "2021-06-11T17:23:40.6115Z",
"is_estimated": true
},
{
"catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
"catalog_object_type": "ITEM_VARIATION",
"state": "IN_STOCK",
"location_id": "SNTR5190QMFGM",
"quantity": "24",
"calculated_at": "2021-06-11T17:23:40.6115Z"
}
],
"changes": [
{
"type": "ADJUSTMENT",
"adjustment": {
"from_state": "NONE",
"to_state": "IN_STOCK",
"location_id": "SNTR5190QMFGM",
"catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
"catalog_object_type": "ITEM_VARIATION",
"quantity": "10",
"occurred_at": "2021-06-11T17:12:00.4125Z",
"source": {
"product": "EXTERNAL_API",
"application_id": "sq0ids-hLgkXFJ58T_vJI5g1Dpoww",
"name": "HelloCustomers"
}
}
}
]
}
With the wine fully stocked, the seller can begin to take orders. Suppose the first order involves one bottle of the wine. This should decrement the inventory count of the stockable variation by one unit (bottle).
The following example request shows a call to the BatchChangeInventory
endpoint on the stockable variation (PMUUU2EFXNRBKTUAMTC5SQTZ
) to adjust the inventory accordingly:
Batch change inventory
Note
In the Virtual Terminal in the Square Dashboard, the previous request corresponds to taking a payment for one bottle of wine.
The successful request returns a 200 OK
response with the payload similar to the following. The quantity of the stockable variation (PMUUU2EFXNRBKTUAMTC5SQTZ
) is now reduced by 1
(bottle) to become 23
(bottles). The quantity of the sellable-only variation (IUD2QMXX4K62W35HW5CVQGL6
) is reduced by 5
, based on the specified stock conversion, to become 115
.
{
"counts": [
{
"catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
"catalog_object_type": "ITEM_VARIATION",
"state": "IN_STOCK",
"location_id": "SNTR5190QMFGM",
"quantity": "23",
"calculated_at": "2021-06-11T17:51:51.6115Z"
},
{
"catalog_object_id": "IUD2QMXX4K62W35HW5CVQGL6",
"catalog_object_type": "ITEM_VARIATION",
"state": "IN_STOCK",
"location_id": "SNTR5190QMFGM",
"quantity": "115",
"calculated_at": "2021-06-11T17:51:51.6115Z",
"is_estimated": true
}
],
"changes": [
{
"type": "ADJUSTMENT",
"adjustment": {
"from_state": "IN_STOCK",
"to_state": "SOLD",
"location_id": "SNTR5190QMFGM",
"catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
"catalog_object_type": "ITEM_VARIATION",
"quantity": "1",
"occurred_at": "2021-06-11T17:50:00.6115Z",
"source": {
"product": "EXTERNAL_API",
"application_id": "sq0ids-hLgkXFJ58T_vJI5g1Dpoww",
"name": "HelloCustomers"
}
}
}
]
}
Now, another customer orders two glasses of wine. To update the inventory to account for this transaction, call the BatchChangeInventory
endpoint on the sellable-only variation (IUD2QMXX4K62W35HW5CVQGL6
), specifying the quantity 2
.
This is shown in the following example request:
Batch change inventory
Note
In the Virtual Terminal in the Square Dashboard, the previous request corresponds to taking a payment for two glasses of wine.
The successful request returns a 200 OK
response with the payload similar to the following. The quantity of the stockable variation (PMUUU2EFXNRBKTUAMTC5SQTZ
) is now further reduced by 2/5
to become 22.60000
. The quantity of the sellable-only variation (IUD2QMXX4K62W35HW5CVQGL6
) is further reduced by 2
to become 113
.
{ "counts": [ { "catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ", "catalog_object_type": "ITEM_VARIATION", "state": "IN_STOCK", "location_id": "SNTR5190QMFGM", "quantity": "22.60000", "calculated_at": "2021-06-11T17:56:01.4135Z" }, { "catalog_object_id": "IUD2QMXX4K62W35HW5CVQGL6", "catalog_object_type": "ITEM_VARIATION", "state": "IN_STOCK", "location_id": "SNTR5190QMFGM", "quantity": "113", "calculated_at": "2021-06-11T17:56:01.4135Z", "is_estimated": true } ], "changes": [ { "type": "ADJUSTMENT", "adjustment": { "id": "YUGSU46HZJIKV2TTXU77E4Q4", "from_state": "IN_STOCK", "to_state": "COMPOSED", "location_id": "SNTR5190QMFGM", "catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ", "catalog_object_type": "ITEM_VARIATION", "quantity": "0.40000", "occurred_at": "2021-06-11T17:52:00.6115Z", "created_at": "2021-06-11T17:52:00:00.1112Z", "source": { "product": "EXTERNAL_API", "application_id": "sq0ids-hLgkXFJ58T_vJI5g1Dpoww", "name": "HelloCustomers" }, "adjustment_group": { "id": "adjGrp_4GH4NVSK6UFHJUI5", "from_state": "IN_STOCK", "to_state": "SOLD" } } }, { "type": "ADJUSTMENT", "adjustment": { "id": "UQ4TDTMP7IYSWBD2WMUA4YMO", "from_state": "COMPOSED", "to_state": "SOLD", "location_id": "SNTR5190QMFGM", "catalog_object_id": "IUD2QMXX4K62W35HW5CVQGL6", "catalog_object_type": "ITEM_VARIATION", "quantity": "2", "occurred_at": 2021-06-11T17:52:00.6115Z", "created_at": "2021-06-11T17:52:00:00.1112Z", "source": { "product": "EXTERNAL_API", "application_id": "sq0ids-hLgkXFJ58T_vJI5g1Dpoww", "name": "HelloCustomers" }, "adjustment_group": { "id": "adjGrp_4GH4NVSK6UFHJUI5", "root_adjustment_id": "UQ4TDTMP7IYSWBD2WMUA4YMO", "from_state": "IN_STOCK", "to_state": "SOLD" } } } ] }
Adjusting the inventory on the sellable-only variation involves two separate adjustments:
- The inventory adjustment on the stockable variation from the
IN_STOCK
state to theCOMPOSED
state. - The inventory adjustment on the sellable-only variation from the
COMPOSED
state to theSOLD
state.
The two component inventory adjustments are included in an adjustment group that represents a single inventory change event transitioning from a representative from_state
of IN_STOCK
to a representative to_state
of SOLD
.
This behavior is different from the inventory change on a stockable variation.