Units
One tracked physical item of a Product — with its own location, bin, status, lot, price, and complete movement history. Units are what you check out, sell, transfer, count, and consume.
Product vs. Unit, in one line: a Product is the catalogue entry; a Unit is one tracked item of it.
Looking for measurement units like "lb", "gal" or "ea"? That's Units of Measure.
A unit is one physical item of a Product. If the Product is "Cordless Drill, 18V," then each actual drill — sitting in a bin, checked out to a tech, or in transit between warehouses — is a unit. Units carry their own location, bin, status, optional lot and expiration, and a complete movement history, while inheriting their name, price, and usage type from the Product.
Lot numbers, expiry dates and being able to answer "where did this batch go" are what units are for. For the practice — how lot codes are read and what a recall actually takes — see lot traceability and recalls. This page is how units work here.
Naming note: these records are Units in the app and in the REST API alike —
/api/v1/inventory/units, referenced from other resources asunit_id. Don't confuse them with Units of Measure (lb,gal,ea), which are measurement labels served from/api/v1/inventory/units-of-measure.
Everything you do with stock happens to units: you check them out, sell them, transfer them, mark them used, hold them, and count them. The Product just says what they are.
How units come into being #
Units are created several ways:
- Receiving a purchase order — purchasing creates units as stock arrives, landing them in the location's receiving bin.
- Manually — Inventory → Units → New Unit, useful for opening balances or stock that didn't come through a PO. You can create several identical units at once with the quantity to create field.
- Building from existing inventory — when the Product is composite, creating an unit can consume its component units, which are marked used automatically and linked to the new unit.
- Manufacturing — work orders produce finished units from components.
When you create a unit you choose its Product (required, and it must come first), optional name override, vendor, location and bin, starting status, barcode, and — if the category tracks them — a lot number and expiration date. Pricing can be Each, Total, or Inherit from Product.
Add Stock on a product's page does the same job from the other end, and asks the two questions a delivery answers: which vendor it came from, and the delivery note / packing slip number on the paperwork. When the product's Vendors tab lists exactly one supplier, that supplier is filled in for you. Both end up on every movement the delivery writes, so the Movement Log can say whose goods arrived and against which delivery — which for a business without the purchasing module is its entire receiving audit trail.
Creating a unit through the API is the same
stock-in event and writes the same movement, and POST /api/v1/inventory/units
takes the same facts: vendor_id, reference_number for the delivery note or
packing slip, and an adjustment_reason. Leave bin_id out and the unit lands
in the location's nominated receiving bin, the same shelf the receiving screens
would have offered. The one difference is accounting: stock booked in through
the API is not posted to QuickBooks as a journal
entry, because a script loading stock is not the same act as a person deciding
to adjust it.
Unit statuses #
A unit is always in exactly one status, shown as a badge in the list:
- In Stock — sitting in a bin, available.
- Checked Out — a Returnable unit is out with a person; it has an active checkout record.
- On Hold — reserved for something (an appointment, a sales order, etc.) and not available to others.
- In Transit — moving between locations on a transfer.
- Out of Stock — nothing left: sold, used up, consumed into a build, or written off with Discard.
- Discontinued — no longer carried.
- Missing — nobody can find it. The record exists; the thing does not.
Statuses change as a side effect of the actions below — you rarely set them by hand, though a bulk Change Status action exists for corrections.
Missing is worth separating from its neighbours, because all the others describe stock whose whereabouts you know. Out of Stock is a unit you consumed, sold or wrote off with Discard, Discontinued is a product you chose to stop carrying, and On Hold means somebody reserved it and it is still on the shelf. Missing is the one that says the tool walked out of the building. It is set by answering No — it is missing on a stock count, and a missing unit is dropped out of its bin, counts as zero stock on hand, carries no value on the valuation report, and can never be reserved, allocated, sold, loaned or rented to anybody.
Actions on a unit #
The actions available depend on the Product's usage type and the unit's current status. From the unit list (or the unit's own page):
- Check Out — Returnable, In Stock only. Hand the unit to a staff user, customer, or contact. A due date is required — it's the day the unit is expected back — and notes are optional. Status becomes Checked Out. See Asset Checkout.
- Check In — Checked Out only. Bring it back into a destination bin; status returns to In Stock and the checkout is closed.
- Mark as Used — Consumable, In Stock only. Record a percentage consumed; the unit's remaining quantity drops by that much, and a unit that hits 0% is emptied out of its bin.
- Transfer — move the unit to a different location and/or bin. See transfers.
- Hold / Release — reserve a unit for an appointment or order, then release it back to stock.
- Discard & Write Off Stock — the unit is gone: damaged, expired, scrapped or spoiled. It goes Out of Stock at zero quantity, leaves its bin, is released from any order or appointment holding it, and can no longer be checked out, sold, rented or counted; its cost comes off the valuation as a write-off. Nothing is deleted — the unit and its history stay on file, and the write-off is added to the movement log with your name and reason against it. Putting the stock back is a deliberate act, not a correction: you set the unit In Stock again, and that is recorded too. Needs the Discard Units permission (see roles and permissions), which a role can be denied while still being able to edit units.
- Donate — give the unit away, with a recorded reason.
- Mark as Found — Missing only. It turned up. Say which bin it turned up in and the unit goes straight back to In Stock at full quantity. Losing and finding things is ordinary in a stockroom, so this is a normal move rather than a data repair.
Each of these writes a movement (below), so the history always explains how the unit got to its current state.
Bulk actions #
Select multiple units in the list to Bulk Transfer, Bulk Check Out (eligible units only — ineligible ones are skipped with a count), Discard & Write Off Stock with a reason (every selected unit goes Out of Stock, as above; the action is only offered to a role holding Discard Units), or Bulk Change Status.
Remaining quantity #
Each unit tracks a remaining quantity as a percentage of one full unit —
handy for partially-used consumables (a half-full drum reads 50%). The form
offers quick-set buttons (100 / 75 / 50 / 25 / 0%) and shows the real amount
alongside, computed from the Product's unit size (e.g. 50% × 500 ml = 250 ml).
Returnable equipment is tracked whole — it's either out or in, not partially
used.
Lots, expiration, location, and bins #
- Lot number and expiration date appear on the unit only when its Product's category is set to track them — keeping the form clean for units that don't need them.
- Location and bin say where the unit physically is. Setting a bin sets the location automatically. In single-location accounts the location field is hidden. Bins are hierarchical, so a bin shows its full path (e.g. Warehouse A → Rack 5 → Shelf 3), with the bin's name in front of it where one has been given (Power Tools Rack A (Warehouse A → Rack 5 → Shelf 3)).
- A bin is required for In Stock units — stock nobody can walk to is not really in stock. Adding stock by hand pre-fills the location's default receiving bin — which every location has, named Receiving, from the moment it is created — and changing the location re-points it at that location's own. So most of the time there is nothing to choose. If the shelf you want does not exist yet, + New Bin on the field creates it at the selected location without leaving the form (subject to the create inventory bins permission). Units that are not in stock (checked out, on order, discarded) need no bin.
- Custom fields inherited from the category appear at the bottom of the form and on the unit's page.
Movement history #
Every meaningful event on a unit is recorded as a movement, visible on the Movements tab of the unit's page. A movement captures the type, the amount and units involved, the source and destination location/bin, the reference (the record it came from — a purchase order, the vendor a by-hand stock-in came from, the checkout a returned unit closes), a delivery note / packing slip number where one was given, and any notes. Movement types include Purchase, Sale, Transfer, Check Out / Check In, Used, Adjustment, Discard, Donation, Return, Material Consumed, and Manufactured. Together they form an unbroken audit trail — nothing changes a unit's location, status, or quantity without leaving a movement behind.
Adjustment reasons #
Most movement types say why the stock moved simply by being what they are: a Purchase came from a vendor, a Sale went to a customer. Adjustment is the exception — it's the type for a change with no document behind it, so on its own it says only that somebody changed the number.
An adjustment can therefore carry a reason:
| Reason | What it means |
|---|---|
| Goods received | A delivery arrived from a supplier and you're booking it in. |
| Found | There's more here than the system said, or something lost has turned up. |
| Missing | There's less here than the system said, and nobody can account for it. |
| Opening balance | Stock you already owned, being entered for the first time. |
| Damaged | The goods are no longer sound and can't be sold or used. |
| Correction | Somebody keyed the wrong number. Nothing physical changed. |
The log then reads Adjustment — Opening balance rather than a bare Adjustment, and you can filter and group by reason to see how much of your shrinkage is loss, damage, or simply mis-keying.
Goods received is there because not every business has the purchasing module. Receiving against a purchase order writes a Purchase movement carrying that order and needs no reason at all — but without that module there are no purchase orders, so every delivery you ever take is booked in by hand, and the reason list has to have a word for it. Picking Found for a delivery would put something untrue in the record.
Reasons are filled in for you where the action already knows the answer: marking a unit missing records Missing, finding it again records Found, and posting a stock count records Found or Missing per line depending on which way the variance went. You're only asked when the system can't know — entering stock by hand, or changing status in bulk — and the reason is always optional.
The Checkouts tab shows the unit's checkout history — who had it, when it left, when it came back, due dates, and overdue flags.
Counting and accuracy #
When you reconcile what's recorded against what's physically on the shelf, the adjust action posts the difference as an Adjustment movement so the remaining quantity matches reality and the history stays honest. See stock counts.
The unit list #
The unit list (Inventory → Units) shows each unit's Product/name, location, bin, status, and remaining %. Filter by category, location, bin, or status, and toggle In stock only to focus on what's actually available.
Doing it from the API #
# List units
curl "https://your-domain.com/api/v1/inventory/units" \
-H "Authorization: Bearer $TOKEN"
# Check a unit back in to a bin
curl -X POST "https://your-domain.com/api/v1/inventory/units/{item}/check-in" \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"bin_uuid": "..."}'