API-Referenz-Navigation
Storefront Products
StorefrontStorefront Products groups 4 operations on the storefront tier.
Storefront tier. Reachable anonymously; a public vnstss_ token may be sent to identify the storefront.
/api/{version}/products
One page of the catalogue. Returns StorefrontProductListResponse; pass include=facets to have the same payload carry the facet sidebar, and follow the Link header's rel="next" URL for the next page.
vnstss_ token may be sent to identify the storefront.Query-Parameter
| Name | Typ | Beschreibung |
|---|---|---|
| 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. |
| ids optional | string | Comma-separated product ids. |
| q optional | string | Free-text search. |
| collection_id optional | string (uuid) | Collection filter. |
| vendor optional | string (uuid) | Manufacturer (vendor) filter. |
| order optional | string | Sort spec, e.g. |
| color_id optional | string | Colour facet ids ( |
| 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 ( |
| 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 |
|
| on_sale optional | boolean |
|
| include optional | string | Comma-separated extras to embed in the response. |
| IncludeFacets optional | boolean | Whether |
Antworten
- 200StorefrontProductListResponseOK
- 422ApiErrorResponseUnprocessable Content
curl -X GET \
'https://<your-shop-domain>/api/2026-04-01/products' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer vnstss_<token>'{
"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"
}
}/api/{version}/products/facets
Filter facets for the whole catalogue. Takes the same filters as the list above, so passing the current selection through returns counts that agree with the products on screen.
vnstss_ token may be sent to identify the storefront.Query-Parameter
| Name | Typ | Beschreibung |
|---|---|---|
| q optional | string | Free-text search. |
| vendor optional | string (uuid) | Manufacturer (vendor) filter — the |
| color_id optional | string | Colour facet ids ( |
| 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 ( |
| 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 |
|
| on_sale optional | boolean |
|
| include optional | string | Comma-separated extras to embed in the response. |
| IncludeFacets optional | boolean | Whether |
Antworten
curl -X GET \
'https://<your-shop-domain>/api/2026-04-01/products/facets' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer vnstss_<token>'{
"facets": [
{
"key": "string",
"values": [
{}
]
}
],
"price_range": {
"min": 1,
"max": 1,
"currency": "string"
}
}/api/{version}/products/{id}
vnstss_ token may be sent to identify the storefront.Pfad-Parameter
| Name | Typ | Beschreibung |
|---|---|---|
| id erforderlich | string (uuid) |
Antworten
- 200StorefrontProductResponseOK
- 404ApiErrorResponseNot Found
curl -X GET \
'https://<your-shop-domain>/api/2026-04-01/products/<id>' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer vnstss_<token>'{
"product": {
"id": "00000000-0000-0000-0000-000000000000",
"handle": "string",
"title": "string",
"body_html": "string",
"summary_html": "string",
"image": {
"id": "00000000-0000-0000-0000-000000000000",
"src": "string",
"preview_src": "string",
"alt": "string",
"position": 1,
"width": 1,
"height": 1
},
"images": [
{
"id": "00000000-0000-0000-0000-000000000000",
"src": "string",
"preview_src": "string",
"alt": "string",
"position": 1,
"width": 1,
"height": 1
}
],
"available": true,
"vendor": "string",
"rating": 1,
"rating_count": 1,
"currency": "string",
"price_min": 1,
"price_max": 1,
"manufacturer": {
"id": "00000000-0000-0000-0000-000000000000",
"name": "string",
"logo_url": "string"
},
"category_path": [
{
"id": "00000000-0000-0000-0000-000000000000",
"name": "string"
}
],
"flag": {
"name": "string",
"color": "string"
},
"custom_fields": [
{
"key": "string",
"label": "string",
"value": "string",
"type": "string"
}
],
"variants": [
{
"id": "00000000-0000-0000-0000-000000000000",
"product_id": "00000000-0000-0000-0000-000000000000",
"handle": "string",
"title": "string",
"sku": "string",
"option_group": "string",
"price": 1,
"net_price": 1,
"compare_at_price": 1,
"tax_rate": 1,
"available": true,
"inventory_quantity": 1,
"description": "string",
"description_additional": "string",
"year": "string",
"size": "string",
"area": "string",
"country": "string",
"alcohol_volume": 1,
"quantity_rule": {},
"custom_fields": [],
"factsheet_url": "string",
"facets": {}
}
]
}
}/api/{version}/products/{id}/variants
vnstss_ token may be sent to identify the storefront.Pfad-Parameter
| Name | Typ | Beschreibung |
|---|---|---|
| id erforderlich | string (uuid) |
Antworten
- 200StorefrontVariantListResponseOK
- 404ApiErrorResponseNot Found
curl -X GET \
'https://<your-shop-domain>/api/2026-04-01/products/<id>/variants' \
-H 'Accept: application/json' \
-H 'Authorization: Bearer vnstss_<token>'{
"currency": "string",
"variants": [
{
"id": "00000000-0000-0000-0000-000000000000",
"product_id": "00000000-0000-0000-0000-000000000000",
"handle": "string",
"title": "string",
"sku": "string",
"option_group": "string",
"price": 1,
"net_price": 1,
"compare_at_price": 1,
"tax_rate": 1,
"available": true,
"inventory_quantity": 1,
"description": "string",
"description_additional": "string",
"year": "string",
"size": "string",
"area": "string",
"country": "string",
"alcohol_volume": 1,
"quantity_rule": {
"min": 1,
"max": 1,
"increment": 1
},
"custom_fields": [
{}
],
"factsheet_url": "string",
"facets": {
"color": {},
"region": {},
"vintage": {},
"size": {},
"options": []
}
}
]
}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.
errorsstringnullableHuman-readable description of what went wrong, e.g.
Not Found,Invalid page_info.codestringnullableMachine-readable error code. Only a few endpoints (checkout) emit one; omitted everywhere else.
StorefrontCategoryRefDto
Storefront category reference used in a product's category breadcrumb.
idstring (uuid)namestringnullable
StorefrontCustomFieldDto
Storefront custom field: a tenant-defined attribute (key, localized label, value, kind).
keystringnullablelabelstringnullablevaluestringnullabletypestringnullable
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.
keystringnullableDimension 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_fieldsis 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'snamefor display and itsidas thecustom_field_idfilter 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.
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.
price_rangeStorefrontPriceRangeDto
StorefrontFacetValueDto
One selectable facet value: filter token id, localized name, matching product count.
idstringnullableFilter 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:
categories→category_id,colors→color_id,sizes→size_id,years→year_id,countries→country_id,regions→region_id,custom_fields→custom_field_id,manufacturers→vendor.namestringnullableDisplay label in the request's language; may be
nullwhen the tenant left it untranslated.valuestringnullableRaw value for custom-field options;
nullfor 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.
namestringnullablecolorstringnullable
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)srcstringnullablepreview_srcstringnullablealtstringnullablepositioninteger (int32)widthinteger (int32)heightinteger (int32)
StorefrontManufacturerDto
Storefront manufacturer (vendor): id, display name, logo URL.
idstring (uuid)namestringnullablelogo_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.
currencystringnullableISO code the two figures are in.
StorefrontProductDetailDto
Storefront representation of a single catalog product detail read, including every published variant.
Served by GET /api/{version}/products/{id}; the lighter list shape is
Cloudwawi.Shop.Api.V2026_04_01.Storefront.StorefrontProductDto.
idstring (uuid)handlestringnullabletitlestringnullablebody_htmlstringnullablesummary_htmlstringnullableimageStorefrontImageDtoavailablebooleanvendorstringnullableratingnumber (double)rating_countinteger (int32)currencystringnullableprice_minnumber (double)price_maxnumber (double)manufacturerStorefrontManufacturerDtoCategory breadcrumb, root first; empty when the product is uncategorized.
Tenant-defined custom attributes for the representative variant.
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)handlestringnullabletitlestringnullablebody_htmlstringnullableimagestringnullableavailablebooleancurrencystringnullableprice_minnumber (double)Lowest variant gross price;
0when the product has no priced variant.price_maxnumber (double)Highest variant gross price;
0when the product has no priced variant.variants_countinteger (int32)Number of active, published variants.
manufacturerStorefrontManufacturerDtoratingnumber (double)Average approved rating (0 when unrated).
rating_countinteger (int32)Number of approved ratings.
Tenant-defined custom attributes for the representative variant.
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.
The page of products. Always present; an empty array when nothing matches.
Filter facets for this result set — identical to what the matching
/facetsendpoint returns for the same filters. Present only when the request passedinclude=facets; the property is omitted entirely otherwise (it is nevernullon the wire).price_rangeStorefrontPriceRangeDto
StorefrontQuantityRuleDto
Storefront variant quantity rule: minimum, optional maximum, and increment (step).
minnumber (double)maxnumber (double)nullableincrementnumber (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)handlestringnullabletitlestringnullableskustringnullableoption_groupstringnullablepricenumber (double)Display price (gross, tax included).
net_pricenumber (double)compare_at_pricenumber (double)Pre-discount price when on offer;
0otherwise.tax_ratenumber (double)availablebooleaninventory_quantitynumber (double)descriptionstringnullabledescription_additionalstringnullableyearstringnullablesizestringnullableareastringnullablecountrystringnullablealcohol_volumenumber (double)nullablequantity_ruleStorefrontQuantityRuleDtoTenant-defined custom attributes for this variant.
factsheet_urlstringnullableRelative 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.
regionStorefrontFacetRefDtovintageStorefrontFacetRefDtoTenant-defined dropdown options (grape variety, for tenants that model it). Each carries the owning field's
field_keyso a client can select the field it cares about.
StorefrontVariantListResponse
Envelope returned by GET /products/{id}/variants.
currencystringnullableISO currency code the variants' money fields are expressed in — the request's active currency.
Every active, published variant of the product.
StorefrontVariantOptionDto
A selected tenant-defined option, qualified by the custom field that owns it.
field_keystringnullableStable machine key of the owning custom field (falls back to its numeric code).
field_labelstringnullableLocalized display name of the owning custom field.
idstring (uuid)namestringnullable
