Product Sub-Resources (Product tag)
Sub-resources of a product — gallery assets, tier prices, customizable options and their pricing/translations, raw EAV values. Most of these are already inlined on the Single Product response; the dedicated endpoints listed here exist when you need just one slice without re-fetching the whole PDP.
URL naming is not uniform
Root URLs in this group use two different separators, so a path cannot be guessed from the resource name:
| Separator | Endpoints |
|---|---|
| Dashed | *-images, *-videos, *-bundle-option-products, *-downloadable-links, *-downloadable-samples |
| Underscored | product_customizable_options, product_customizable_option_prices, product_customizable_option_translations, product_bundle_options, product_grouped_products |
The underscored form is the framework's default snake-case route, kept where no explicit path was declared. Copy the URL from the parent resource's IRI rather than assembling it by hand — the IRIs in a response are authoritative.
Endpoints in this group
Images (type = images)
Images come back in gallery order — the order the storefront draws them in, lowest position first, which is also the product's main image. Each carries altText, the description stored for the current locale, and fileName, the file's base name without directory or extension.
| Method | Path | Purpose |
|---|---|---|
| GET | /api/shop/products/{productId}/images | All images for a product (nested) |
| GET | /api/shop/product-images | Paginated, every image across the catalog (root) |
| GET | /api/shop/product-images/{id} | Single image by global ID |
Videos (type = videos)
| Method | Path | Purpose |
|---|---|---|
| GET | /api/shop/products/{productId}/videos | All videos for a product (nested) |
| GET | /api/shop/product-videos | Paginated root collection |
| GET | /api/shop/product-videos/{id} | Single video by global ID |
Same response shape as Images, with type: "videos".
Customer Group Prices (tier prices)
| Method | Path | Purpose |
|---|---|---|
| GET | /api/shop/products/{productId}/customer-group-prices | Tier prices for a product |
The nested list is the only tier-price endpoint. There is no single-row route and no root collection — reading one row means reading the product's list and picking it out.
Customizable Options + Prices + Translations
| Method | Path | Purpose |
|---|---|---|
| GET | /api/shop/products/{productId}/customizable-options | All custom inputs for a product (nested) |
| GET | /api/shop/product_customizable_options/{id} | Single option by ID |
| GET | /api/shop/product_customizable_option_prices | Paginated pricing rows |
| GET | /api/shop/product_customizable_option_prices/{id} | Single pricing row |
| GET | /api/shop/product_customizable_option_translations | Paginated locale labels |
| GET | /api/shop/product_customizable_option_translations/{id} | Single label |
Attribute Values (raw EAV — sub-resource only)
| Method | Path | Purpose |
|---|---|---|
| GET | /api/shop/products/{productId}/attribute-values | Every attribute value row for a product |
There is no root collection and no single-row endpoint. Read the values through the product itself.
Response field reference
Image / Video
| Field | Type | Description |
|---|---|---|
id | integer | Asset primary key |
type | string | images or videos |
path | string | Storage path (relative) |
productId | integer | Owning product |
position | integer | Display order |
publicPath | string | Fully-qualified URL |
Customer Group Price
| Field | Type | Description |
|---|---|---|
id | integer | Tier-price row ID |
qty | number | Threshold quantity for this tier |
valueType | string | fixed (replaces price) or discount (percentage off) |
value | number | Tier value — interpreted by valueType |
customerGroupId | integer | Customer group this tier applies to |
uniqueId | string | Internal lookup key (<group>|<product>|<qty>) |
productId | integer | Owning product |
Customizable Option
| Field | Type | Description |
|---|---|---|
id | integer | Option primary key |
type | string | field, area, drop_down, radio, checkbox, multiple, date, date_time, time, file |
isRequired | boolean (0/1) | Whether the customer must fill the option |
sortOrder | integer | Display order on the PDP |
product | string (IRI) | Parent product |
prices | array (IRI) | One IRI per pricing row — dereference for the actual prices |
translation | string (IRI) | Translation for the request locale |
translations | array (IRI) | All locale translations |
Customizable Option Price
| Field | Type | Description |
|---|---|---|
id | integer | Pricing row primary key |
price | number | Price increment for this option |
priceType | string | fixed or percent |
customizableOption | string (IRI) | Parent customizable option |
Customizable Option Translation
| Field | Type | Description |
|---|---|---|
id | integer | Translation row primary key |
locale | string | Locale code |
label | string | Localized option label shown to the customer |
customizableOption | string (IRI) | Parent customizable option |
Attribute Value
| Field | Type | Description |
|---|---|---|
id | integer | EAV row primary key |
locale | string | Locale this value applies to |
channel | string | Channel code |
textValue / integerValue / decimalValue / booleanValue / datetimeValue / dateValue / jsonValue | mixed | The typed storage column — only one is populated per row, depending on the attribute's columnName |
value | mixed | Convenience accessor — same as the populated typed column |
uniqueId | string | <channel>|<locale>|<product>|<attribute> — internal index |
attribute | string (IRI) | Parent attribute |
product | string (IRI) | Parent product |
Use Cases
- Refresh the gallery without re-fetching the entire PDP after the customer changes a configurable variant —
GET /api/shop/products/{variantId}/images. - Audit assets across the catalog from an admin tool —
GET /api/shop/product-images?per_page=50and walk the pagination. - Display tier-price tables on a B2B PDP —
GET /api/shop/products/{id}/customer-group-prices. - Render a customizable-option editor — list the option from the PDP, then dereference each
prices[]IRI for the per-option upcharge. - Inspect the raw EAV record during a data-quality audit —
GET /api/shop/products/{id}/attribute-valuesshows exactly what's stored onproduct_attribute_values.
Related Resources
- Single Product — embeds
images,videos,customizableOptions, … inline - Product Type Sub-Resources — the per-type structure behind variants, bundles, and downloadables
- Introduction → IRIs & HATEOAS — how to dereference the path references in these payloads

