List Store Products
GET/api/storefront/instances/:id/products
The store's own catalogue as mirrored into SKU.io — one row per store product, with the SKU.io product it is mapped to.
This endpoint currently requires session authentication; Personal Access Token scope support is in progress.
The store keys its catalogue by SKU, so storefront_product_id and sku carry the same value: the store's product key IS its SKU.
The mapping fields (product, subscription_offering, revenue_line, mapped_sku, mapped_at, product_listing_id, is_mapped) are TOP-LEVEL keys on each row, never nested under a mapped_product object.
store_available is null when the store holds no stock record for that SKU. That is not a quantity of zero and must not be rendered as one.
Filters (all sent as filter[<key>]):
filter[search]— free-text term. Pair it with the top-levelsearch_columns(comma-separated) to restrict which columns are searched, andsearch_strict_columnsto make a listed column match exactly instead of partially. Searchable columns:id(ALWAYS exact — a numeric term never partially matches an id),sku,storefront_product_id(the store's own product key) andunified_title(the store's product name).filter[ids]— comma-separated list (or array) of store-product ids. Used to act on, or export, an explicit selection.filter[mapping_status]—mappedorunmapped.allis a no-op.filter[mapped]— boolean equivalent of the above (true/false).filter[status]—activeorinactive(computed from the store's active flag).allis a no-op.filter[archived]—true,falseorall. When the parameter is absent entirely, archived products are hidden; sendallto see both.
Every column below also accepts operator filters, written filter[<column>.<operator>]:
- Text columns
sku,unified_title,storefront_product_id,status— operatorscontains,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 columns
id,price,store_available— operatorsis,is_not,is_one_of,is_not_one_of,greater_than,less_than,greater_than_or_equal,less_than_or_equal,between,is_empty,is_not_empty. - Date/time columns
store_updated_at,created_at,updated_at— operatorsis,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. filter[mapped.is],filter[archived.is]andfilter[archived.is_not]take a boolean.- Writing a column bare (
filter[sku]=ABC) is the same as itsisoperator.
filter_groups combines conditions with AND/OR: base64 of a JSON tree such as {"conjunction":"and","children":[{"type":"condition","condition":{"column":"mapped","operator":"is","value":"false"}}]}. A tree that cannot be parsed is ignored by this list endpoint (but rejected by the bulk endpoints).
Sorting: sort accepts id, sku, price, store_available, store_updated_at, created_at, updated_at, position, storefront_product_id, unified_title and status. Prefix with - for descending. Default: -id.
Pagination: page (default 1) and per_page (default 10).
Authentication: Bearer token (session or PAT).
Request
Responses
- 200
- 401
- 403
- 404
- 429
OK
Response Headers
Unauthenticated — the bearer token is missing, revoked, expired, or malformed. Never retry automatically; fix the credential. See the Errors guide.
Forbidden — the token lacks a required scope, the endpoint is not available to API tokens, or the user behind the token lacks the permission. A human must adjust the token scopes or user permissions; do not retry.
Not found — no record with the given identifier (or the route does not exist). Verify the ID before retrying.
Rate limited — platform limit is 1,000 requests/min; individual tokens may carry lower limits. Honor the Retry-After header before retrying. See the Rate Limits guide.