API surface. Stock levels and fulfillment orders (create, read, update, cancel) are REST, for OMSs and platforms. Warehouse execution (allocation, picking, packing, shipping, waves, counts, storage locations and manual movements) is GraphQL Interface.A 3PL, a merchant’s own warehouse or a carrier’s fulfillment arm all answer the same questions: what do we hold, where, in what condition, for whom, and how does an order become a shipment. This module answers them with the same discipline as tracking (chapter 07): an append-only ledger of movements is the truth, and stock levels are a projection over it. It reuses
product (chapter 20) for what is stored, facility (chapter 16 §1) for where, asn (chapter 18 §4) for inbound receipts, device_event (chapter 22) for scans, shipment (chapter 03) for what leaves, and meter (chapter 28 §4) for storage and handling fees.
The module is
inventory. It is required in 3PL mode, and optional in Universal (a merchant’s own warehouses), Carrier and Network (warehousing services) modes.
1. Storage locations
GraphQL:
storageLocations, storageLocation, createStorageLocation, updateStorageLocation, deleteStorageLocation, importStorageLocation (CSV of a facility layout, run as a job). Delete is refused while stock is present.
2. Stock
stock rows are read-only projections. They change only through movements (§3).
Stock levels
available is what can be promised. inbound counts open stock-receipt ASNs. Omit facility to aggregate across the network, or group_by=facility for one row per facility. Low-stock thresholds per product and facility (thresholdsInventory (GraphQL Interface mutation)) emit inventory.level_low.
3. Stock movements (the ledger)
Rules:
- Movements are append-only. A mistake is corrected by a compensating movement, never by editing or deleting.
- Every movement is idempotent on
(source, device_event)or onIdempotency-Key, so retried scans never double-count. createStockMovement(GraphQL Interface mutation) records manual movements (putaway,move,adjust,status_change). It returns409 insufficient_stockwhen thefromside lacks quantity.stockMovements(GraphQL Interface query) is the audit trail. With data network replication, movements become signed records (chapter 23).
4. Fulfillment orders
- Allocation strategies:
single_facility_nearest,single_facility_cheapest(rates each candidate facility),split_minimize_shipments, andfixed(a named facility). Lots followlot_policy:fefo,fifo, orspecific. - Packing to shipping:
packwrites the handling units.shipcreates the shipment with those handling units, whose items reference the products, rates or usesshipping.carrier_configs, and buys it. The label, the packing slip (frompacking.inserts) and the invoice land indocuments[]. This one path connects inventory to every carrier in the spec. - Pick lists are documents rendered from a template (
type: "pick_list", chapter 25), sorted bypick_sequence.
5. Counts
blind: true, counters do not see expected quantities. complete returns per-line expected, counted, variance and value_variance (variance × product.unit_value). Implementers MAY require approval above a variance threshold.
6. Sync with sales channels
inventory.level_changedfires whenavailablechanges for a product and facility, coalesced to at most once per minute per product.GET /v1/inventory/levels?updated[gte]=…supports incremental pulls for platforms that poll.- A connection to a sales channel (an integration with
kind: "ecommerce_platform", chapter 26) withsync: { inventory: "push" }pushesavailable(minus an optional safety buffer) to the channel. A job schedule (chapter 27) runs a full reconciliation nightly.
7. Billing hooks
The inventory module feeds built-in meters (chapter 28 §4):storage.pallet_days, storage.cubic_meter_days, storage.bin_days (computed daily from stock by location type), fulfillment.orders, fulfillment.picks, fulfillment.units_packed, receiving.units, and returns.processed. 3PLs price them in a price_plan per owner account.
8. Events
storage_location.created, stock_movement.created, inventory.level_changed, inventory.level_low, fulfillment_order.created, .allocated, .backordered, .picking, .packed, .shipped, .cancelled, wave.released, inventory_count.completed.