Stock and pre-order settings are not part of the product. Each variant has an inventory item (one per location when the store has several), and the calls below change it without a product revision or a variants array. "Mark X in stock", "add 2 units", "set every product to 1 in stock", "stop tracking inventory" and "allow pre-orders for X" all use them. To give stock to variants that a product update has just created, use Set Stock for New Variants in Update Product with Options (Catalog V3).
idA request that names the product and the change ("add 2 units to the Fertile Eggs", "mark the Tote Bag out of stock") is the user's confirmation. Ask first when:
Every call in this recipe is complete and was run as written: send it without looking up its schema first.
Lookups lag behind a new product. Search Products, the product.variantSku filter and the product object on inventory items can miss a product created in the last seconds (on a site set up minutes ago, longer). Get Product and Query Products read the catalog itself and see it at once. So, in the same execution: when a lookup returns nothing for a product that should exist, wait 3 seconds and send it again, up to 3 times, before you try the next fallback; never tell the user a product or SKU does not exist until the Query Products fallback below also found nothing.
By product name. Users often put the variant in the product name ("the red Eval Tee", "Large Hoodie"). Search for the product name without the choice word, and keep the choice (Red, Large) to select the variant afterwards. Resolve the product with an exact, case-insensitive name filter:
When that returns nothing, the user may have given part of the name: search { "search": { "search": { "expression": "Product name", "fields": ["name"], "mode": "AND" } } } and pick a clear match from products[].name. Search can also miss a product created in the last few seconds: if both return nothing, list the products with POST https://www.wixapis.com/stores/v3/products/query and { "query": { "cursorPaging": { "limit": 100 } } } and match name in code, ignoring case. Then query the inventory items by the products[].id:
By SKU. The inventory filter { "product.variantSku": "TEE-RED-L" } (case-sensitive) is the fast path, but it and the Search Products SKU filter both miss a product created seconds ago. The SKU itself is on product.variantsInfo.variants[].sku in a default Get Product response, which is current at once. Run this lookup as written, in the same execution as the update:
item then holds the id, revision and trackQuantity that Step 2 needs. Tell the user a SKU does not exist only when this lookup returns NO_VARIANT_WITH_THIS_SKU. Do not search a SKU as free text on Search Products: it splits the SKU at - and can match the whole catalog.
Each inventoryItems[] entry has:
| Field | What it holds |
|---|---|
id, revision | Needed by Bulk Update (revision as returned, a string) |
productId, variantId, locationId | Which variant and location the item belongs to |
product.name, product.variantName, product.variantSku | variantName is the choice name (such as Black), or the product name for a product without options |
trackQuantity | true: the item has quantity. false: the item has inStock (true or false) and no quantity |
availabilityStatus | IN_STOCK, OUT_OF_STOCK or PREORDER |
preorderInfo | enabled, message, limit |
To select a named variant, match product.variantName to the choice. For a few seconds after a product is created, its inventory items can come back without the product object; then map choices to variantId with Get Product. This lookup handles both cases, in the same execution as the search and the update:
Choose the body from the request and from the item's trackQuantity:
| Request | Tracked item (trackQuantity: true) | Untracked item (trackQuantity: false) |
|---|---|---|
| Set a quantity ("set to 10", "1 in stock") | Bulk Update, "quantity": 10 | Bulk Update, "quantity": 10 — tracking starts |
| Add or remove units ("add 2", "sold 1") | Bulk Increment or Bulk Decrement By Variant And Location — never read the quantity and set a sum | Fails with INVENTORY_QUANTITY_NOT_TRACKED: ask how many are in stock and set that quantity |
| Mark out of stock | Bulk Update, "quantity": 0 — tracking stays on | Bulk Update, "inStock": false |
| Mark in stock, no number given | Ask how many units are in stock, then set quantity | Bulk Update, "inStock": true |
| Stop tracking inventory | Bulk Update, "inStock": true (or false to keep it unavailable) | Nothing to change |
Send inStock to a tracked item only when the user asks to stop tracking: it ends tracking and the quantity is gone.
Bulk Update Inventory Items — POST https://www.wixapis.com/stores/v3/bulk/inventory-items/update, up to 1000 items, each with its id and the revision from Step 1:
Add or remove units — Bulk Increment Inventory Items By Variant And Location, POST https://www.wixapis.com/stores/v3/bulk/inventory-items/increment-by-variant-and-location, up to 300 items. It takes the productId and the variant's id from Search Products and Get Product, so it needs no inventory item lookup and no revision; leave out locationId for the store's default location. For a product without options, the one variant in GET https://www.wixapis.com/stores/v3/products/{productId} → product.variantsInfo.variants[0].id is the one to change. To remove units, send the same shape to https://www.wixapis.com/stores/v3/bulk/inventory-items/decrement-by-variant-and-location with decrementData and decrementBy.
results[].item.quantity is the new total (3 + 2 = 5). When you already hold the inventory item id, https://www.wixapis.com/stores/v3/bulk/inventory-items/increment with { "incrementData": [ { "inventoryItemId", "incrementBy" } ] } does the same.
These bulk calls return 200 even when items fail. Check bulkActionMetadata.totalFailures and each results[].itemMetadata.success. A failed item has results[].itemMetadata.error.code:
| Code | Meaning | Fix |
|---|---|---|
INVALID_REVISION | The revision is stale | Query the item again (Step 1) and resend it with the new revision |
INVENTORY_QUANTITY_NOT_TRACKED | Increment or decrement on an untracked item | Ask how many units are in stock and set quantity |
Confirm the new state from results[].item.quantity, inStock, trackQuantity and availabilityStatus. The product's inventory.availabilityStatus in Search and Query Products reflects the change at once.
Pre-order lets customers buy a variant after its stock reaches zero. It is set per inventory item in preorderInfo, with Bulk Update Inventory Items (several variants) or Update Inventory Item (one).
limit (how many units can be pre-ordered after stock reaches zero) works only on a tracked item. On an untracked item, tell the user that quantity tracking will be turned on, ask for the current quantity, and send it with the limit.Enable pre-orders on several variants — Bulk Update Inventory Items:
With a limit, on an item that was not tracked (the quantity is the one the user gave):
With 10 in stock and a limit of 50, customers can order up to 60 units in total: 10 from stock and 50 as pre-orders.
One variant — Update Inventory Item, PATCH https://www.wixapis.com/stores/v3/inventory-items/{inventoryItemId}:
Disable pre-orders — the same call with "preorderInfo": { "enabled": false, "limit": null }.
After the change, confirm it from the returned item's preorderInfo and availabilityStatus. If the product description mentions availability, offer to update it.
Last updated: 4 November 2026