Skip to main content

List Inventory Comparison

GET 

/api/storefront/instances/:id/inventory

One row per SKU this store sells, comparing the quantity SKU.io would send right now against the quantity the store was last told. Rows are the outbound listings for connection 1; nothing here is fetched live from the store.

Not yet available to API tokens

This endpoint currently requires session authentication; Personal Access Token scope support is in progress.

How the compared quantity is built (inventory.sku_quantity): sum SKU.io available stock for the listing's product across the connection's selected warehouses — or the tenant-wide total row when no warehouses are selected — subtract the connection's inventory buffer, then floor at 0. inventory.store_quantity is the quantity last pushed (null before the first push) and inventory.variance is sku_quantity minus store_quantity (null before the first push).

inventory.status — the derived comparison status, one of five values:

  • in_sync — the last pushed quantity equals what SKU.io would send now; the next push skips it.
  • variance — the last pushed quantity differs from what SKU.io would send now; the next push re-sends this SKU.
  • never_pushed — no inventory has been pushed for this SKU yet.
  • unknown_on_store — the store answered the last push saying it holds no product with this SKU, so the quantity went nowhere. Create or map the product on the store, then push again.
  • not_managed — nothing will ever push this row, so no comparison is meaningful. Two things put a row here: the connection's master of stock is not SKU.io, or the SKU.io product has left the push-eligible set (archived, not a sellable type, or its SKU cleared). This takes precedence over the quantity comparison — a row whose numbers happen to match still reports not_managed, never in_sync. inventory.is_managed carries the same fact as a boolean.

Row cross-links. sku_product_id / sku_product_route point at the SKU.io product; storefront_product_id / storefront_product_route point at the imported store product mirroring the same SKU, and are null when the store catalogue has no match for it. Both *_route values are relative in-app link paths — append them to your SKU.io base URL to open the record; they are navigation hints, not API endpoints.

Store-reported stock. store_reported_quantity / store_reported_at are what the STORE said it holds for this SKU when the catalogue was last imported. They are a read-only observation and never take part in the comparison or the push. A null store_reported_quantity means the store reported no stock record for the SKU — it does not mean zero.

Filters:

  • filter[search] — fuzzy match across the listing SKU, the listing name, and the SKU.io product's SKU and name, plus an exact match on the listing id when the term is all digits (so a text term starting with a digit never drags in row 1). Narrow it with the top-level search_columns (comma list of id, external_id, name, product.sku, product.name) and force = instead of LIKE for chosen columns with search_strict_columns.
  • filter[status] — the derived status above. Accepts one value or a comma-separated list; an unrecognised value matches nothing rather than everything.
  • filter[inventory_push_status] — the raw outcome of the last inventory push for the listing, as a comma-separated list of pending, pushed, failed, unknown, deactivated. This is the stored push result, not the derived comparison status.
  • filter[id], filter[store_quantity] (last pushed quantity), filter[sku_quantity] (the derived SKU.io quantity), filter[variance] (the derived difference) — numeric.
  • filter[external_id] (the listing SKU), filter[name] — text.
  • filter[inventory_pushed_at], filter[created_at], filter[updated_at] — date/time.

Operator syntax — every filter below also accepts filter[<field>.<operator>]=<value>; the bare filter[<field>]=<value> form is the implicit is.

  • Text operators: contains, does_not_contain, is, is_not, is_one_of, is_not_one_of, starts_with, does_not_start_with, ends_with, does_not_end_with, is_empty, is_not_empty.
  • Numeric operators: is, is_not, is_one_of, is_not_one_of, greater_than, less_than, greater_than_or_equal, less_than_or_equal, between (comma-separated pair), is_empty, is_not_empty.
  • Date/time operators: is, is_not, before, after, on_or_before, on_or_after, between, is_empty, is_not_empty, today, yesterday, tomorrow, past_week, past_month, past_year, next_week, next_month, next_year, days_ago, days_from_now, past_days, next_days (the last four take a number of days).
  • is_one_of / is_not_one_of take a comma-separated list.

filter_groups takes a base64-encoded JSON tree of the same filter keys, so conditions can be combined with AND/OR and nested groups: {"conjunction":"and","children":[{"type":"condition","condition":{"column":"status.is","operator":"is","value":"variance"}}]}. A tree that references a key not listed here is rejected rather than silently ignored.

Sorting: sort= id, sku, external_id, name, store_quantity, sku_quantity, variance, inventory_pushed_at, created_at, updated_at. Prefix with - for descending. Default: external_id ascending. sku_quantity and variance sort on the derived expression, not a stored column.

Pagination: page (default 1) and per_page (default 10, clamped to 1-200). The response is a paginated envelope: data, current_page, last_page, per_page, total, from, to.

Authentication: Bearer token (session or PAT).

Request​

Responses​

OK

Response Headers
    Content-Type