Browse the docs

Build

Inventory sync

Push stock counts and adjustments without putting sold stock back on the shelf.

Customers only see what is in stock. Your POS is where most stock moves — the counter, deliveries from suppliers, write-offs — so your POS owns the count, and pushes it to Scanimart.

Push counts

Shell
curl -X PUT https://api.scanimart.com/v1/stores/1042/inventory \
  -H "Authorization: Bearer $SCANIMART_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{
    "as_of": "2026-10-08T10:00:00+05:30",
    "items": [
      { "barcode": "8901725181222", "stock": 14, "price": "229.00", "mrp": "245.00", "external_id": "SKU-ATTA-5" },
      { "barcode": "8901262010016", "stock": 0 }
    ]
  }'
  • stock is units on the shelf according to your POS at as_of.
  • name is required the first time Scanimart sees a barcode; after that, only the fields you send change.
  • external_id is your SKU. It is echoed on order lines, so your POS can find the product without a barcode lookup.
  • Up to 1,000 items per push, each barcode once. Up to 200 are applied immediately and the response is 200 with the result. Bigger pushes are queued: you get 202 with an id, and GET …/inventory/syncs/{id} shows when it is done.

Rows that fail — an unknown barcode with no name, a negative price — are listed in the result's errors; the rest still apply.

Why as_of matters

Scanimart takes stock too: when a store accepts an online order, and when a customer pays for a Scan & Go basket in the aisle. Your POS only learns about those when it books the sale.completed. A count you took before booking one of our sales still includes those units — written as-is, it would put sold stock back on the shelf.

So for every push, Scanimart subtracts the units in its own sales that you had not booked by as_of:

stock = max(your count − Scanimart units you had not booked by as_of, 0)

The result's adjusted_for_unbooked_sales lists the units subtracted per barcode. A sale counts as booked once your endpoint answered its sale.completed with 2xx, or you acknowledged it with POST …/sales/ack. Sales older than 72 hours are never subtracted.

Always send as_of — the moment your POS took the count, not the moment you send it. It defaults to now, which is only right if the count is that fresh.

Adjustments

For a single movement, send a delta instead of a count:

Shell
curl -X POST https://api.scanimart.com/v1/stores/1042/inventory/adjustments \
  -H "Authorization: Bearer $SCANIMART_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "adjustments": [
        { "barcode": "8901725181222", "delta": -2, "reason": "sale", "reference": "BILL-20402" },
        { "barcode": "8901262010016", "delta": 24, "reason": "received", "reference": "GRN-118" }
      ] }'

reason is one of sale, return, received, damaged, correction, other. Up to 500 per call. Use an Idempotency-Key: an adjustment applied twice is two adjustments.

Do not send adjustments for Scanimart's own sales — they already took the stock.

Reading stock

GET /v1/stores/{store_id}/inventory lists each product with:

Field Means
stock Units on the shelf
reserved Units held for paid online orders not yet accepted
available stock − reserved: what can still be sold

GET …/inventory/syncs shows your recent pushes and adjustments, and the dashboard shows the same.

How often

Push a full count once a day (after closing is a good time), and adjustments as they happen. If you cannot send adjustments, push changed items every few minutes instead.