Flow · 17 steps

Running more than one location

Open a second location, move stock to it, and see what fulfillable changes.

Every organization starts with one location that can ship. A location that is not fulfillable can receive, hold and transfer stock, but never sell it: right for a quarantine bay, a repair bench or a 3PL you have not switched on yet.

Services involved

A filled dot is a read; a ring is a call that changes something.

  • Inventory Manager: https://inventory.getmanifold.io
  • Fulfillment Manager: https://fulfillment.getmanifold.io

Every call carries Authorization: Bearer $MANIFOLD_TOKEN unless its step says otherwise (getting a token). Run a flow in your sandbox, not your live organization: see Before you start.

1 See what you already have

One fulfillable location, opened with the account. The last fulfillable one can be neither archived nor switched off, so this list is never empty.

GET /locations Inventory Manager

What the answer holds: the operation's example.

From your answer, later steps send items[0].id as {mainLocationId}.

2 Stock the main site

Forty units at the site the account was created with — the only place, so far, that anything can be sold from.

POST /items Inventory Manager

Request · application/json
{
  "sku": "WIDGET-BLUE",
  "name": "Blue widget, 40mm",
  "quantity": 40,
  "locationId": "{mainLocationId}"
}

Answers 201. What the answer holds: the operation's example.

Records inventory.item-created.

3 Open a quarantine bay

fulfillable: false is the flag with teeth. Stock here is real, counted and visible — and nothing can reserve, allocate or dispatch it to a customer.

POST /locations Inventory Manager

Request · application/json
{
  "name": "Quarantine bay",
  "fulfillable": false,
  "note": "Goods held pending inspection."
}

Answers 201. What the answer holds: the operation's example.

From your answer, later steps send id as {locationId}.

Records inventory.location-created.

4 Move ten units into it

A transfer is a document first: this opens it and moves nothing. Transferring into a non-fulfillable site is entirely normal — it is how stock reaches quarantine in the first place.

POST /transfers Inventory Manager

Request · application/json
{
  "fromLocationId": "{mainLocationId}",
  "toLocationId": "{locationId}",
  "reference": "QA-2291",
  "lines": [
    {
      "sku": "WIDGET-BLUE",
      "quantity": 10
    }
  ]
}

Answers 201. What the answer holds: the operation's example.

From your answer, later steps send id as {transferId}.

Records inventory.transfer-created.

5 Send it

The units come off the source's shelf and land in the destination's inTransit. Sellable at neither end, which is the honest position for stock in a van. The source must hold them free — units already reserved for an order cannot be sent.

POST /transfers/{transferId}/despatch Inventory Manager

Request · application/json
{
  "reference": "van-WIDGET-BLUE"
}

What the answer holds: the operation's example.

Records inventory.transfer-despatched.

6 Watch them disappear from both sides

Thirty available at main, ten in transit, forty on hand across the organization. Nothing was lost and nothing is sellable twice.

GET /items/WIDGET-BLUE/stock Inventory Manager

What the answer holds: the operation's example.

7 Book them in

inTransit falls and on-hand rises at the destination. Naming fewer units than are on the road records a short delivery and leaves the rest in transit, rather than quietly losing them.

POST /transfers/{transferId}/receive Inventory Manager

Request · application/json
{
  "reference": "van-WIDGET-BLUE-in"
}

What the answer holds: the operation's example.

Records inventory.transfer-received.

8 The flag does its work

Forty units on hand, and only thirty available: the ten in quarantine are physically present and cannot be promised to anybody. byLocation shows exactly where each figure comes from — and this is the number that would be wrong if availability were a simple sum.

GET /items/WIDGET-BLUE/stock Inventory Manager

What the answer holds: the operation's example.

9 Read the transfer back

Per line: what was asked for, what left, and what arrived. The gap between the last two is what is still on the road.

GET /transfers/{transferId} Inventory Manager

What the answer holds: the operation's example.

10 See how this organization may move stock

An organization that has set nothing gets the conservative shape: two-step, the only mode that never claims stock arrived before it did. That is what the transfer above used.

GET /settings Inventory Manager

What the answer holds: the operation's example.

11 Allow instant moves as well

unrestricted lets the caller pick per transfer. instant would force it, two-step would forbid it, and off would refuse transfers entirely — for merchants whose stock only ever moves in and out, never sideways.

PUT /settings Inventory Manager

Request · application/json
{
  "transfers": "unrestricted"
}

What the answer holds: the operation's example.

Records inventory.settings-configured.

12 Move stock with no van involved

Between two bays of the same building there is no moment at which the stock is anywhere else, so instant moves it in a single commit and the transfer comes back already received. The journal records one fact — inventory.transfer-completed — rather than a despatch and a receipt describing a transit that never happened.

POST /transfers Inventory Manager

Request · application/json
{
  "fromLocationId": "{mainLocationId}",
  "toLocationId": "{locationId}",
  "mode": "instant",
  "reference": "QA-2292",
  "lines": [
    {
      "sku": "WIDGET-BLUE",
      "quantity": 5
    }
  ]
}

Answers 201. What the answer holds: the operation's example.

Records inventory.transfer-completed.

13 Rename the bay, and let it sell

Locations are editable. Switching one back to fulfillable puts its stock on sale without moving a unit — and the last fulfillable location cannot be switched off, so an organization always has somewhere to ship from.

PATCH /locations/{locationId} Inventory Manager

Request · application/json
{
  "name": "Bay 2",
  "fulfillable": true
}

What the answer holds: the operation's example.

Records inventory.location-updated.

14 Take an order — routed to one site

Allocation picks the shelf, and the parcel it opens carries the locationId it will ship from. Two sites now hold this SKU, and routing chose between them: what a line is held against is a decision, recorded on the allocation fact.

POST /orders Fulfillment Manager

Request · application/json
{
  "reference": "WEB-10288",
  "lines": [
    {
      "sku": "WIDGET-BLUE",
      "quantity": 2,
      "unitPriceCents": 2400
    }
  ],
  "customer": {
    "personId": "psn_01a15890-1b2c-7d3e-8f4a-5b6c7d8e9f0a"
  }
}

Answers 201. What the answer holds: the operation's example.

From your answer, later steps send id as {orderId} and lines[0].id as {lineId}.

Records fulfillment.order-created, fulfillment.stock-allocated, fulfillment.shipment-created.

15 Move the hold to the other site

Allocation is final until a person changes it — nothing re-routes a held line on its own. This is that person: the units are released where they were and taken where they are going in one transaction, the pending parcel moves with them (joining a parcel already open there, or opening a fresh one), and reference makes it a move that cannot happen twice. A parcel already picked is refused — by then the stock is on a bench, and moving it is a physical act.

POST /orders/{orderId}/lines/{lineId}/allocation Fulfillment Manager

Request · application/json
{
  "toLocationId": "{locationId}",
  "reference": "move-WIDGET-BLUE",
  "reason": "Bay 2 is closer to the courier"
}

What the answer holds: the operation's example.

Records fulfillment.allocation-moved.

16 Look at it on its own

One location, with whether it can sell and when it was opened.

GET /locations/{locationId} Inventory Manager

What the answer holds: the operation's example.

17 Try to close it while it still holds stock

Refused. Archiving a site holding units would strand them where nothing can reach them, so the error names the SKUs still there — transfer them out first, which is what transfers are for.

POST /locations/{locationId}/archive Inventory Manager

Refused · 409
{
  "_tag": "LocationNotEmpty",
  "locationId": "{locationId}",
  "skus": [
    "WIDGET-BLUE"
  ]
}

Records nothing.

What a recorded fact is: Facts and the journal. Why a repeated step changes nothing: Idempotency and retries.