The calls behind the four kinds of page every storefront has, in the order they happen, with the API for each step. Catalogue and product pages are cached Discovery reads with per-shopper parts streamed in. The cart and checkout run on the Shop API from your server.
Home, category, brand and landing pages are the same for every visitor except for a few personal parts. Build them that way:
facets only where filters are shown. Facets are a large part of a listing's response.A category listing is one browse on the product shape, filtered on the folder path at any depth, with the facets the sidebar shows:
query Category($path: String!) {
browse {
product(
language: en
filters: { parentPaths: { equals: $path } }
facets: { brand_items_name: { limit: 10 }, attributes_value: { limit: 10 } }
pagination: { limit: 24 }
) {
summary {
totalHits
hasMoreHits
endToken
facets
priceRange(priceIdentifier: "default") { min max }
}
hits {
itemId
name
path
defaultVariant {
sku
defaultPrice
firstImage {
url
altText
variants(types: "webp", maxWidth: 768) { url width height }
}
}
}
}
}
}query Category($path: String!) {
browse {
product(
language: en
filters: { parentPaths: { equals: $path } }
facets: { brand_items_name: { limit: 10 }, attributes_value: { limit: 10 } }
pagination: { limit: 24 }
) {
summary {
totalHits
hasMoreHits
endToken
facets
priceRange(priceIdentifier: "default") { min max }
}
hits {
itemId
name
path
defaultVariant {
sku
defaultPrice
firstImage {
url
altText
variants(types: "webp", maxWidth: 768) { url width height }
}
}
}
}
}
}summary.facets comes back as a hash keyed by facet field, with a count and a label per value. Each value carries the filter field to send back, so a facet link can be a plain URL that an agent or crawler can follow. Page through results with endToken as pagination.after. The Discovery API pages cover filters, sorting and pagination in full.
search with a path filter and a fragment for the shape. Paths are unique only within their folder, so never look a product up by its last path segment.variant(selected:) and shows stock from the variant's stock location.query Product($path: String!) {
search(language: en, filters: { path: { equals: $path } }, pagination: { limit: 1 }) {
hits {
... on product {
itemId
name
path
updatedAt
breadcrumbs { name path }
variants {
sku
name
attributes
defaultPrice
defaultStock
images { url altText variants(types: "webp") { url width height } }
}
selected: variant(selected: [{ attribute: "Color", value: "Olive" }]) {
sku
defaultPrice
defaultStock
}
}
}
}
}query Product($path: String!) {
search(language: en, filters: { path: { equals: $path } }, pagination: { limit: 1 }) {
hits {
... on product {
itemId
name
path
updatedAt
breadcrumbs { name path }
variants {
sku
name
attributes
defaultPrice
defaultStock
images { url altText variants(types: "webp") { url width height } }
}
selected: variant(selected: [{ attribute: "Color", value: "Olive" }]) {
sku
defaultPrice
defaultStock
}
}
}
}
}breadcrumbs is a list of trails, one per path to the item, and each trail ends with the item itself. Attribute names and values in variant(selected:) are case-sensitive. A name that only matches in another case returns null and adds a warning under extensions.warnings.
Paths are translated, so the same product has a different path in each language. Read them all in one request, one alias per language, joined on the item id:
query Paths($id: String!) {
en: search(language: en, filters: { itemId: { equals: $id } }, pagination: { limit: 1 }) { hits { path } }
no: search(language: no, filters: { itemId: { equals: $id } }, pagination: { limit: 1 }) { hits { path } }
sv: search(language: sv, filters: { itemId: { equals: $id } }, pagination: { limit: 1 }) { hits { path } }
}query Paths($id: String!) {
en: search(language: en, filters: { itemId: { equals: $id } }, pagination: { limit: 1 }) { hits { path } }
no: search(language: no, filters: { itemId: { equals: $id } }, pagination: { limit: 1 }) { hits { path } }
sv: search(language: sv, filters: { itemId: { equals: $id } }, pagination: { limit: 1 }) { hits { path } }
}A missing alias result means the item is not published in that language. Leave that language out of hreflang and the language switcher.
The browser holds only the cart id, in an httpOnly cookie. The full flow, with the price context, is on Cart, checkout and orders.
setCustomer), then any cart metadata (setMeta), then lock the cart with place. After place the cart can't change. If the shopper goes back, start a new cart.place returned.createFromCart, passing pipelines, payment status and payments in the same call.createFromCart returned. Reading it back by id can briefly answer "not found", so retry rather than fail.orders(customerIdentifier). A new order can take from seconds to minutes to appear there, so the confirmation page should say so.The Checkout Flow Tutorial walks through hydrate, place and createFromCart with full queries. Orders is the reference for order mutations, payments and pipelines.