Skip to content

Single Product

Returns the full PDP-ready document for a product — categories, channels, attribute family, images, videos, super-attributes (configurable parents), variants, bundle options, booking config, grouped members, downloadable links / samples, customizable options, related/up-sell/cross-sell products — all embedded inline. No follow-up requests are needed to render a complete product detail page.

Endpoint

GET /api/shop/products/{id}

Request Headers

HeaderRequiredDescription
AcceptYesapplication/json
X-STOREFRONT-KEYYesStorefront API key (pk_storefront_…)
X-LocaleNoOverride request locale
X-ChannelNoOverride channel scope
X-CurrencyNoOverride currency in formattedPrice etc.

Path Parameters

ParameterTypeRequiredDescription
idintegerYesProduct primary key

Response

200 OK — single product object. The card-level fields (id, sku, type, name, price, …) are present, plus the embedded relations below.

Card-level fields

Same shape as items in Products — see that page for the field table. This includes the per-customer isInWishlist and isInCompare booleans.

Wishlist & compare flags: isInWishlist (active channel) and isInCompare tell you whether the signed-in customer already has this product in their wishlist / compare list (1 = yes, 0 = no), so you can highlight the wishlist / compare icon on the product page without a separate lookup. Include the customer Bearer token alongside the storefront key — for guests both are 0. REST returns 1 / 0 integers (over GraphQL the same flags come back as the strings "1" / "0").

Always-present extras (over the list)

FieldTypeDescription
descriptionstringFull HTML description
createdAtstring (ISO)Creation timestamp
updatedAtstring (ISO)Last update timestamp
isSaleablebooleanWhether the product passes saleability checks (stock, status, …)
attributeFamilyobject{ id, code, name }

Filterable attribute summary

The default-family product output includes top-level shortcuts for the common filterable attributes:

FieldTypeDescription
colorobject | null{ id, code, label } for the assigned color option
sizeobject | nullSame shape, for size
brandobject | nullSame shape, for brand

The exact set depends on the active attribute family — these three are present for the default family.

Embedded relations (always present, may be empty [])

FieldTypeNotes
categoriesarrayCategories the product belongs to
channelsarrayChannels exposing this product ({ id, code, hostname, currencyCode, localeCode })
imagesarrayImage objects ({ id, type, path, productId, position, publicPath })
videosarrayVideo objects
superAttributesarrayConfigurable type only — list of attributes used to build variants, with their options inlined
variantsarrayConfigurable type only — child variant products, each carrying card-level fields
bookingProductsarrayBooking type only — slot config with type (default/appointment/rental/event/table) and a type-specific slots block
bundleOptionsarrayBundle type only — option groups with their member products inlined
groupedProductsarrayGrouped type only — associated products
downloadableLinksarrayDownloadable type only — purchasable links
downloadableSamplesarrayDownloadable type only — preview samples
customizableOptionsarrayPer-product custom inputs (text fields, file uploads, dropdowns added by the merchant)
relatedProductsarray"Customers also bought" cards
upSellsarray"Upgrade to" cards
crossSellsarray"Pairs well with" cards (shown in the cart/checkout)

Empty [] for product types that don't apply — a simple product has no variants, a booking product has no bundleOptions, etc. Clients should treat these as "render only if non-empty".

What this endpoint deliberately omits

  • attributeValues — the raw EAV table is not returned. Use the typed fields (name, description, price, color, …) instead.
  • Reviews — fetched separately via the Product Reviews endpoint, paginated.

Sub-resource endpoints

Each embedded relation is also available as its own URL — useful when you only need one slice without re-fetching the entire PDP. These are tagged Product or Product Types in Swagger UI:

URLReturns
GET /api/shop/products/{productId}/variantsVariants for a configurable product
GET /api/shop/products/{productId}/booking-productsBooking config row(s) for a booking product
GET /api/shop/booking-products/{id}Single booking config (with type-specific slots)
GET /api/shop/booking-slots?id={bp}&date=YYYY-MM-DDRuntime slot availability — see Booking Slots

Use Cases

  • Render a full product detail page in one network round trip.
  • Configurable variant picker: read superAttributes[] for the dimensions, variants[] for the inventory of combinations.
  • Bundle builder: walk bundleOptions[] for the selectable groups; each group has its member products inlined.
  • Determine product type at render time via type (simple, configurable, bundle, …) and bookingType (default, appointment, rental, event, table for booking products).

Released under the MIT License.