Stock items
Material and inventory tracking (CV-filters, kraanleertjes, sifons) layered on top of your product catalog. Each stock item is a sidecar on a CRM product — the API resource id is the product id. Quantity mutations go through an append-only ledger (stock_movements) so you have an audit history of every bijboeking, afboeking, retour and consume.
Scopes: operations.stock.read / operations.stock.write.
403 MODULE_VAKMAN_DISABLED otherwise.Endpoints
/api/workspace/v1/stock-items/api/workspace/v1/stock-items/{productId}/api/workspace/v1/stock-items/{productId}/api/workspace/v1/stock-items/{productId}/adjust/api/workspace/v1/stock-items/{productId}/movementsThe stock item object
| Field | Type | Description |
|---|---|---|
| product_id | integer | Identical to the product id from the CRM products API — stock is a sidecar |
| name | string | Product name (inherited from the product) |
| sku | string | Product SKU |
| unit | string | Unit of measure (stuk, meter, liter, kg, ...) |
| is_stock_tracked | boolean | Whether stock is actively tracked |
| stock_current | integer | Current on-hand quantity |
| stock_min_threshold | integer | Low-stock threshold — fires stock.low_threshold event when crossed |
| stock_location | string | Shelf/aisle/warehouse label |
| ean_barcode | string | EAN-13 barcode for scanner workflows |
| supplier_name | string | Default supplier label |
| last_stock_movement_at | string(ISO) | When the most recent adjust happened |
The stock movement object
Movements are append-only. Every adjust creates one row with a signed delta and the resulting on-hand quantity. Combined with the five movement types, this gives you full root-cause attribution of any stock change.
| Field | Type | Description |
|---|---|---|
| id | integer | Movement id (append-only ledger) |
| product_id | integer | The stock item that was mutated |
| movement_type | enum | workorder_consume | manual_adjust | purchase_receive | return | opening_balance |
| quantity_delta | integer | Signed delta — positive for receives/returns, negative for consume/adjust-down |
| stock_after | integer | On-hand quantity after this movement |
| workorder_id | integer | Links the movement to a work order when the technician consumed material |
| notes | string | Free-form movement notes |
| created_at | string(ISO) | When the movement was recorded |
Set tracking + initial balance
Use PATCH to turn tracking on, set a threshold, pin a shelf location, and optionally seed an opening balance. Settings and quantity in a single idempotent call.
curl "https://app.staffifyai.com/api/workspace/v1/stock-items/842" \
-X PATCH \
-H "Authorization: Bearer sfy_wsp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"is_stock_tracked": true,
"stock_current": 25,
"stock_min_threshold": 5,
"stock_location": "Magazijn A3",
"ean_barcode": "4260182982266",
"supplier_name": "Rexel Benelux"
}'Register a purchase receive (bijboeking)
POST to /adjust with a positive quantity_delta and movement_type: "purchase_receive". The response contains the updated stock item. Negative delta that would push on-hand below 0 returns 422 INSUFFICIENT_STOCK.
curl "https://app.staffifyai.com/api/workspace/v1/stock-items/842/adjust" \
-X POST \
-H "Authorization: Bearer sfy_wsp_live_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"quantity_delta": 12,
"movement_type": "purchase_receive",
"notes": "PO 2026-10-184 Rexel"
}'Stop tracking
There is no DELETE on stock items — stock is a sidecar on the CRM product. To stop tracking a product, PATCH is_stock_tracked to false. The movement history is kept and the sidecar row stays, so you can resume tracking later without losing the audit trail.
Events
stock.upserted— settings changed via PATCHstock.adjusted— quantity changed via /adjuststock.low_threshold— fires whenever an adjust leaves the on-hand quantity at or belowstock_min_threshold