Fulfillment and inventory
Goal: bring stock in against a purchase order and receive it into a lot, and
route an order line to a dropship vendor — all through the fdk_ merchant API.
Audience: a back-office integration authenticating with an fdk_
credential (Authorization: Bearer fdk_…). The tenant is carried by the
credential. Money is integer cents.
The supply-and-routing surface splits by ownership: vendors, purchase orders,
and receiving are inventory (scope manage:own_inventory); fulfillment
nodes and dropship dispatch are fulfillment (scope manage:own_fulfillment).
Bring stock in: vendor, PO, receive
Create a vendor
POST /v1/merchant/inventory/vendors HTTP/1.1
Host: api.ruo.pro
Authorization: Bearer fdk_live_…
Content-Type: application/json
{ "name": "Nova Peptide Supply" }201 returns { vendor: { id, tenant_ref, name } }.
Create a purchase order with its lines
Each line references a canonical_item_id, an expected_qty, and a landed
unit_cost_cents (integer cents).
POST /v1/merchant/inventory/purchase-orders HTTP/1.1
Authorization: Bearer fdk_live_…
Content-Type: application/json
{
"vendor_id": "ven_…",
"reference": "PO-2026-014",
"lines": [
{ "canonical_item_id": "item_bpc5mg", "expected_qty": 200, "unit_cost_cents": 1200 }
]
}201 returns { purchase_order, lines }. A PO’s status is open,
partially_received, received, or cancelled.
Receive stock against a line into a lot
Receiving creates an inventory lot — the traceable unit that carries manufacturing/expiry dates and drives FEFO reservations.
POST /v1/merchant/inventory/purchase-orders/{id}/receive HTTP/1.1
Authorization: Bearer fdk_live_…
Content-Type: application/json
{
"line_id": "pol_…",
"internal_lot": "LOT-BPC-2026-014",
"qty_received": 200,
"vendor_lot": "NP-88213",
"mfg_date": "2026-08-01",
"exp_date": "2028-08-01",
"location_id": "loc_…"
}201 returns { lot, line, purchase_order } — the created lot, the line with
its updated received_qty, and the PO with its walked status.
Receiving fails closed. Receiving against a non-receivable PO
(po_not_receivable) or an over-receipt beyond expected_qty
(receive_exceeds_expected) is refused — never a silent partial write.
Read what you have
GET /v1/merchant/inventory/vendors -> { vendors: [...] }
GET /v1/merchant/inventory/purchase-orders -> { purchase_orders: [...] }
GET /v1/merchant/inventory/purchase-orders/{id} -> { purchase_order, lines }An unknown PO id is a 404 for this tenant.
Fulfillment nodes and dropship routing
A fulfillment node is an endpoint stock ships from — own_warehouse,
threepl, or dropship_vendor.
Create a node
POST /v1/merchant/fulfillment/nodes HTTP/1.1
Authorization: Bearer fdk_live_…
Content-Type: application/json
{ "kind": "dropship_vendor", "name": "Nova Dropship", "vendor_ref": "ven_…" }201 returns { node: { id, tenant_ref, kind, name, location, vendor_ref } }.
List them with GET /v1/merchant/fulfillment/nodes.
Route a queued order to the dropship vendor
Dropship routes each line to a vendor node without reserving or decrementing
your own stock — it records a per-line vendor dispatch. Supply a fallback
unit_cost_cents per line for COGS when no vendor-cost mapping exists.
POST /v1/merchant/fulfillment/{id}/dropship HTTP/1.1
Authorization: Bearer fdk_live_…
Content-Type: application/json
{
"node_id": "node_…",
"lines": [ { "queue_item_id": "qi_…", "unit_cost_cents": 1500 } ]
}201 returns { queue, dispatches } — the advanced queue row and the recorded
dropship dispatches (each dispatched or shipped, with a resolved
unit_cost_cents).
The queue row is created automatically when an order is placed — the
fulfillment module consumes commerce.order.placed.v1 and enqueues the row and
its lines. You route an existing queue row; you do not create it.
Refusals
404— the queue row or node does not exist for this tenant.409— the queue row is not in a state that permits dropship routing (for example it is already allocated to own stock — mixing modes on one route is refused).
The full pick/pack/ship depth
Own-stock allocation, buying carrier labels, the ship transition (which commits
reservations, captures COGS, and walks the commerce order), and marking
delivered are covered — with their operator and merchant routes, modes
(dedicated / allocated / dropship), and COGS capture — in the reference.
Related
- Fulfillment depth — nodes, modes, receiving, vendor costs, and per-line COGS in full.
- Order lifecycle — the order statuses fulfillment transitions drive.
- Money invariants — integer cents everywhere.