Skip to main content
This page is the curated reference. The complete, generated type reference lives at /kit/api/core and is regenerated from the published typings.
Everything here is read-only and needs the products:read scope, except shop.get(), which needs checkout:read. Only visible products come back; cost prices, suppliers and internal notes are never exposed to a publishable key. The data shapes are on Types. Every method takes an optional signal (an AbortSignal) to cancel the request on a route change or unmount. Currency. Every product read carries the client’s currency as ?currency= (see Currencies), and each read also takes a per-call currency: a code prices that one read in it, null reads the shop’s own prices. Every product states what its prices came back in as product.currency; format with that. A well-formed code the shop does not offer silently falls back to the shop’s currency; a malformed one throws a ShopkitConfigError before the request.

products.list

The catalog in the merchant’s own order. Accepts only paging. For anything a shopper navigates (a category page, a search box, a sorted grid) use products.search (below) instead: list() filters hidden products after paging, so its pages can come back shorter than limit.
number
default:"50"
Page size, 1 to 200. Above 200 is capped; 0 or a negative value is a 400.
string
The next_cursor from the previous page.
string | null
Price this read for a campaign storefront. Omitted means the client’s binding; null means the shop’s ordinary prices. See Campaign storefronts.
string | null
Price this read in another currency. Omitted means the client’s currency; null means the shop’s own. See Currencies.
AbortSignal
Product[]
boolean
string | null
Feed it back as cursor.
Filtered and sorted in the database, with visibility applied in the query so pages arrive full.
Free text, matched against product name, SKU, GTIN, variant SKU and GTIN, and option values. Words are AND-ed and order-independent ("merino crew" finds “Crew neck, merino”). Only the first 10 words count.
'name' | 'price' | 'createdAt'
default:"createdAt"
createdAt is the catalog order.
'asc' | 'desc'
default:"desc"
number
Inclusive lower bound in minor units (20000 is 200.00).
number
Inclusive upper bound in minor units. An inverted range (minPrice above maxPrice) is a 400.
string | number
"cat_12" or 12. Direct membership only: child categories are not walked.
number
default:"50"
1 to 200.
string
string | null
Same as on list().
string | null
Same as on list(). The results are converted; the price bounds and sort are not (see below).
AbortSignal
Price bounds and sortBy: "price" match the undiscounted list price, in the shop’s own currency, even when the results come back converted into another one. Discounts and the conversion are applied per page after the query, so a product can come back priced outside the bounds you asked for. Label price filters in shop.currency.
What search() does not do: return facet counts, filter by an option value across the catalog (“everything in black”), or match slugs.

products.get

One product by id, "prod_27" or 27. Resolves to null when the product does not exist or is not visible: a missing product is a normal answer, not an exception. Only this method returns relatedProducts on the product.

products.getBySlug

The API has no slug filter, so this pages through the catalog until it finds a match. The currency is resolved once, so every page of the walk is priced in the same one. Matching is case-insensitive and ignores surrounding slashes, so a route param works as is. maxPages defaults to 200.
On a large catalog, cache the lookup per slug, or build a slug-to-id map at deploy time from listAll() and call get(), which is a single request.

products.listAll

Every product, for static params and sitemaps. Bounded at 200 pages. Do not call it while rendering a request.

categories.list

boolean
Only top-level categories.
string
Children of one category, one level down.
string
number
string
AbortSignal
Categories sit behind products:read. A category page is products.search({ categoryId }). To include products that live only in child categories, walk the tree with categories.list({ parentId }) and query each.

categories.get

null when the category does not exist.

shop.get

Name, logo, brand colour, language, terms URL, the currencies the shop offers and its tracking ids: what a storefront shell needs before it renders. Requires checkout:read, because it is served by the checkout’s shop endpoint, the only shop surface a publishable key can reach.
string | null
The shop’s own currency, upper-case ISO 4217. Absent on a platform older than the field.
ShopCurrency[]
Every currency a shopper may browse in, base first: { code, mode: "base" | "display" | "charge", rate }. Only the base entry when the merchant’s currency converter is off. See Currencies.
ShopTracking | null
The merchant’s GA4 measurement id, GTM container id and Meta pixel id (validated by the platform; null when unset), and whether the platform sends Meta Conversions API events. What the kit’s analytics loads by default. See Consent and analytics.
The full shape is on Types.

Shop cache

The shop does not change while a page is open, and every currency switcher, useCurrency() and <qb-currency-select> needs it. This cache gives them one request between them. A rejected read is evicted, so the next caller retries.

Product lookup cache

The promise cache behind <ProductProvider slug|id> and <qb-product>. Two lookups of the same product share one request. Entries are keyed on the currency (the lookup’s own, else the client’s current one) and the campaign, so a currency switch never hands back a promise priced in the old currency. Call clearProductCache after a revalidation in a long-lived browser session.