Inventory & warehouse
Know what you can actually promise.
Every stock system can tell you what is on the shelf. The number that decides whether you can take an order is a different one — what is on the shelf minus what is already spoken for — and in Oneop that subtraction is an invariant enforced at the write, not a column rendered in a table. Five different code paths change stock, and every one of them locks the row before it reads the number it is about to change.
Multiple warehouses, bin locations, lots and serials, variants, transfers and cycle counts sit on top of it. Purchase orders come in, sales orders go out, and each change leaves a movement row that records what the quantity and the value were before and after.
No credit card. Free plan, 2 seats.
5
Stock write paths, every one under a row lock
1
Transaction per shipment — stock, COGS, invoice, status
4
Movement types, each recording quantity and value before and after
3
Cost sources tried before a purchase line is refused
9
Carrier adapters, rating against your own accounts
One unit, from received to shipped, without a number ever being estimated.
A product exists. An order commits part of it. What you can promise drops by exactly that much, immediately, before anyone else can read the old number. Fulfilment consumes the commitment rather than the shelf a second time. And every one of those steps leaves a row behind.
- Receiving is partial-safeEach purchase-order line tracks what was ordered against what has already arrived. Receiving more than was ordered is rejected with a 422, not clamped down to the ordered quantity — the earlier behaviour silently absorbed the difference.
- Reservation shares the order's transactionConfirming ORD-2398 reserves stock inside the same commit that creates the order. A failure halfway through rolls both back together, so there is no hold left behind for an order that does not exist.
- Shipping is one transactionSHP-812 locks the sales-order row, re-validates that it is still shippable, decrements stock, posts cost of goods sold, raises the invoice and advances the status together. A crash anywhere rolls all of it back.
- The movement row is the recordNot a running total you have to trust. Each row states the quantity and the value before and after, and what caused it — so the history is readable rather than reconstructed.
What a stock column does not do
Four things below. Each one is a mechanism you can check, not a capability we claim.
Fixed point 1
The subtraction happens under a lock, not in the interface
Reservation opens a transaction, locks the stock row, computes what is available, and refuses the request if the answer would go negative. Because the lock is taken before the read, a second request cannot see the same availability as the first — it waits, then reads the number the first one left behind. Five write paths change stock and all five behave this way, including transfers, which lock both ends in a consistent order so two transfers running in opposite directions cannot deadlock.
Reserving and shipping are different operations
- Reserving checks availabilityOn-hand minus reserved. It cannot commit stock another order already holds.
- Shipping checks on-handIt consumes a commitment that already exists, so it does not subtract twice.
And the refusal is a real error
- An over-reservationFails at the write with the requested and the available quantity named in the error.
- Every surfaceImports, bulk edits and integration syncs go through the same write path, so none of them routes around it.
| Event | On hand | Reserved | Available |
|---|---|---|---|
| Opening positionNH-MED-001 in your main warehouse | 17 | 0 | 17 |
| ORD-2398 confirmedReserves 1 — inside the order's own transaction | 17 | 1 | 16 |
| SHP-812 shippedIssues the reserved unit and releases the hold together | 16 | 0 | 16 |
| A second order for 17Rejected at the write with WH_RESERVE_FAIL, not greyed out in the interface | — | — | Refused |
Note the third row: shipping moves on-hand without moving what you can promise, because the promise was already made and accounted for.
Fixed point 2
Every change is a row that records before and after
There are four kinds of stock movement — a receipt, an issue, a transfer and an adjustment — and each one writes a row carrying the quantity and the value as they stood before the change and as they stand after it, together with what caused it. A balance you can only read forwards is a balance you have to trust. This one you can read backwards.
Shipping is where that history meets the accounts. It posts cost of goods sold as a balanced journal entry inside the same transaction that decrements the stock, so the two records are written or not written together. Receiving a purchase order raises the accounts-payable bill. For inventory orders the invoice is deliberately deferred to the shipment, so you never invoice goods that have not left the building.
Each movement row carries
- Quantity before and afterPlus value before and after, so a revaluation is as visible as a physical move
- Its causeThe document that produced it, by type and id — not a free-text note
- Its ledger linkWhere a journal entry was posted, the movement names it
And the ledger it posts to
- Refuses to unbalanceDebits equal credits is enforced at the database, not by the caller
- Reverses cleanlyVoiding an invoice reverses the entry and releases the reservation
- One set of booksThe same ledger, not a finance sidecar — how the ledger works
Ship — one transaction
A crash anywhere rolls all three back — never a partial ship.
Void the invoice — the mirror, also one transaction
Fixed point 3
Replenishment refuses to guess
A reorder point can be set on the item or overridden per warehouse, and one effective threshold is resolved from those — the override when there is one, the item value otherwise — so the stock view, the product record and the low-stock alert cannot disagree about when to reorder.
Forecasting is Holt’s linear trend method over your own issue movements: 91 days back, 8 weeks forward, a level component and a trend component. That is statistics, and the page says so because the difference matters when you are deciding whether to trust it.
When it comes to writing a draft purchase line, three cost sources are tried in order — the last price you paid this vendor, the last price you paid any vendor, then the item’s weighted-average book cost. If none of them yields a positive cost, the line is not created and the run reports it as skipped with the reason. A zero-cost line would book zero cost of goods sold when the item eventually sold, which is a wrong number wearing the shape of a right one.
Four independent gates stand between a low stock level and a purchase order reaching a supplier, shown on the right. Being below the reorder point is the only one that is on by default.
Also derived from the same movement history
On-demand runs skip the sweep entirely — always available.
Fixed point 4
Nine carriers, your accounts, and a hard stop when it is not configured
Three multi-carrier aggregators — EasyPost, Shippo and ShipStation — plus FedEx, UPS and USPS directly, plus TCS, Leopards Courier and PostEx for the Pakistan market. You connect your own carrier accounts, so rate shopping returns the rates you negotiated rather than list prices, and buying a label buys a real one with a real tracking number.
Buying is idempotent
- Under a row lockA duplicated click cannot buy and pay for a second label
- Rates are liveEach connected carrier is asked for its own quote at the moment you ask
And it fails closed
- No origin, no rateRating and purchase both refuse until your ship-from address is set
- No invented defaultAn earlier build substituted a placeholder warehouse address. A correctly rated label for the wrong origin is worse than an error.
Connected with Oneop
Six teams, one number, no reconciliation step
Sales quotes against what can be promised, support answers the customer asking where it is, fulfilment picks the unit that was committed, finance receives the cost of goods sold that shipping posted, reporting reads the movement rows, and automation acts on the reorder threshold. Not six systems agreeing after a sync — one record they all read.
- CRMCustomer and commercial context follows the work.
- Help deskSupport sees the customer, commercial and operational history.
- ReportingEvery module is already a reportable dataset, so nothing has to be exported to be measured.
- FinanceOperational transactions continue into financial records.
- AutomationA trigger in one module can act in another without an integration between them.
The other 6 modules sit on the same record, and reach Inventory & warehouse the same way:
- Live chatConversations become part of customer context.
- SequencesOutreach works from CRM and customer context under controlled automation.
- Project managementSold work becomes delivery without rebuilding customer context.
- AI chatbotAI responds using permitted business context.
- AI agentsAI acts on the same records people do, under limits that are published rather than described.
- AI governanceWhatever AI touches in any other module is metered on the same path first.
Beyond the four
Bins, zones and cycle counts
Locations inside a warehouse rather than one bucket per site, and counts that post as adjustment movements — so a correction is part of the history, not a silent overwrite of it.
Lots, batches and serials
Track a unit to the batch it came from or the serial it carries, for recalls, expiry and warranty. Available from Pro, alongside returns.
Returns and RMAs
Draft, approved, received, refunded — with a credit note at the end and per-line received and rejected states, because a return is rarely all or nothing.
Purchase orders with landed cost
Freight and duty land on the item cost rather than disappearing into an expense account, so margin is calculated against what the goods actually cost you.
Transfers between warehouses
Both ends locked in a consistent order, a movement row written at each, and availability at the destination updated as part of the same commit.
Variants and product structure
Size and colour are separate stock records, not one product with a note. Navy Hoodie Medium is a SKU that can be reserved, shipped and counted on its own.
Where stock meets the rest of your stack
The storefronts that create the orders, the accounting and payment rails the movements post into, and the three aggregators that reach the carriers. The first five are native integrations with their own pages; the last three are carrier connections you configure inside Inventory, which is why they are not on the integrations directory.
See all integrations- Shopify
- WooCommerce
- WordPress
- QuickBooks
- Stripe Connect
- EasyPost
- Shippo
- ShipStation
For the technical evaluator
Available stock is on-hand minus reserved. Nothing can sell what is already promised.
That is the one sentence this module is built to keep true, and it is kept true at the write rather than in a nightly reconciliation.
Locks, movements and what each write path actually does
Five functions change stock. Each opens a transaction and selects the warehouse stock row FOR UPDATE before reading anything it intends to modify, which is what makes the read-then-write pair indivisible. Issuing takes stock out. Issuing against a reservation takes it out and releases the hold in the same step. Adjusting corrects a count. Transferring moves between two rows, locked in a consistent order so opposing transfers serialise instead of deadlocking. Reserving commits stock without moving it.
Reserving and issuing test different quantities, and conflating them is the classic way a system double-counts. Reserving compares the request against on-hand minus reserved and fails with a named error if it does not fit. Issuing against an existing reservation compares only against on-hand, because the commitment was already accounted for when it was made; it then releases the hold clamped so the reserved figure cannot be driven negative by an out-of-order call.
A reservation can join a caller's transaction rather than opening its own. That is how confirming a sales order reserves stock inside the order's own commit: if anything later in the order creation fails, the hold disappears with it. There is no compensating cleanup job, because there is nothing left to clean up.
Movements are typed — receipt, issue, transfer, adjustment — and every row records the quantity and the value as they stood before and after, the document that caused it, and the journal entry it posted where there was one. Reporting and valuation read those rows rather than a maintained balance, so a figure on a report can always be traced back to the events that produced it.
Shipping a sales order is the one flow that is atomic end to end across modules. It locks the order row, re-checks that the order is still in a shippable state — the loser of a race aborts there rather than shipping twice — then writes the shipment, updates the lines, attaches any service lines exactly once, decrements stock, posts the cost of goods sold and raises the invoice. One commit, or none of it.
Everything above is tenant-scoped at the data layer. Stock rows, movements, orders and shipments all carry the workspace they belong to, and no query crosses that boundary.
What it costs
Stock, warehouses and fulfilment are on every plan including Free — what the plan changes is size and depth. Products, warehouses and carrier connections have per-plan ceilings. Purchase orders unlock at Starter; returns, serial numbers and lot tracking at Pro. The reservation guarantee itself is not a plan feature and never has been.
See full pricing| Plan | Products | Warehouses | Carriers | Purchase orders | Returns & lots |
|---|---|---|---|---|---|
| Free $0 | 20 | 1 | 1 | Not included | Not included |
| Starter $19 | 250 | 1 | 2 | Included | Not included |
| Pro $59 | 2,500 | 3 | 5 | Included | Included |
| Business $129 | 10,000 | 10 | 15 | Included | Included |
Frequently asked
What stops two orders from selling the same last unit?
The order in which the database does the work. Reservation opens a transaction and takes a row-level lock on the stock row before it reads anything, then computes available as on-hand minus reserved, then writes. The second request blocks on that lock until the first commits, so it reads the updated numbers rather than the stale ones, and is rejected with an insufficient-stock error. The check and the write are not separable, which is what makes the guarantee hold under concurrency rather than only under light load.
Do I have to turn inventory on?
No. Stock, warehouses and fulfilment are on from your first login on every plan, including Free — there is no module switch. What changes with the plan is size and depth: how many products, warehouses and carrier connections you can have, whether purchase orders are available (Starter and up) and whether returns, serial numbers and lot tracking are (Pro and up). The one genuinely opt-in mechanism is the automatic daily replenishment sweep; on-demand runs are always available.
Is the demand forecasting AI?
No, and we will not call it that. It is Holt’s linear trend method — double exponential smoothing with a level and a trend component — fitted to your own historical issue movements, looking 91 days back and projecting 8 weeks forward. No language model is involved anywhere in it. Naming the method is more useful to you than the label would be, and it means you can check whether it suits your demand pattern.
What happens when Oneop does not know what something costs?
It refuses to write the line. Automatic replenishment tries three cost sources in order — the last price you actually paid this vendor, the last price you paid any vendor, then the item’s weighted-average book cost. If none of them yields a positive cost, the draft line is not created and the run reports it as skipped with the reason. A zero-cost line would book zero cost of goods sold when the item eventually sold, which is a wrong number that looks like a right one.
Which carriers can I use, and do I keep my rates?
Nine adapters: EasyPost, Shippo and ShipStation as multi-carrier aggregators; FedEx, UPS and USPS directly; and TCS, Leopards Courier and PostEx for the Pakistan market. You connect your own carrier accounts, so rate shopping quotes your negotiated rates rather than list prices. Rating and label purchase both refuse to run until your ship-from origin is configured — an earlier version substituted a placeholder address, which is how a correctly rated label gets bought for the wrong origin.
How does stock reach the accounts?
Shipping a sales order runs as one transaction: it locks the order row, decrements stock, posts cost of goods sold as a balanced journal entry, raises the invoice and advances the status together, so stock and the ledger cannot disagree about a shipment that half-happened. Receiving a purchase order creates the accounts-payable bill. For inventory orders, invoicing is deliberately deferred to shipment, so you never invoice goods that have not left the building. The posting lands in the same ledger, not an export.
Can I move stock between warehouses safely?
Yes. A transfer locks both the source and the destination row, in a consistent order so two transfers running in opposite directions cannot deadlock, and writes a transfer movement at each end. Like every other stock change it records quantity and value before and after, so the history reads as a sequence of events rather than as a current balance you have to trust.
See it against your own stock.
The free plan covers one warehouse and 20 products. Or book a walkthrough and we will show you the reservation lock refusing an order, the ship transaction posting cost of goods sold, and the movement row that records both.
Free forever · 2 seats · No credit card