Flow · 20 steps
Open the books with a stocktake
Every set of books begins with the stock counted and valued. The organization's first stocktake is its opening one: every stock SKU at every live location, each SKU given its cost. Completing it is the canonical fact the general ledger opens at — the counted stock posted at its cost against opening balances, nothing before it the ledger's — and until it is done no accounting app can be activated. Every later stocktake counts what it names and posts the difference as a write-down or a gain.
Services involved
A filled dot is a read; a ring is a call that changes something.
- Inventory Manager:
https://inventory.getmanifold.io - Accounting Ledger:
https://accounting.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 Bring two SKUs in
Twelve oak lamps on the shelf, as an import or a person left them — no cost yet.
POST /items Inventory Manager
{
"sku": "LAMP-OAK",
"name": "Oak table lamp",
"quantity": 12
}Answers 201. What the answer holds: the operation's example.
Records inventory.item-created.
2 And a second, with nothing on hand
A SKU holding nothing still needs a cost: the opening stocktake values every stock SKU.
POST /items Inventory Manager
{
"sku": "SHADE-LINEN",
"name": "Linen shade",
"quantity": 0
}Answers 201. What the answer holds: the operation's example.
Records inventory.item-created.
3 Start the opening stocktake
The first stocktake is the opening one, over every live location. The id is the caller's: a retry answers with the stocktake it started.
POST /stocktakes Inventory Manager
{
"stocktakeId": "stk_01a15870-d6a0-7c6d-8e7f-9a0b1c2d3e4f"
}Answers 201. What the answer holds: the operation's example.
Records inventory.stocktake-started.
4 Only one at a time
A second stocktake while one is open is refused 409 StocktakeInProgress, naming the open one.
POST /stocktakes Inventory Manager
{
"stocktakeId": "stk_01a15885-51ee-7e8f-8a91-b2c3d4e5f607"
}{
"_tag": "StocktakeInProgress",
"stocktakeId": "stk_01a15870-d6a0-7c6d-8e7f-9a0b1c2d3e4f"
}Records nothing.
5 Read the counting sheet
Every SKU of the scope, each at least once, with what on-hand says now and — where the stocktake gives none yet — the cost basis it suggests. Both SKUs still want a cost.
GET /stocktakes/stk_01a15870-d6a0-7c6d-8e7f-9a0b1c2d3e4f/sheet?missingCost=true Inventory Manager
What the answer holds: the operation's example.
6 Count the lamps and value them
Ten lamps on the shelf, not twelve, at $18.50 each. Saved as it is entered; nothing moves yet.
PUT /stocktakes/stk_01a15870-d6a0-7c6d-8e7f-9a0b1c2d3e4f/counts Inventory Manager
{
"counts": [
{
"sku": "LAMP-OAK",
"counted": 10
}
],
"costs": [
{
"sku": "LAMP-OAK",
"unitCostCents": 1850
}
]
}What the answer holds: the operation's example.
Records inventory.stocktake-counted.
7 Save the same figures again
Idempotent by content: what the stocktake already holds appends nothing.
PUT /stocktakes/stk_01a15870-d6a0-7c6d-8e7f-9a0b1c2d3e4f/counts Inventory Manager
{
"counts": [
{
"sku": "LAMP-OAK",
"counted": 10
}
],
"costs": [
{
"sku": "LAMP-OAK",
"unitCostCents": 1850
}
]
}What the answer holds: the operation's example.
Records nothing.
8 Try to complete it with a SKU unvalued
The shade has no cost: an opening stocktake values every stock SKU, so it is refused 409 StocktakeIncomplete, naming the SKU, and nothing moves.
POST /stocktakes/stk_01a15870-d6a0-7c6d-8e7f-9a0b1c2d3e4f/complete Inventory Manager
{
"_tag": "StocktakeIncomplete",
"stocktakeId": "stk_01a15870-d6a0-7c6d-8e7f-9a0b1c2d3e4f",
"missing": 1,
"skus": [
"SHADE-LINEN"
]
}Records nothing.
9 Value the shade
Nothing on hand, but a cost all the same — what the next one received will be measured against.
PUT /stocktakes/stk_01a15870-d6a0-7c6d-8e7f-9a0b1c2d3e4f/counts Inventory Manager
{
"costs": [
{
"sku": "SHADE-LINEN",
"unitCostCents": 640
}
]
}What the answer holds: the operation's example.
Records inventory.stocktake-counted.
10 Complete the opening stocktake
On-hand becomes the count, every SKU's cost basis the stocktake's, and the fact carries the whole opening balance. Accounting opens the general ledger here.
POST /stocktakes/stk_01a15870-d6a0-7c6d-8e7f-9a0b1c2d3e4f/complete Inventory Manager
What the answer holds: the operation's example.
Records inventory.stocktake-completed.
11 Complete it again
Idempotent by state: a stocktake completes once, so the retry answers with it and appends nothing.
POST /stocktakes/stk_01a15870-d6a0-7c6d-8e7f-9a0b1c2d3e4f/complete Inventory Manager
What the answer holds: the operation's example.
Records nothing.
12 The books open
The general ledger's first posting: ten lamps at $18.50 debited to inventory against opening balances. Accounting reads inventory's journal from its replica, so the poll waits for it. A poll claims nothing.
GET /postings?source=opening-stocktake Accounting Ledger
What the answer holds: the operation's example.
13 Read the opening one back
Its counts as completed: what it set on-hand to, and the cost it gave each SKU.
GET /stocktakes/stk_01a15870-d6a0-7c6d-8e7f-9a0b1c2d3e4f Inventory Manager
What the answer holds: the operation's example.
14 Start a recount, and abandon it
A later stocktake is periodic. Started by mistake, it is cancelled; nothing it counted moves.
POST /stocktakes Inventory Manager
{
"stocktakeId": "stk_01a15885-51ee-7e8f-8a91-b2c3d4e5f607"
}Answers 201. What the answer holds: the operation's example.
From your answer, later steps send id as {stocktakeId}.
Records inventory.stocktake-started.
15 Cancel it
Idempotent by state: a stocktake is cancelled once.
POST /stocktakes/{stocktakeId}/cancel Inventory Manager
{
"reason": "started on the wrong day"
}What the answer holds: the operation's example.
Records inventory.stocktake-cancelled.
16 Recount the lamps
A periodic stocktake over what it names: two lamps are missing since the opening.
POST /stocktakes Inventory Manager
{
"stocktakeId": "stk_01a15879-379d-7d7e-9f80-a1b2c3d4e5f6"
}Answers 201. What the answer holds: the operation's example.
From your answer, later steps send id as {stocktakeId}.
Records inventory.stocktake-started.
17 Eight on the shelf
The count only; a periodic stocktake asks no cost of a SKU that came up short.
PUT /stocktakes/{stocktakeId}/counts Inventory Manager
{
"counts": [
{
"sku": "LAMP-OAK",
"counted": 8
}
]
}What the answer holds: the operation's example.
Records inventory.stocktake-counted.
18 Complete the recount
On-hand drops to eight; the two lamps short are the variance.
POST /stocktakes/{stocktakeId}/complete Inventory Manager
What the answer holds: the operation's example.
Records inventory.stocktake-completed.
19 The variance posts
Two lamps at the cost they were counted at, written down: stock write-downs debited, inventory credited.
GET /postings?source=stocktake-variance Accounting Ledger
What the answer holds: the operation's example.
20 Every stocktake, newest first
The recount, the abandoned one and the opening one — the books begin at the first completed.
GET /stocktakes Inventory Manager
What the answer holds: the operation's example.
What a recorded fact is: Facts and the journal. Why a repeated step changes nothing: Idempotency and retries.