Recipe: keep stock levels in sync
Read the current level, then push a correction with PUT for one product or POST /inventory/batch for many, using Idempotency-Key so a retried request never double-applies.
How do I read current stock
Section titled “How do I read current stock”GET /products/{id}/inventory returns one row per live outlet the product is stocked at.
curl https://api.oletapp.com/your-store/v1/products/PRODUCT_ID/inventory \ -H "Authorization: Bearer olet_live_YOUR_API_KEY"{ "data": [ { "outlet_id": "...", "on_hand": 42, "reorder_method": "none", "reorder_point": null, "reorder_amount": null, "reorder_target": null, "version": "..." } ]}How do I set one product’s stock level
Section titled “How do I set one product’s stock level”PUT /products/{id}/inventory/{outlet_id} sets an absolute level. Send the same on_hand twice and the second call changes nothing (changed: false), so it is safe to retry without an Idempotency-Key, though you may still send one. Without a reason_id, the change is recorded under the system reason “Stock set via API”. GET /inventory/adjustment-reasons lists the reasons you can name instead.
curl -X PUT https://api.oletapp.com/your-store/v1/products/PRODUCT_ID/inventory/OUTLET_ID \ -H "Authorization: Bearer olet_live_YOUR_API_KEY" \ -H "Content-Type: application/json" \ -d '{"on_hand": 37}'{ "data": { "changed": true, "previous": 42, "on_hand": 37, "delta": -5, "adjustment_id": "...", "movement_id": "..." }}How do I sync many products in one call
Section titled “How do I sync many products in one call”POST /inventory/batch sets or adjusts up to 100 product/outlet lines in one all-or-nothing request. Each line names exactly one of set (absolute) or adjust (relative), and exactly one of product_id or sku. Idempotency-Key is required here: a retried batch replayed without one could double-apply a relative adjust line.
curl -X POST https://api.oletapp.com/your-store/v1/inventory/batch \ -H "Authorization: Bearer olet_live_YOUR_API_KEY" \ -H "Idempotency-Key: YOUR_UNIQUE_KEY" \ -H "Content-Type: application/json" \ -d '{"lines": [ {"sku": "SKU-001", "outlet_id": "OUTLET_ID", "set": {"on_hand": 37}}, {"sku": "SKU-002", "outlet_id": "OUTLET_ID", "set": {"on_hand": 12}} ]}'{ "data": [ { "product_id": "...", "sku": "SKU-001", "outlet_id": "OUTLET_ID", "changed": true, "previous": 42, "on_hand": 37, "delta": -5 }, { "product_id": "...", "sku": "SKU-002", "outlet_id": "OUTLET_ID", "changed": true, "previous": 10, "on_hand": 12, "delta": 2 } ]}A batch with a bad line, such as an unknown sku, writes nothing at all: the whole request fails or the whole request succeeds. The same product and outlet pair can appear only once in a batch. A replayed batch marks each line "replayed": true.
How do I find out when stock changes on the OLET side
Section titled “How do I find out when stock changes on the OLET side”There is no delta-sync feed for stock levels the way there is for products and sales. Poll GET /products/{id}/inventory for the products you care about on whatever interval fits your integration, and treat the returned on_hand as the current truth.
What if I only have a SKU, not a product id
Section titled “What if I only have a SKU, not a product id”The batch endpoint and POST /inventory/adjustments accept sku as an alternative to product_id, matched case-insensitively against live products only, never against a barcode. PUT /products/{id}/inventory/{outlet_id} takes the product id in its path, so use GET /products?sku=... to find the id first.
What can refuse a stock write
Section titled “What can refuse a stock write”422 INSUFFICIENT_STOCKwhen an adjustment would take stock below zero.422 REASON_NOT_ALLOWEDwhen the reason is a system reason or is turned off.422 REASON_DIRECTION_MISMATCHwhen areason_idon a set does not match whether stock went up or down.422 OUTLET_DELETEDwhen the outlet has been deleted.
Where to go next
Section titled “Where to go next”See idempotency for the full replay rules, or errors for what 422 INSUFFICIENT_STOCK and 422 NOT_STOCK_TRACKED mean.