Fulfillment & inventory
The pick/pack/ship loop has a supply-and-routing spine covering two areas: purchase orders, receiving, and physical stock locations on the inventory side, and fulfillment nodes, routing modes, dropship vendor costs, and COGS capture on the fulfillment side.
Inventory: purchase orders, receiving, locations
Inventory (items/lots/FEFO reservations) has supply-side depth: vendors,
purchase orders (with lines), receiving against a PO, and per-node
physical locations. Receiving fails closed on a non-receivable PO
(po_not_receivable) or an over-receipt (receive_exceeds_expected).
Inventory administration (operator-managed)
Tenant-level location, vendor, and purchase-order administration is operator/console-managed. Merchants manage their own through the merchant routes below.
| Method | Path | Purpose |
|---|---|---|
POST | /v1/tenants/:tenant/locations | Create a physical stock location; optional node_ref binds it to a fulfillment node. |
GET | /v1/tenants/:tenant/locations | List locations. |
POST | /v1/tenants/:tenant/vendors | Create a supply vendor. |
GET | /v1/tenants/:tenant/vendors | List vendors. |
POST | /v1/tenants/:tenant/purchase-orders | Create a PO + its lines. |
GET | /v1/tenants/:tenant/purchase-orders | List POs. |
GET | /v1/tenants/:tenant/purchase-orders/:id | Fetch a PO + lines. |
POST | /v1/tenants/:tenant/purchase-orders/:id/receive | Receive stock against a PO (creates lots; fails closed on over-receipt). |
Merchant routes — fdk_, scope manage:own_inventory, under /v1/merchant/inventory
| Method | Path | Purpose |
|---|---|---|
GET | /v1/merchant/inventory/vendors | List the caller’s vendors. |
POST | /v1/merchant/inventory/vendors | Create a vendor. |
GET | /v1/merchant/inventory/purchase-orders | List POs. |
GET | /v1/merchant/inventory/purchase-orders/:id | Fetch one PO + lines. |
POST | /v1/merchant/inventory/purchase-orders | Create a PO. |
POST | /v1/merchant/inventory/purchase-orders/:id/receive | Receive against a PO. |
Fulfillment: nodes, modes, dropship costs, COGS
A fulfillment node is a own_warehouse / threepl / vendor endpoint.
Allocation picks a mode:
dedicated— draw from own stock, no node pinned.allocated— pin the queue to a specificown_warehouse/threeplnode and draw FEFO from that node’s bound inventory location. An unbound node fails closed (node_location_unmapped) rather than silently drawing from elsewhere.dropship— route each line to a vendor node without reserving or decrementing own stock, recording a per-line vendor dispatch (the “purchase/dispatch to vendor”) and a dropship shipment row that stands in for the carrier label.
Mode/node selection happens on the first (queued) pass only; a re-entrant
allocate keeps the row’s chosen mode. Mixing own-stock and dropship on one
route is refused (wrong_mode) — dropship has its own route.
COGS capture: every shipped line captures cost of goods at ship time (when
the reservations commit / the vendor is dispatched). Dropship COGS resolves
each line’s unit cost from the (node, sku) vendor-cost mapping; a line
with no cost recorded is captured at zero rather than blocking the ship.
Fulfillment administration (operator-managed)
Tenant-level fulfillment administration (queue, nodes, vendor costs, allocation, labels, ship/deliver) is operator/console-managed. Merchants manage their own through the merchant routes below.
| Method | Path | Purpose |
|---|---|---|
GET | /v1/tenants/:tenant/fulfillment | List the fulfillment queue. |
GET | /v1/tenants/:tenant/fulfillment/:id | Fetch one queue row. |
POST | /v1/tenants/:tenant/fulfillment/:id/allocate | Allocate own stock; a nodeId pins mode allocated, omitting it is dedicated. |
POST | /v1/tenants/:tenant/fulfillment/:id/dropship | Route to a vendor node (mode dropship), no own-stock reservation. |
POST | /v1/tenants/:tenant/nodes | Create a fulfillment node (own_warehouse/threepl/vendor). |
GET | /v1/tenants/:tenant/nodes | List nodes. |
POST | /v1/tenants/:tenant/vendor-costs | Map a per-(node, sku) vendor unit cost (dropship COGS input). |
GET | /v1/tenants/:tenant/vendor-costs | List vendor costs. |
POST | /v1/tenants/:tenant/fulfillment/:id/label | Buy a shipping label. |
POST | /v1/tenants/:tenant/fulfillment/:id/ship | Ship — commit reservations / dispatch vendor, capture COGS, advance the order. |
POST | /v1/tenants/:tenant/fulfillment/:id/cancel | Cancel the queue row. |
POST | /v1/tenants/:tenant/fulfillment/:id/deliver | Mark delivered (advances the order to delivered). |
Merchant routes — fdk_, scope manage:own_fulfillment, under /v1/merchant/fulfillment
| Method | Path | Purpose |
|---|---|---|
GET | /v1/merchant/fulfillment | List the queue. |
GET | /v1/merchant/fulfillment/nodes | List nodes. |
POST | /v1/merchant/fulfillment/nodes | Create a node. |
GET | /v1/merchant/fulfillment/vendor-costs | List vendor costs. |
POST | /v1/merchant/fulfillment/vendor-costs | Map a vendor cost. |
GET | /v1/merchant/fulfillment/:id | Fetch one queue row. |
POST | /v1/merchant/fulfillment/:id/allocate | Allocate. |
POST | /v1/merchant/fulfillment/:id/dropship | Dropship-route. |
POST | /v1/merchant/fulfillment/:id/label | Buy a label. |
POST | /v1/merchant/fulfillment/:id/ship | Ship. |
POST | /v1/merchant/fulfillment/:id/cancel | Cancel. |
POST | /v1/merchant/fulfillment/:id/deliver | Mark delivered. |
Manifest gates
None. Fulfillment routing, POs, receiving, nodes, and COGS are back-office surfaces with no storefront manifest toggle.
Notes
- Allocation matches by SKU — a fulfillment queue line whose SKU has no
matching inventory item fails allocation with a surfaced
422 inventory_item_not_found, never a silent skip. - One queue row and one shipment per order today; reships and multi-package shipments are out of scope.
- Dropship COGS for a line with no vendor cost recorded is captured at zero, not blocked — a documented simplification.