Skip to content

Catalog Product — Detail

Returns a single catalog product by ID with all detail-level fields populated, including translations, images, categories, inventories, customer group prices, and type-specific blocks. This is the read endpoint for the admin Catalog → Products edit form.

Endpoint

EndpointMethodAuthentication
/api/admin/catalog/products/{id}GETAdmin Bearer token

{id} must be a positive integer. The route carries a requirements: ['id' => '\d+'] constraint — non-numeric path segments are rejected with 404 before reaching the provider. This prevents the {id} segment from accidentally matching sibling routes under /catalog/products/.

Path Parameter

ParameterTypeRequiredDescription
idintegerYesThe numeric product ID

Response Shape

The response is a single JSON object (not wrapped in a { data } envelope) with the following top-level fields:

Core fields (always present)

FieldTypeDescription
idintegerProduct ID
skustringProduct SKU
namestringLocalised product name
typestringProduct type (simple, configurable, bundle, grouped, downloadable, virtual, booking)
statusinteger1 = enabled, 0 = disabled
pricestringRaw decimal price string (e.g. "99.9900")
formattedPricestringCurrency-formatted price (e.g. "$99.99")
quantityintegerTotal quantity across all inventory sources
baseImageUrlstring|nullURL of the base/primary image
imagesCountintegerTotal number of product images
categoryIdinteger|nullPrimary category ID
categoryNamestring|nullPrimary category display name
channelstringChannel code used for value resolution
localestringLocale code used for value resolution
attributeFamilyIdintegerAttribute family ID
attributeFamilyNamestringAttribute family display name
urlKeystringURL slug (e.g. classic-watch)
visibleIndividuallybooleanWhether the product appears in listings
shortDescriptionstring|nullShort description (may contain HTML)
descriptionstring|nullFull description (may contain HTML)
metaTitlestring|nullSEO meta title
metaDescriptionstring|nullSEO meta description
metaKeywordsstring|nullSEO meta keywords
weightfloat|nullProduct weight
taxCategoryIdinteger|nullTax category ID
manageStockboolean|nullWhether inventory is managed
inStockbooleanWhether the product is currently in stock
featuredbooleanWhether the product is featured
newbooleanWhether the product is marked as new
createdAtstringISO 8601 creation timestamp
updatedAtstringISO 8601 last-updated timestamp

translations[] array

Each element is one per-locale translation row:

FieldTypeDescription
localestringLocale code (e.g. en, fr)
namestring|nullTranslated product name
descriptionstring|nullTranslated full description
shortDescriptionstring|nullTranslated short description
urlKeystring|nullTranslated URL slug
metaTitlestring|nullTranslated SEO meta title
metaDescriptionstring|nullTranslated SEO meta description
metaKeywordsstring|nullTranslated SEO meta keywords

images[] array

Each element is one product image:

FieldTypeDescription
idintegerImage ID
pathstringStorage path relative to the disk root
urlstringFull public URL
sortOrderintegerDisplay order position

categories[] array

Each element is a category the product belongs to:

FieldTypeDescription
idintegerCategory ID
namestringCategory display name
slugstringCategory URL slug

inventories[] array

Each element is one inventory source row:

FieldTypeDescription
sourceIdintegerInventory source ID
sourceCodestringInventory source code (e.g. default)
qtyintegerQuantity at this source

customerGroupPrices[] array

Each element is a customer-group price override. Empty array ([]) when none are configured.

Type-Specific Blocks

These seven fields are always present in the response but are null unless the product's type matches:

FieldPresent for typeDescription
superAttributesconfigurableThe configurable attributes, each with its full options list
variantsconfigurableVariant child products with their chosen attribute values
bundleOptionsbundleBundle option groups with their selectable products
linkedProductsgroupedThe associated products
downloadableLinksdownloadableDownload link rows — title, type, url or file, price, download limit
downloadableSamplesdownloadableSample download rows
bookingProductbookingBooking sub-type, location, availability window, and slots or tickets

Switch on type to know which to read. A simple or virtual product has all seven as null.

channels[] array

Every channel in the store, each flagged with whether this product is assigned to it — mirrors the Channels checkbox box on the edit screen (all options shown, the product's ones ticked). The singular channel field above is the channel code the data was resolved for.

FieldTypeDescription
idintegerChannel ID
codestringChannel code
namestringChannel display name
assignedbooleantrue if this product is assigned to the channel

attributes[] array

The product's attribute-family field set — the same fields the admin edit screen renders, in the same order, driven by the product's attribute family. This includes family-specific fields (e.g. color, size, brand, product_number) that aren't top-level columns. Fields with no value are still present, with value: null.

FieldTypeDescription
idintegerAttribute ID
codestringAttribute code (e.g. sku, color, meta_title)
adminNamestringField label as shown in the admin
typestringInput type (text, textarea, price, boolean, select, multiselect, checkbox, date, datetime, image, file)
isRequiredbooleanWhether the field is required
valuePerChannelbooleanWhether the value can differ per channel
valuePerLocalebooleanWhether the value can differ per locale
groupCodestringCode of the field group it belongs to
groupNamestringDisplay name of the field group
valuemixed|nullThe product's resolved value for the requested channel/locale (null when unset). For select it's the chosen option ID; for multiselect/checkbox a comma-separated list of option IDs
optionsarray|nullFor select/multiselect/checkbox: the selectable options (id, adminName, swatchValue, sortOrder). null for other types

Everything Arrives Inline

Every nested field — translations, images, videos, categories, inventories, customerGroupPrices, channels, attributes, and all the type-specific blocks — is a plain inline JSON array. There are no IRI strings and no sub-resource links, so one call returns the whole product.

attributes plus channels together reconstruct the admin edit form: channels renders the channel checkboxes with the assigned ones ticked, and attributes renders every General / Description / Meta / Settings / Price field for the product's family. The top-level convenience fields (sku, status, urlKey, …) also appear inside attributes — the same values surfaced twice, which is deliberate.

Where This Differs From GraphQL

adminCatalogProduct returns the same product with nested blocks as Relay connections rather than arrays, and the two are not shape-compatible:

  • variants[].attributeValues is a map here{"select_age_group": "5-7 Y"} — but a connection of { code, adminName, value } nodes over GraphQL.
  • channels lists every channel with an assigned flag here, while GraphQL returns only the assigned ones.
  • attributes, bookingProduct, and warnings exist only on this endpoint. They are declared in the GraphQL schema but always resolve null there.
  • Scalar types differ. status, quantity, weight, featured, and new are real JSON numbers and booleans here; over GraphQL they are strings, with "" standing in for false.

Errors

HTTP StatusBody
401{"message": "Unauthenticated.", "error": "unauthenticated"}
404{"type": "/errors/404", "title": "Not Found", "status": 404, "detail": "Product not found."}

A non-numeric {id} also returns 404. The route constrains the segment to digits, so /catalog/products/abc is rejected before the product is looked up — which is what keeps the segment from swallowing sibling routes such as /catalog/products/mass-delete.

Working With This Endpoint

  • Null fields are returned, not omitted. Every one of the 55 keys is present on every response, so a key-existence check tells you nothing — test the value.
  • The response is a bare object, unlike the listing, which wraps rows in { data, meta }.
  • Booking products are fully readable here even though they cannot be added to an admin draft cart. The cart blocks them at add-item time with HTTP 400; reading them is unrestricted.

Released under the MIT License.