Overview
Three endpoints support atomic multi-item inventory operations. Each accepts anitems[] array and guarantees all-or-nothing behavior: every item writes in a single database transaction. If item 5 of 10 fails, items 0-4 are automatically rolled back.
Each endpoint also accepts single-item (top-level) payloads for backward compatibility.
POST /v1/inventory/receive
When to use
Use for non-PO standalone receipts — opening stock loads, vendor samples, or inventory counts that don’t correspond to a purchase order. Each item establishes its own FIFO cost layer. For PO-linked receipts usePOST /v1/purchase-orders/{id}/receive.
Multi-item atomic receive
Response shape
Required fields per item
Validation error shape (400)
If any item fails upfront validation, no items are written and the response includes exactparam paths:
POST /v1/inventory/adjustments
When to use
Use for cycle-count corrections, shrinkage write-downs, and inventory revaluations. A GL journal entry fires per item inside the same database transaction (Rule 21). Positive deltas (adding stock) requireunit_cost to establish a new FIFO layer. Negative deltas consume existing FIFO layers automatically and calculate COGS from the oldest layers.
Multi-item atomic adjustment
Response shape
Required fields per item
GL behavior
Each adjustment item creates its own journal entry (DR/CR balanced to the cent):- Positive delta (add stock): DR Inventory Asset, CR Inventory Adjustment/Suspense. Amount =
quantity_delta * unit_cost. - Negative delta (remove stock): DR Inventory Adjustment/Shrinkage, CR Inventory Asset. Amount = FIFO COGS (oldest layers consumed first).
journal_entry_id on each item links the transaction to the GL record. gl_amount is positive for additions, negative for removals.
Serialized product adjustments
For serialized products, include matching serial arrays whose length equalsabs(quantity_delta):
POST /v1/inventory/transfers
When to use
Use to move inventory between locations within the same entity (internal transfer) or between entities (intercompany transfer). A transfer is created indraft status. GL entries fire when the transfer is submitted (internal) or shipped (intercompany).
Multi-item atomic transfer
Response shape
Field name aliases
Both naming conventions are accepted:GL lifecycle
Atomicity guarantee
All three endpoints wrap theiritems[] loop in a single pool.connect() + BEGIN/COMMIT/ROLLBACK transaction:
- All items validate upfront (before
BEGIN). BEGINstarts.- Each item writes inside the transaction.
- Any item failure triggers
ROLLBACK— every item reverts. COMMITfires only after all items succeed.
failed_item_index and items_completed_before_failure so you know which item triggered the rollback. All items are reverted regardless of items_completed_before_failure — the count is informational only.
Idempotency
All three endpoints honor theIdempotency-Key header. Replaying the same key within 24 hours returns the original response without re-applying the operation. Use a UUID or a deterministic key tied to your batch (e.g. receive-batch-${date}-${batchId}).
Related endpoints
POST /v1/purchase-orders/{id}/receive— PO-linked receipts (triggers GRNI GL, matches against PO lines)GET /v1/inventory/balances— query current on_hand / allocated / available by product and locationGET /v1/inventory/transactions— movement history logGET /v1/inventory/fifo-layers— FIFO cost layers per product/locationPOST /v1/inventory/serials— bulk enroll serial numbers (status transition only, no on_hand change)

