WinShopAPI docs
Concepts

Filtering and pagination

How every list endpoint works - the filter-paginated request, sorting, field selection and paging.

Large lists are never returned by a plain GET. Every searchable resource has a POST …/filter-paginated endpoint instead, for example POST /api/products/filter-paginated or POST /api/documents/expedition/delivery-notes/filter-paginated. It is a POST only because the search criteria travel in the body. It changes nothing on the server and is safe to repeat.

All of these endpoints share one request shape and one response shape. Only the filter object and the rows in data differ.

Request

{
  "filter": {
    "basic": {
      "dateFrom": "2026-10-01T00:00:00",
      "dateTo": "2026-10-31T23:59:59",
      "customerId": [1042],
      "documentStateId": [2, 3]
    }
  },
  "pageNumber": 1,
  "pageSize": 100,
  "orderBy": ["dateOfDocument desc", "id"],
  "limitFields": ["id", "internalNumber", "dateOfDocument", "customerName", "totalPrice"]
}
FieldTypeMeaning
filterobjectSearch criteria. The shape is different for every endpoint; its reference page lists the fields. Every field is optional, and the ones you set are combined with AND. An array field matches any of its values.
pageNumberintegerPage to return, starting at 1.
pageSizeintegerRows per page. See the warning below.
orderBystring[]Sort order, most significant first. Each entry is a field name, optionally followed by a space and desc.
limitFieldsstring[]Names of the fields you want back. Leave it out to get all of them.

Always set pageSize

If you leave pageSize out, the API returns every matching row in one response. -1 asks for the same thing explicitly. On a real catalog or a few years of documents that is a very large response. Pick a page size that suits the data and page through: 100 to 500 rows when you read whole rows, up to a few thousand when limitFields keeps each row to a handful of fields.

Sorting

orderBy takes the names of the fields in the response rows. Each entry must be one word, or one word plus a direction: "totalPrice", "totalPrice desc". Formally, an entry has to match ^\w+(\s+\w+)?$. Anything else, such as a comma-separated list in one string, is rejected.

Always sort by something unique last, such as id. Without a stable order, rows can move between pages while you read them.

Selecting fields

limitFields cuts the response down to the columns you name, which makes large syncs much faster. A name the endpoint does not know is rejected, and the error message says which one.

When you use limitFields, rely only on the fields you asked for. Ignore everything else in the row.

Response

{
  "data": [
    {
      "id": 77120,
      "internalNumber": 2600418,
      "dateOfDocument": "2026-10-09T00:00:00",
      "customerName": "Example Retail s.r.o.",
      "totalPrice": 12450.5
    }
  ],
  "currentPage": 1,
  "totalPages": 3,
  "totalCount": 212,
  "pageSize": 100,
  "hasPreviousPage": false,
  "hasNextPage": true
}
FieldMeaning
dataThe rows of this page.
currentPageThe page you asked for.
totalPagesNumber of pages for this filter and page size.
totalCountNumber of rows that match the filter, across all pages.
pageSizeRows per page.
hasPreviousPage, hasNextPageWhether there is a page before or after this one.

Loop while hasNextPage is true.

When a list request is rejected

Three mistakes in the request make a list endpoint answer 400 Bad Request. The message tells you which one:

MistakeMessage in messages
A pageNumber beyond totalPages, unless the result is emptyPage number is too high, max is: 3
A name in limitFields that the endpoint does not knowThe field 'colour' does not exists
An orderBy entry that is not a word, or a word plus a directionInvalid order-by field: 'id; name'

Do not retry these. Read messages and fix the request. See Errors for the error format.

Fields differ between instances

The list columns come from a database view the customer can change

The rows of a filter-paginated endpoint are read from a SQL view inside the WinShop database, and a customer can have that view customised. The reference shows the columns of the demo instance. If a name in orderBy or limitFields is rejected on one instance but works on another, the column probably does not exist there. Ask the customer or WinShop support, and keep the field lists of your integration configurable.

Full example

List the delivery notes of one customer for October 2026, newest first, 100 per page. A delivery note is the document that records goods leaving a warehouse for a customer; see Documents. documentStateId is the customer-defined state of the document.

curl -X POST https://<your-instance>/api/documents/expedition/delivery-notes/filter-paginated \
  -H "Authorization: Bearer $ACCESS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "filter": {
      "basic": {
        "dateFrom": "2026-10-01T00:00:00",
        "dateTo": "2026-10-31T23:59:59",
        "customerId": [1042],
        "documentStateId": [2, 3]
      }
    },
    "pageNumber": 1,
    "pageSize": 100,
    "orderBy": ["dateOfDocument desc", "id"],
    "limitFields": ["id", "internalNumber", "dateOfDocument", "customerName", "totalPrice"]
  }'

The filter fields and the full list of row fields are on the reference page: Search delivery notes.

On this page