Skip to main content

Place & manage stock holds

A stock hold sets aside on-hand units of a product at a warehouse so nothing else can claim them — no sales order can allocate them and no other hold can double-book them. Use one to quarantine damaged goods, park stock for quality control, ring-fence inventory for a promotion, or reserve units for a specific customer without raising an order. A hold moves units into the On Hold bucket, which lowers Available without changing On Hand. This guide covers placing a hold (one product or a batch), browsing the holds list, releasing or deleting holds, and editing a hold that's still active.

Holds move stock between buckets — they don't post movements

Placing a hold shifts units from Available to On Hold; it doesn't create an inventory movement or touch FIFO layers or COGS. On Hold is a first-class stock state alongside On Hand, Available, Allocated, and Non-Sellable — see Stock states and the stock states reference. A hold is separate from an allocation: an allocation commits stock to an order line, a hold sets it aside for no order at all.

Before you begin

RequirementWhy it's needed
Inventory access (the inventory scope)The Stock Holds page, its metric cards, filters, and detail view all sit behind read/write access to inventory.
Adjust inventory permission (inventory.adjust)Required to create, edit, release, or delete a hold. Without it you can view the list but not change it.
Export inventory permission (inventory.export)Required only to export the holds list.
On-hand, available stockA hold can only reserve units that are on hand and not already allocated or held. The net-available check runs under a database lock at save time.

Open the list at Inventory → Stock Holds (route /inventory/stock-holds).

"Reservation" in the API means a stock hold

The underlying API routes and some messages use the word reservation — for example, "Inventory reservation created successfully." It's the same thing the UI calls a stock hold.

Reserve stock (place a hold)

The Reserve Stock modal handles both a single hold and a batch in one place — add one product for a single hold, or add up to 100 to reserve them together under shared settings.

  1. On Inventory → Stock Holds, click Reserve Stock (top right). On a phone, tap the + button.
  2. Choose the Warehouse (required). It defaults to your default warehouse from inventory settings; the availability figures and the net-available check are all scoped to this warehouse.
  3. Choose a Reason (required). Pick a suggested reason — Quality Control, Customer Hold, Seasonal, Promotional, Internal Use, Damaged, Pending Inspection, Expired / Near Expiry, or Other — or type your own; the field accepts a custom reason.
  4. Set an Expires date (optional). It must be in the future. An expiring hold auto-releases — see When holds expire.
  5. Add Notes. They're optional for most reasons, but required when the Reason is "Other" — the field shows an asterisk and the save is blocked until you fill it in. In a batch, the notes apply to every item.
  6. Add products. Search by SKU, name, or barcode, or click the Browse products icon to pick from the drawer. Each row shows a live availability preview for the chosen warehouse: Avail (available), Alloc (allocated), Rsv (units already on hold), and On Hand.
  7. Enter a Quantity for each row. Quantity must be greater than zero.
  8. Click Reserve Stock.

What you'll see: for a single product, the hold is created and appears at the top of the list; the product's Available drops and On Hold rises by the held quantity. For a batch, a message reports how many were created — for example, "3 reservation(s) created."

How the availability check works

At save time SKU.io locks the product-and-warehouse inventory row and computes net available as:

On Hand − Allocated − existing active holds

Existing active holds are counted live from the holds themselves, not from the cached On Hold figure, so a stale cache can't wave through a hold that would overcommit stock. If your quantity exceeds net available, the hold is rejected with a 422 error whose message states the amount available net of existing holds — for example, "Insufficient available inventory. Requested: 50, Available (net of existing holds): 32." Reduce the quantity or free up stock and try again.

Batch holds: partial success is the norm

In a batch, each item is checked on its own. Items that pass are created; items that fail the availability check are returned as per-item errors and skipped — the successful ones still stand. The whole batch only rolls back if every item fails. After a partial batch, read the summary message and re-add just the items that didn't take.

Browse the Stock Holds list

The list opens on your active holds. Four metric cards sit across the top:

CardShows
Active HoldsCount of holds currently holding stock.
Total Qty HeldTotal units reserved across active holds.
Expiring SoonActive holds whose expiry falls within the next 7 days.
Released (30d)Holds released in the last 30 days.
  • Search — by hold ID, SKU, or product name.
  • Warehouse — a specific warehouse or All.
  • Reason — any reason in use, plus the standard set.
  • StatusAll, Active, Partially Released, or Released. The list defaults to Active.
  • ExpirationAll, Has Expiration, or No Expiration.
  • Advanced filters — build conditions on ID, quantity, reason, created date, expires date, and warehouse.

Columns

ColumnNotes
IDLinks to the hold's detail page.
SKU / Product NameThe held product.
WarehouseWhere the stock is held.
Qty HeldUnits currently on hold.
Qty ReleasedUnits released from this hold so far (accumulates across partial releases).
ReasonThe hold reason.
StatusActive, Partially Released (some units released, some still held), or Released.
NotesCopy to clipboard with one click.
Created By / Created DateWho placed the hold and when.
ExpiresThe expiry date; shows a warning chip when the hold is expiring soon (within 7 days).
Released At / Release ReasonHidden by default; show them from the column picker.

Status is derived, not stored: a hold with released_at set reads Released; a still-active hold that has had units released reads Partially Released; otherwise it's Active.

Open a hold

Click a hold's ID to open its detail page. It has two tabs:

  • Details — product, warehouse, reason, quantity held and released, status, expiry, notes, created-by, and (once released) a Release Information card with released-at, released-by, total released, and the release reason.
  • Activity — the hold's activity log, so you can see every change over its life.

The detail page carries its own Release and Delete actions, the same as the list.

Export

Click Export (in the menu on mobile) to download the list as XLSX or CSV. Export honors your current filters, or you can export just your selected rows. Exporting requires the Export inventory permission.

Release a hold

Releasing returns held units to Available. You can release the whole hold or just part of it.

  1. On the list (or the detail page), click Release on the hold.
  2. In Release Stock Hold, enter a Quantity to release. Leave it blank — or enter the full held quantity — to release everything. The field can't exceed the held quantity.
  3. Optionally add a Release Reason.
  4. Click Release.

What happens:

  • Full release — the hold is stamped with the release time, the releasing user, and the reason; its remaining units move into Qty Released; and its status becomes Released. The units return to Available.
  • Partial release — the hold's Qty Held drops by the amount released, Qty Released rises by the same amount, and the hold stays Active (now Partially Released). You can release more later.

Either way, SKU.io refreshes the inventory cache and dispatches a background job so the freed stock can flow to any waiting backorders — see Work the backorder queue.

You can't release a hold twice

Releasing a hold that's already fully released returns a 422 error ("Reservation has already been released."). If you need to reduce an already-released hold's recorded quantity, that's not a release — the hold is closed.

Release several holds at once

  1. Select holds with their row checkboxes. A bulk-actions bar appears.
  2. Click Release.

Every selected active hold is released in full. Holds already released are skipped, and the confirmation reports both counts — for example, "4 hold(s) released successfully. 1 skipped (already released)." Bulk release doesn't take a per-hold quantity; for a partial release, use the single Release dialog above.

Delete a hold

Deleting removes the hold record entirely. Deleting an active hold also frees its held stock (the same cache refresh and backorder-release job as a release); deleting an already-released hold just removes the record and doesn't free anything again.

  1. Click Delete on the hold (list or detail page), or select rows and click Delete in the bulk-actions bar.
  2. Confirm in the dialog.

What you'll see: a message confirms how many holds were deleted — for example, "1 hold(s) deleted successfully." The single-hold Delete runs through the same path as bulk delete, so the inventory cache is always rebuilt.

Release keeps the record; delete removes it

Release frees the stock but leaves an audited, closed hold you can still find under the Released status. Delete frees the stock (if the hold was active) and erases the record. Prefer Release when you want a paper trail.

Edit a hold

You can change an active hold's quantity, notes, or expiry without releasing and re-creating it. The hold's product, warehouse, and reason are fixed — to move stock to a different product or warehouse, release the hold and place a new one.

  1. Find the hold on the list or open its detail page, then click Edit — the pencil action on the row, or the Edit button on the detail page. (Released holds don't show it.)
  2. In the Edit Stock Hold dialog, adjust the Quantity Held, Notes, or Expires date. Save Changes enables once something has changed.
  3. Click Save Changes.
  • Increasing the quantity re-runs the availability check — but against stock net of other holds, since this hold's own units already count as held. If the increase would overcommit, it's rejected with the same 422 insufficient-stock error.
  • Reducing the quantity is always allowed and frees the difference back to Available, dispatching the backorder-release job so freed units can fill waiting demand.
  • Changing notes or expiry never touches stock. A new Expires date must be in the future.
  • Editing a hold that's already been released returns a 422 error ("Cannot update a released reservation.") — a closed hold can't be edited, which is why released holds don't offer an Edit action.

When holds expire

If you set an Expires date, SKU.io automatically releases the hold once that time passes. An hourly background job sweeps expired holds per tenant and releases each in full with the reason "Auto-released: reservation expired," returning the units to Available exactly as a manual release would. Holds with no expiry stay until you release or delete them.

Next steps

Last verified: