Skip to content

Storefront Collections

Storefront

Storefront Collections groups 4 operations on the storefront tier.

Storefront tier. Reachable anonymously; a public vnstss_ token may be sent to identify the storefront.

GET

/api/{version}/collections

AuthenticationAnonymousStorefront tier. Reachable anonymously; a public vnstss_ token may be sent to identify the storefront.
curl -X GET \
  'https://<your-shop-domain>/api/2026-04-01/collections' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer vnstss_<token>'
Response200example shape
{
  "collections": [
    {
      "id": "00000000-0000-0000-0000-000000000000",
      "handle": "string",
      "title": "string",
      "body_html": "string",
      "image": {
        "id": "00000000-0000-0000-0000-000000000000",
        "src": "string",
        "preview_src": "string",
        "alt": "string",
        "position": 1,
        "width": 1,
        "height": 1
      },
      "products_count": 1,
      "sort_order": "string",
      "meta_title": "string",
      "meta_description": "string",
      "custom_fields": [
        {}
      ]
    }
  ]
}
GET

/api/{version}/collections/{id}

AuthenticationAnonymousStorefront tier. Reachable anonymously; a public vnstss_ token may be sent to identify the storefront.

Path parameters

NameTypeDescription
id
required
string (uuid)
curl -X GET \
  'https://<your-shop-domain>/api/2026-04-01/collections/<id>' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer vnstss_<token>'
Response200example shape
{
  "collection": {
    "id": "00000000-0000-0000-0000-000000000000",
    "handle": "string",
    "title": "string",
    "body_html": "string",
    "image": {
      "id": "00000000-0000-0000-0000-000000000000",
      "src": "string",
      "preview_src": "string",
      "alt": "string",
      "position": 1,
      "width": 1,
      "height": 1
    },
    "products_count": 1,
    "sort_order": "string",
    "meta_title": "string",
    "meta_description": "string",
    "custom_fields": [
      {
        "key": "string",
        "label": "string",
        "value": "string",
        "type": "string"
      }
    ]
  }
}
GET

/api/{version}/collections/{id}/products

AuthenticationAnonymousStorefront tier. Reachable anonymously; a public vnstss_ token may be sent to identify the storefront.

Path parameters

NameTypeDescription
id
required
string (uuid)

Query parameters

NameTypeDescription
limit
optional
integer (int32)

Page size. Clamped to 1..250 by the handler.

page_info
optional
string

Opaque cursor. When present, filter params must match those that produced the cursor.

q
optional
string

Free-text search within the collection.

vendor
optional
string (uuid)

Manufacturer (vendor) filter.

order
optional
string

Sort spec, e.g. "price asc" | "created desc" | "title asc".

color_id
optional
string

Colour facet ids (facets[key=colors].values[].id).

region_id
optional
string

Region facet ids.

year_id
optional
string

Vintage facet ids.

country_id
optional
string

Country facet ids.

size_id
optional
string

Bottle-size facet ids.

category_id
optional
string

Category facet ids. AND'd: a product must sit in every category passed.

custom_field_id
optional
string

Custom-field option ids (facets[key=custom_fields].values[].id) — the dimension grape variety and other tenant-defined dropdowns surface under.

price_min
optional
number (double)

Lower bound on the gross price, in the request's active currency.

price_max
optional
number (double)

Upper bound on the gross price, in the request's active currency.

available
optional
boolean

true keeps only products that are buyable right now. Omit it — do not send available=false — to list the whole catalog including sold-out products, which is the default. false is accepted and means the same as omitting it; there is no "sold out only" listing.

on_sale
optional
boolean

true keeps only products with at least one variant on offer — a retail price whose compare_at_price is above the price actually charged. Same convention as available: omit for the whole catalog.

include
optional
string

Comma-separated extras to embed in the response. facets adds the facet set for the current filters, saving the separate /facets round trip when first painting a sidebar next to a grid. Ask for it on the first page only. Facets describe the whole filtered catalog, not the page, so they are identical on every page — and recomputing them costs an extra search per filtered dimension.

IncludeFacets
optional
boolean

Whether include asked for the embedded facet set.

Responses

curl -X GET \
  'https://<your-shop-domain>/api/2026-04-01/collections/<id>/products' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer vnstss_<token>'
Response200example shape
{
  "products": [
    {
      "id": "00000000-0000-0000-0000-000000000000",
      "handle": "string",
      "title": "string",
      "body_html": "string",
      "image": "string",
      "available": true,
      "currency": "string",
      "price_min": 1,
      "price_max": 1,
      "variants_count": 1,
      "manufacturer": {
        "id": "00000000-0000-0000-0000-000000000000",
        "name": "string",
        "logo_url": "string"
      },
      "flag": {
        "name": "string",
        "color": "string"
      },
      "rating": 1,
      "rating_count": 1,
      "custom_fields": [
        {}
      ],
      "variants": [
        {}
      ]
    }
  ],
  "facets": [
    {
      "key": "string",
      "values": [
        {}
      ]
    }
  ],
  "price_range": {
    "min": 1,
    "max": 1,
    "currency": "string"
  }
}
GET

/api/{version}/collections/{id}/facets

AuthenticationAnonymousStorefront tier. Reachable anonymously; a public vnstss_ token may be sent to identify the storefront.

Path parameters

NameTypeDescription
id
required
string (uuid)

Query parameters

NameTypeDescription
q
optional
string

Free-text search.

vendor
optional
string (uuid)

Manufacturer (vendor) filter — the manufacturers facet's own dimension.

color_id
optional
string

Colour facet ids (facets[key=colors].values[].id).

region_id
optional
string

Region facet ids.

year_id
optional
string

Vintage facet ids.

country_id
optional
string

Country facet ids.

size_id
optional
string

Bottle-size facet ids.

category_id
optional
string

Category facet ids. AND'd: a product must sit in every category passed.

custom_field_id
optional
string

Custom-field option ids (facets[key=custom_fields].values[].id) — the dimension grape variety and other tenant-defined dropdowns surface under.

price_min
optional
number (double)

Lower bound on the gross price, in the request's active currency.

price_max
optional
number (double)

Upper bound on the gross price, in the request's active currency.

available
optional
boolean

true keeps only products that are buyable right now. Omit it — do not send available=false — to list the whole catalog including sold-out products, which is the default. false is accepted and means the same as omitting it; there is no "sold out only" listing.

on_sale
optional
boolean

true keeps only products with at least one variant on offer — a retail price whose compare_at_price is above the price actually charged. Same convention as available: omit for the whole catalog.

include
optional
string

Comma-separated extras to embed in the response. facets adds the facet set for the current filters, saving the separate /facets round trip when first painting a sidebar next to a grid. Ask for it on the first page only. Facets describe the whole filtered catalog, not the page, so they are identical on every page — and recomputing them costs an extra search per filtered dimension.

IncludeFacets
optional
boolean

Whether include asked for the embedded facet set.

curl -X GET \
  'https://<your-shop-domain>/api/2026-04-01/collections/<id>/facets' \
  -H 'Accept: application/json' \
  -H 'Authorization: Bearer vnstss_<token>'
Response200example shape
{
  "facets": [
    {
      "key": "string",
      "values": [
        {}
      ]
    }
  ],
  "price_range": {
    "min": 1,
    "max": 1,
    "currency": "string"
  }
}

Schemas

ApiErrorResponse

The error envelope every non-2xx response from this API uses. Documentation shape: actions build it as an anonymous object, so this type exists to give the OpenAPI document a schema to point at.

  • errorsstringnullable

    Human-readable description of what went wrong, e.g. Not Found, Invalid page_info.

  • codestringnullable

    Machine-readable error code. Only a few endpoints (checkout) emit one; omitted everywhere else.

StorefrontCollectionDto

Storefront representation of a published collection. body_html, meta_* and custom_fields are only present on single-collection reads. Text is returned in the request's active language, falling back to the collection's stored default text.

  • idstring (uuid)
  • handlestringnullable
  • titlestringnullable
  • body_htmlstringnullable
  • products_countinteger (int32)
  • sort_orderstringnullable
  • meta_titlestringnullable
  • meta_descriptionstringnullable
  • custom_fieldsStorefrontCustomFieldDto[]nullable

    Tenant-defined attributes of the collection; empty when none are set.

StorefrontCollectionListResponse

Envelope returned by GET /collections.

  • collectionsStorefrontCollectionDto[]nullable

    Every published collection. Always present; an empty array when the tenant has none.

StorefrontCollectionResponse

Envelope returned by GET /collections/{id}.

StorefrontCustomFieldDto

Storefront custom field: a tenant-defined attribute (key, localized label, value, kind).

  • keystringnullable
  • labelstringnullable
  • valuestringnullable
  • typestringnullable

StorefrontFacetDto

Storefront filter facets: one entry per dimension (manufacturers, categories, colors, sizes, years, countries, regions, custom_fields), each with its selectable values and product counts. Drives a faceted-search / filter sidebar, mirroring ShopController's filters.

  • keystringnullable

    Dimension key. One of a closed set, always emitted in this order: manufacturers, categories, colors, sizes, years, countries, regions, custom_fields. No key is guaranteed to be present. A dimension is emitted only when at least one of its values has a non-zero product count for the current filters, so the key set is data-dependent — it varies by tenant, by language and by the filters on the request. Treat a missing key as "this dimension has nothing to offer here", not as an error, and never hard-code the key set observed on one tenant. Conversely, no key outside the eight above is ever returned. custom_fields is the catch-all for tenant-defined attributes: every configured custom field's options are flattened into this one dimension rather than getting a key of their own. On a wine tenant grape variety arrives here, alongside anything else the tenant has configured. Use each value's name for display and its id as the custom_field_id filter token; there is no per-field grouping in the response.

  • The selectable values for this dimension. Never empty — a dimension with no matching values is omitted from the response instead. Values whose count would be zero are dropped.

StorefrontFacetRefDto

One facet value: the id to filter by and its localized label. name is null while the tenant's periodically-rebuilt filter snapshot doesn't yet carry the id — membership is still reported.

  • idstring (uuid)
  • namestringnullable

StorefrontFacetsResponse

Envelope returned by GET /products/facets and GET /collections/{id}/facets, and by the facets member of Cloudwawi.Shop.Api.V2026_04_01.Storefront.StorefrontProductListResponse.

  • facetsStorefrontFacetDto[]nullable

    One entry per facet dimension that has at least one matching value. See Cloudwawi.Shop.Api.V2026_04_01.Storefront.StorefrontFacetDto.Key for the closed set of keys and which of them are data-dependent. Always present; an empty array when the tenant has no filters configured or nothing matches.

StorefrontFacetValueDto

One selectable facet value: filter token id, localized name, matching product count.

  • idstringnullable

    Filter token to send back, as a string (GUIDs are rendered in their usual dashed form). Which query parameter it belongs to follows from the facet key: categoriescategory_id, colorscolor_id, sizessize_id, yearsyear_id, countriescountry_id, regionsregion_id, custom_fieldscustom_field_id, manufacturersvendor.

  • namestringnullable

    Display label in the request's language; may be null when the tenant left it untranslated.

  • valuestringnullable

    Raw value for custom-field options; null for entity-backed facets.

  • countinteger (int32)

    Number of products that would match if this value were selected. Always greater than zero. Counts are self-excluding within a dimension: for a dimension the caller has already filtered on, the counts ignore that dimension's own selection, so the other options in the same list stay clickable.

StorefrontFlagDto

Storefront product badge/flag: display name and CSS colour.

  • namestringnullable
  • colorstringnullable

StorefrontImageDto

Storefront representation of a product image. An image is an object (id, src, alt, position, width, height) rather than a bare URL, so clients get the gallery order, accessibility text, and intrinsic dimensions.

  • idstring (uuid)
  • srcstringnullable
  • preview_srcstringnullable
  • altstringnullable
  • positioninteger (int32)
  • widthinteger (int32)
  • heightinteger (int32)

StorefrontManufacturerDto

Storefront manufacturer (vendor): id, display name, logo URL.

  • idstring (uuid)
  • namestringnullable
  • logo_urlstringnullable

StorefrontPriceRangeDto

The price range of a filtered catalog: what a price slider's ends should be. Money is in the request's active currency, quoted gross — the same basis as price_min/price_max take. Kept out of the facet list on purpose. A facet value is an id with a count, and a price range is neither, so a client that renders facets generically would have had to special-case it anyway.

  • minnumber (double)

    Cheapest gross price in the matching set.

  • maxnumber (double)

    Dearest gross price in the matching set.

  • currencystringnullable

    ISO code the two figures are in.

StorefrontProductDto

Storefront representation of a catalog product. This is the list projection: it carries the product's gross retail price range (price_min/price_max in currency) and variant count so a listing/collection card can show a price range and an "N options" badge, mirroring a Shopify storefront listing. The full variant list is served by the detail read and /{id}/variants.

  • idstring (uuid)
  • handlestringnullable
  • titlestringnullable
  • body_htmlstringnullable
  • imagestringnullable
  • availableboolean
  • currencystringnullable
  • price_minnumber (double)

    Lowest variant gross price; 0 when the product has no priced variant.

  • price_maxnumber (double)

    Highest variant gross price; 0 when the product has no priced variant.

  • variants_countinteger (int32)

    Number of active, published variants.

  • ratingnumber (double)

    Average approved rating (0 when unrated).

  • rating_countinteger (int32)

    Number of approved ratings.

  • custom_fieldsStorefrontCustomFieldDto[]nullable

    Tenant-defined custom attributes for the representative variant.

  • variantsStorefrontVariantDto[]nullable

    The product's variants (list-level view from the catalog index). Tax rate, alcohol volume and option group are not carried by the index and are left at their defaults here; the single-product detail read returns the fully-resolved variants. For a text search only matching variants appear — see Cloudwawi.Shop.Api.V2026_04_01.Storefront.StorefrontProductDto.VariantsCount for the true total.

StorefrontProductListResponse

Envelope returned by GET /products and GET /collections/{id}/products. One page of products, in the order requested by order. Paging is cursored: when more products match, the response carries a Link header of the form <https://…?…&limit=50&page_info=…>; rel="next". Follow that URL verbatim — the cursor embeds a fingerprint of the filters that produced the page, and a request whose filters no longer match is rejected with 422. There is no total count and no last page link.

  • productsStorefrontProductDto[]nullable

    The page of products. Always present; an empty array when nothing matches.

  • facetsStorefrontFacetDto[]nullable

    Filter facets for this result set — identical to what the matching /facets endpoint returns for the same filters. Present only when the request passed include=facets; the property is omitted entirely otherwise (it is never null on the wire).

StorefrontQuantityRuleDto

Storefront variant quantity rule: minimum, optional maximum, and increment (step).

  • minnumber (double)
  • maxnumber (double)nullable
  • incrementnumber (double)

StorefrontVariantDto

Storefront representation of a product variant, including the product attributes the storefront page renders. Money fields are in the enclosing response's currency — Cloudwawi.Shop.Api.V2026_04_01.Storefront.StorefrontProductDetailDto.Currency on the detail read, the sibling currency field on the /{id}/variants envelope.

  • idstring (uuid)
  • product_idstring (uuid)
  • handlestringnullable
  • titlestringnullable
  • skustringnullable
  • option_groupstringnullable
  • pricenumber (double)

    Display price (gross, tax included).

  • net_pricenumber (double)
  • compare_at_pricenumber (double)

    Pre-discount price when on offer; 0 otherwise.

  • tax_ratenumber (double)
  • availableboolean
  • inventory_quantitynumber (double)
  • descriptionstringnullable
  • description_additionalstringnullable
  • yearstringnullable
  • sizestringnullable
  • areastringnullable
  • countrystringnullable
  • alcohol_volumenumber (double)nullable
  • custom_fieldsStorefrontCustomFieldDto[]nullable

    Tenant-defined custom attributes for this variant.

  • factsheet_urlstringnullable

    Relative URL of the generated variant factsheet PDF.

StorefrontVariantFacetsDto

A variant's facet membership. Each entry pairs the filter token a client sends back with its localized label, so a card can render attribute chips and a client can filter in-memory without a second call.

StorefrontVariantOptionDto

A selected tenant-defined option, qualified by the custom field that owns it.

  • field_keystringnullable

    Stable machine key of the owning custom field (falls back to its numeric code).

  • field_labelstringnullable

    Localized display name of the owning custom field.

  • idstring (uuid)
  • namestringnullable