Inventory
Stock in LithosPOS is held per store and moves through documents, not through direct balance writes. Every change is an adjustment, a transfer, a production or a purchase receipt — so the merchant can always answer “why did this number change?”.
Endpoints
Section titled “Endpoints”| Method | Path | Scope |
|---|---|---|
GET | /v1/stock-adjustments | stock_adjustments.read |
POST | /v1/stock-adjustments | stock_adjustments.write |
PATCH | /v1/stock-adjustments/:id | stock_adjustments.write |
GET | /v1/stock-transfers | stock_transfers.read |
POST | /v1/stock-transfers | stock_transfers.write |
PATCH | /v1/stock-transfers/:id | stock_transfers.write |
PATCH | /v1/stock-transfers/:id/receive | stock_transfers.write |
GET | /v1/recipes | recipes.read |
POST | /v1/recipes | recipes.write |
PATCH | /v1/recipes/:id | recipes.write |
GET | /v1/productions | productions.read |
POST | /v1/productions | productions.write |
Stock adjustments
Section titled “Stock adjustments”An adjustment records a count, a write-off or a correction against one store.
curl -s "$API_BASE_URL/stock-adjustments" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{ "no": 1042, "type": 2, "storeId": 1, "date": "2026-07-29", "narration": "Monthly count — dry store", "items": [ { "itemId": 8841, "qty": 36, "cost": 1.12 }, { "itemId": 8850, "qty": 4, "cost": 0.80, "note": "damaged" } ] }'| Field | Type | Required | Notes |
|---|---|---|---|
no | number | yes | Document number in the merchant’s own sequence |
type | number | yes | 0 decrease, 1 increase, 2 set to counted quantity |
storeId | number | yes | Store whose stock changes |
date | string | no | YYYY-MM-DD. Defaults to today |
narration | string | no | Reason, shown in the stock ledger |
items[].itemId | number | yes | |
items[].variantId | number | no | 0 when the item has no variants |
items[].qty | number | yes | Interpretation depends on type |
items[].cost | number | no | Unit cost used for valuation |
items[].batchId | number | no | Required for batch-tracked items |
items[].note | string | no | Per-line reason |
type decides what qty means: with 0 and 1 it is a delta, with 2 it is the counted
quantity on the shelf and the system computes the difference.
Transfers between stores
Section titled “Transfers between stores”A transfer is a two-sided document: it leaves the source store when created and arrives at the destination when received.
# 1. Raise the transfercurl -s "$API_BASE_URL/stock-transfers" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{ "transferNo": 231, "date": "2026-07-29", "fromStoreId": 2, "toStoreId": 1, "narration": "Weekly replenishment", "items": [ { "itemId": 8841, "qty": 24, "rate": 1.12 }, { "itemId": 8850, "qty": 12, "rate": 0.80 } ] }'
# 2. Receive it at the destinationcurl -s -X PATCH "$API_BASE_URL/stock-transfers/774/receive" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{ "reciveDate": "2026-07-30" }'| Field | Type | Required | Notes |
|---|---|---|---|
transferNo | number | yes | Document number |
date | string | yes | YYYY-MM-DD dispatch date |
reciveDate | string | no | Expected or actual arrival date |
fromStoreId / toStoreId | number | yes | Must differ |
items[].itemId, qty, rate | number | yes | rate is the transfer valuation, not a selling price |
items[].taxableAmount | number | no | rate × qty; recomputed server-side |
items[].serialNo | array | no | Pre-picked serial numbers for serial-tracked items |
Until a transfer is received, the stock is in transit: gone from the source, not yet countable at the destination.
Recipes
Section titled “Recipes”A recipe describes what a made-to-order or prepared item consumes.
curl -s "$API_BASE_URL/recipes" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{ "Recipe": "Flat White", "ItemId": 8841, "Qty": 1, "ServingUnit": "cup", "AutoDeduct": 1, "Ingredients": [ { "ItemId": 9001, "Qty": 18, "Unit": "g" }, { "ItemId": 9002, "Qty": 150, "Unit": "ml" } ] }'| Field | Type | Required | Notes |
|---|---|---|---|
Recipe | string | yes | Name, up to 45 characters |
ItemId | number | yes | The item this recipe produces |
Qty | number | no | Yield quantity, default 1 |
AutoDeduct | number | no | 1 depletes ingredients when the item sells |
WasteFactorPct | number | no | Adds an allowance on top of the ingredient quantities |
Ingredients[].ItemId | number | yes | |
Ingredients[].Qty | number | yes | Per yield unit |
Ingredients[].Unit | string | no | Free text, up to 20 characters |
Ingredients[].CostOverride | number | null | no | null uses the ingredient item’s own cost |
With AutoDeduct on, selling the finished item consumes the ingredients automatically —
no production document required.
Productions
Section titled “Productions”A production converts ingredients into finished stock in one step: batch cooking, bottling, assembling a pack.
curl -s "$API_BASE_URL/productions" \ -H "Authorization: Bearer $ACCESS_TOKEN" \ -H 'Content-Type: application/json' \ -d '{ "storeId": 1, "itemId": 8905, "qty": 40, "date": "2026-07-29", "narration": "Morning bake", "items": [ { "itemId": 9010, "qty": 8000, "cost": 0.0012 }, { "itemId": 9011, "qty": 120, "cost": 0.02 } ] }'| Field | Type | Required | Notes |
|---|---|---|---|
storeId | number | yes | Where the production happens |
itemId | number | yes | The finished item produced |
qty | number | yes | Units produced |
no | number | no | Batch number. Omit to let the server allocate the next one |
batchId | number | no | For batch-tracked finished goods |
date | string | no | YYYY-MM-DD |
items[].itemId, qty | number | yes | Ingredients consumed |
items[].cost | number | no | Unit cost, used to value the finished stock |
The finished item’s stock rises by qty and each ingredient falls by its line quantity, in
one transaction.