The API
The Stock Count API is what the Hii Retail Inventory app uses, and it is available to integrations on the same terms — for planning counts centrally, counting from another client, or reading results.
https://stock-count-api.retailsvc.com/api/v1
Every request needs a Hii Retail access token and is made for one tenant. The permission each endpoint
requires is listed in the OpenAPI document.
Creating, editing, deleting and submitting a count are permitted per count type — a user can be
allowed to run cycle counts without being allowed to submit a full count — which is why those endpoints
take the count's type as a query parameter.
Every write is asynchronous
🛑 Every endpoint that changes something returns 202 Accepted once the request is valid, and the
change is applied a moment later. That covers creating, editing and deleting counts, registering and
deleting lines, marking a category as done, submitting, importing, and every recurring-definition write.
- A count read back immediately after it was created can return
404. Retry after a short delay, or poll. - A newly created count holds no items until its list has been prepared:
itemsGeneratedDateTimeisnulluntil then. See How a count works. - A
202means the request was accepted, not that it was applied. The API rejects a line for a count that is already completed or deleted, but a line sent in the same moment as the submission can be accepted and still miss the count: once a count is submitted, its published result does not change. Finish counting before submitting.
Retrying safely
This is about your retries — a client resending a request because it timed out or got no answer. Stock Count's own processing needs no care from you: the API gives each request its identifiers before passing it on, so a request that is delivered twice inside the service is recognised and applied once.
A retry from the client, though, is a new request, and the API cannot tell it from a second, different one — unless it carries your identifier:
| Request | Identifier to supply | A client retry without it |
|---|---|---|
| Create a count | stockCountId in the body | creates a second count |
| Register a line | lineId in the body | ⚠ creates a second line, and the item's counted quantity doubles — see below |
| Create a recurring definition | recurringStockCountId in the body | creates a second definition |
Why a line can double although countedQuantity is a total. countedQuantity is the total for
that line: sending the same lineId again replaces the line's quantity, it never adds to it. An item's
counted quantity, on the other hand, is the sum of all its lines — deliberately, because that is how
an item found in several places is counted: 10 on shelf A, 14 on shelf B and 20 in the back room are
three lines, and the item's count is 44.
A line sent without a lineId is given a new one by the API every time, so to Stock Count a retried
request without a lineId looks exactly like another location being counted: a second line carrying
the same quantity, and both are added up. With a lineId, the retry replaces the line with the figure
it already has, and nothing changes.
With identifiers, repeating a request is harmless: a create for an id that exists changes nothing, and a
line for an existing lineId replaces that line. Submitting a count that is already completed does not
complete it again.
Planning counts
| Endpoint | What it does |
|---|---|
POST /business-units/{businessUnitId}/stock-counts?type=… | Create a count: name, start date, optional due date and comment, and — for a cycle count — its saved searches and stock-state filters. See Types of count. |
PUT /business-units/{businessUnitId}/stock-counts/{stockCountId}?type=… | Change a count's name, dates, comment, saved searches or stock-state filters. |
DELETE /business-units/{businessUnitId}/stock-counts/{stockCountId}?type=… | Delete a count. Its items are released and nothing is published. |
POST /business-units/{businessUnitId}/stock-counts:items-not-counted?type=… | Create a count of every item that has moved this year and not been counted this year. CYCLE or TEST. |
POST /business-units/{businessUnitId}/stock-counts/{stockCountId}/import | Create a count with an item list you supply. CYCLE (default) or TEST. |
A saved search is given either as searchSelectionId — a search selection saved in Product, Price and
Promotion — or as query, a search written out directly, plus isMandatory (default false).
Counting
| Endpoint | What it does |
|---|---|
PUT /business-units/{businessUnitId}/stock-counts/{stockCountId}/lines | Register or replace one line: item, location, countedQuantity. Returns the deviation thresholds the item's counted total now exceeds. |
DELETE /business-units/{businessUnitId}/stock-counts/{stockCountId}/lines/{lineId} | Remove a line. |
POST /business-units/{businessUnitId}/stock-counts/{stockCountId}/item-categories/{itemCategoryId}:completed | Mark a category as done: its uncounted mandatory items are registered as 0. |
POST /business-units/{businessUnitId}/stock-counts:quick-count | Count one item and submit at once — see Quick count. |
POST /business-units/{businessUnitId}/stock-counts/{stockCountId}:submit?type=… | Submit the count. |
About a line:
- The item is given as
itemId, or asitemIdentifier(a barcode such as a GTIN) which Stock Count resolves through Product, Price and Promotion. One of the two is required. - A line can be registered for any item, whether or not the count lists it. That is how a control count — which has no list — is counted through the API.
locationis free text. The app numbers an item's locations1,2,3; an integration can use whatever names mean something in the store. Lines at the same location are separate lines; they are added up with the rest.countedQuantityis zero or more and may have decimals, for items sold by weight or length.- The line is stamped with the time it is registered — the request carries no time of its own. That time decides how sales during the count are treated; see Counting while the store is open.
- Optional
batchNumber,serialNumberandbusinessPartnerIdidentify what was counted more exactly, and are passed on in the published count. ⚠ Counting one batch of an item counts all of them: when STP applies a count that names batches or serial numbers for an item, it sets every other batch or serial number of that item, not named in the count, to 0. Count every batch of an item in the same count, or none by batch.
Reading counts
| Endpoint | Returns |
|---|---|
GET /business-units/{businessUnitId}/stock-counts | The store's counts. Filter with statuses, startDateFrom/startDateTo, completedDateFrom/completedDateTo; future and completed counts are included only when asked for (doIncludeFutureStockCounts, doIncludeCompletedStockCounts). |
GET /business-units/{businessUnitId}/stock-counts/{stockCountId} | One count: its settings, status, filters, progress per category, itemsGeneratedDateTime, and its lines (paged with take and skip). |
GET /business-units/{businessUnitId}/stock-counts/{stockCountId}/item?itemId=… | One item in the count, with its lines. Also accepts itemIdentifier. |
GET /business-units/{businessUnitId}/stock-counts/{stockCountId}/items:not-counted | The listed items nobody has counted yet. |
GET /business-units/{businessUnitId}/stock-counts/{stockCountId}/item-categories | The categories the count's items fall into, with counted and not-counted totals. |
GET /business-units/{businessUnitId}/stock-counts/{stockCountId}/item-categories/{itemCategoryId}/items | The items of one category, counted and not. |
GET /business-units/{businessUnitId}/stock-counts/{stockCountId}/locations | The locations used in the count so far. |
Reports
The reports compare what was counted with what was expected, per item or per category, valued at the item's cost. They can be read while the count is open as well as after it is completed.
| Endpoint | Returns |
|---|---|
GET …/stock-counts/{stockCountId}/counts/categories | Counted and not-counted items per category. |
GET …/stock-counts/{stockCountId}/counts/items | Counted and expected quantity and value per item. |
GET …/stock-counts/{stockCountId}/counts/items:deviations | The deviation per item, in quantity, percentage and value. |
All three can be narrowed to one itemCategoryId. The item reports take doExcludeWithinThreshold=true
to leave out every item within the store's deviation thresholds,
and take and skip for paging.
Recurring definitions
| Endpoint | What it does |
|---|---|
POST /recurring-stock-counts | Create a definition |
GET /recurring-stock-counts | List the tenant's active definitions |
GET /recurring-stock-counts/{recurringStockCountId} | Read one definition |
PUT /recurring-stock-counts/{recurringStockCountId} | Replace a definition |
DELETE /recurring-stock-counts/{recurringStockCountId} | Stop a definition. Counts it already generated are not affected. |
GET /recurring-stock-counts/occurrences?from=…&to=… | The dates every definition will generate counts on in the range |
GET /recurring-stock-counts/{recurringStockCountId}/occurrences?from=…&to=… | The same for one definition |
Definitions belong to the tenant, not to a store — the scope inside the definition decides which stores are counted. See Recurring counts.
Read next
- Events — receiving completed counts instead of polling for them
- Types of count — what each create endpoint produces
- OpenAPI document — request and response shapes