WinShopAPI docs
Guides

Stock levels sync

Read stock quantities per warehouse and variant, and keep the availability in an e-shop current.

Goal: show correct availability in an e-shop, or feed stock numbers into another system.

In WinShop, stock is kept as stock items. A stock item is the holding of one product, or one variant of a product, in one warehouse. A variant is one combination of colour, size, length and dimension. So the stock of a T-shirt is not one number: it is one number per variant and per warehouse.

You will use:

  • GET /api/item-lists/warehouses to pick the warehouses
  • POST /api/stock-items/filter-paginated to read the quantities

Before you start

Ask the customer which warehouses count for your purpose. A company often has a central warehouse, shops, and warehouses for returns or claims. An e-shop usually sells from one or two of them. Keep the warehouse ids in your configuration.

Setup

The steps use one small helper for authenticated JSON calls. In C#, keep the record declarations of all snippets at the end of your file. GetAccessTokenAsync() and getAccessToken() are the token cache from Authentication.

using System.Net.Http.Headers;
using System.Net.Http.Json;

var http = new HttpClient { BaseAddress = new Uri("https://<your-instance>") };

async Task<T> SendAsync<T>(HttpMethod method, string path, object? body = null)
{
    using var request = new HttpRequestMessage(method, path);
    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", await GetAccessTokenAsync());
    if (body is not null) request.Content = JsonContent.Create(body);

    using var response = await http.SendAsync(request);
    response.EnsureSuccessStatusCode();
    return (await response.Content.ReadFromJsonAsync<T>())!;
}

record Page<T>(List<T> Data, int CurrentPage, int TotalPages, int TotalCount, int PageSize,
    bool HasPreviousPage, bool HasNextPage);

The sync, step by step

Find the warehouse ids

Warehouses are an item list. Read it once and let the customer choose.

curl https://<your-instance>/api/item-lists/warehouses \
  -H "Authorization: Bearer $ACCESS_TOKEN"
[
  { "id": 1, "number": "01", "name": "Central warehouse" },
  { "id": 2, "number": "02", "name": "Shop Prague" }
]

Read the stock items of those warehouses

Search the stock items with the warehouse ids in filter.warehouseId. Ask only for the identifying fields and the quantities, and page through. See Filtering and pagination for the request shape.

curl -X POST https://<your-instance>/api/stock-items/filter-paginated \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": { "warehouseId": [1, 2] },
    "pageNumber": 1,
    "pageSize": 1000,
    "orderBy": ["id"],
    "limitFields": [
      "id", "productId", "warehouseId", "colorId", "sizeId", "lengthId", "dimensionId",
      "quantityInStock", "quantityBlocked", "quantityAvailable"
    ]
  }'

One row of the response:

{
  "id": 48213,
  "productId": 5120,
  "warehouseId": 1,
  "colorId": 4,
  "sizeId": 12,
  "lengthId": 0,
  "dimensionId": 0,
  "quantityInStock": 14,
  "quantityBlocked": 3,
  "quantityAvailable": 11
}

The stock filter also accepts the product criteria of the product search under filter.basic, for example groupId or productId, if you only need part of the assortment.

Understand the quantities

FieldMeaning
quantityInStockThe stock level WinShop has on record for the item ("In stock" in the WinShop application).
quantityBlockedThe quantity WinShop reports as blocked. The drill-down endpoints below show what blocks it: orders, reservations and other documents.
quantityAvailableThe quantity WinShop reports as available ("Available quantity" in the application). This is normally the number an e-shop shows; confirm it with the customer.
quantityOrdered, quantityOrderedAllWarehousesThe ordered quantity for this warehouse and across all warehouses. Not part of what you can sell now.
minQuantity, maxQuantity, optQuantityThe minimum, maximum and optimal stock level configured for the item. Planning values, not stock.

Use quantityAvailable as WinShop gives it to you. The API does not document how it is derived from the other fields, so do not calculate it yourself.

Quantities are decimals, because goods can be sold by weight or length.

To see what exactly blocks the stock of one item, the API has drill-down endpoints such as blocked goods in e-shop orders.

Aggregate and store

An e-shop usually wants one number per sellable thing: per variant, summed over the warehouses it sells from.

var stock = await LoadStockAsync();

var availability = stock
    .GroupBy(row => (row.ProductId, row.ColorId, row.SizeId, row.LengthId, row.DimensionId))
    .ToDictionary(group => group.Key, group => group.Sum(row => row.QuantityAvailable));

foreach (var (variant, quantity) in availability)
{
    // never publish a negative number
    var sellable = Math.Max(0, quantity);
    // update variant.ProductId / ColorId / SizeId in your system
}

A product or variant that has no stock item in your warehouses does not appear in the result at all. Treat "not in the result" as zero.

How often to poll

Stock changes all day: every sale at a cash register, every processed delivery note and every intake moves it. Polling is always a compromise between freshness and load.

  • Run the full read every 10 to 15 minutes as a baseline. With limitFields and a page size around 1000 it is a modest load even for a large assortment.
  • Do not overlap runs. Start the next run only after the previous one finished.
  • Do not poll single products in a loop. One paged search is far cheaper than thousands of single requests.
  • Re-check at the critical moment. Stock from a poll can be minutes old. If overselling is costly, check the items of a basket again at checkout. For a few products, the variant matrix for one warehouse returns the current quantityInStock and quantityBlocked per variant in one call.

Why webhooks are better, when you can get them

With polling you read the whole stock to find the few rows that changed, and you are still late by up to one interval. Webhooks turn that around: WinShop tells you when something changes, and you update just that item within seconds.

Webhooks are set up by WinShop support on request. If the customer can have them, use webhooks for freshness and keep a slow full read, for example nightly, as the safety net that corrects anything that was missed.

Reference

On this page