Skip to content

Catalog Product — Detail (GraphQL)

GraphQL item query that returns a single catalog product by its IRI, with all detail-level fields populated, including translations, images, categories, inventories, customer group prices, and type-specific blocks.

Operation

OperationType
adminCatalogProductQuery (item)

Authentication

Every request must include an admin Bearer token:

Authorization: Bearer <token>

Obtain a token via the createAdminLogin mutation.

Arguments

ArgumentTypeRequiredDescription
idID!YesAPI Platform IRI of the product (e.g. "/api/admin/catalog/products/42")

Finding the IRI

The IRI can be taken from the id field in any adminCatalogProducts edge node, or constructed as /api/admin/catalog/products/{numericId}. Both forms are accepted by the resolver.

Fields

Core scalar fields

FieldTypeDescription
idIDAPI Platform IRI (e.g. /api/admin/catalog/products/42)
_idIntRaw numeric product ID
skuStringProduct SKU
nameStringLocalised product name
typeStringProduct type (simple, configurable, bundle, grouped, downloadable, virtual, booking)
statusInt1 = enabled, 0 = disabled
priceStringRaw decimal price string (e.g. "99.9900")
formattedPriceStringCurrency-formatted price (e.g. "$99.99")
quantityIntTotal quantity across all inventory sources
baseImageUrlStringURL of the base/primary image
imagesCountIntTotal number of product images
categoryIdIntPrimary category ID
categoryNameStringPrimary category display name
channelStringChannel code used for value resolution
localeStringLocale code used for value resolution
attributeFamilyIdIntAttribute family ID
attributeFamilyNameStringAttribute family display name
urlKeyStringURL slug (e.g. classic-watch)
visibleIndividuallyBooleanWhether the product appears in storefront listings
shortDescriptionStringShort description (may contain HTML)
descriptionStringFull description (may contain HTML)
metaTitleStringSEO meta title
metaDescriptionStringSEO meta description
metaKeywordsStringSEO meta keywords
weightFloatProduct weight
taxCategoryIdIntTax category ID
manageStockBooleanWhether 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

Array/scalar fields (plain JSON)

FieldTypeDescription
translationsscalar (JSON array|null)Per-locale translation rows — see shape below
imagesscalar (JSON array|null)Product image rows — see shape below
categoriesscalar (JSON array|null)Category references — see shape below
inventoriesscalar (JSON array|null)Per-source inventory rows — see shape below
customerGroupPricesscalar (JSON array|null)Customer-group price overrides (empty array when none)
channelsscalar (JSON array)Every channel, each flagged assigned for this product — see shape below
attributesscalar (JSON array)The product's attribute-family field set (edit-screen parity) — see shape below

Type-specific blocks (null unless type matches)

FieldPresent for typeDescription
superAttributesconfigurableConfigurable attributes and their options
variantsconfigurableVariant child products with attribute values
bundleOptionsbundleBundle option groups with selectable products
linkedProductsgroupedLinked associated products
downloadableLinksdownloadableDownload link rows
downloadableSamplesdownloadableSample download rows

translations[] element shape

KeyTypeDescription
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[] element shape

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

categories[] element shape

KeyTypeDescription
idintegerCategory ID
namestringCategory display name
slugstringCategory URL slug

inventories[] element shape

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

channels[] element shape

Every channel in the store, with assigned indicating whether this product belongs to it — mirrors the edit-screen Channels box (all options shown, the product's ticked).

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

attributes[] element shape

The product's attribute-family field set — the same fields the admin edit screen renders (including family-specific ones like color, size, brand, product_number). Empty fields are present with value: null.

KeyTypeDescription
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
groupNamestringDisplay name of the field group
valuemixed|nullResolved value for the requested channel/locale (null when unset); for select the chosen option ID, for multiselect/checkbox a comma-separated option-ID list
optionsarray|nullSelectable options (id, adminName, swatchValue, sortOrder) for select/multiselect/checkbox; null otherwise

Nested data is returned whole

translations, images, categories, inventories, customerGroupPrices, channels, attributes, and the type-specific blocks (variants / bundleOptions / linkedProducts / downloadableLinks / downloadableSamples / superAttributes) are returned as whole JSON — query each as a bare field (attributes, not attributes { … }). The entire array comes back, and it resolves over GraphQL on the detail query.

Example Query

graphql
query AdminCatalogProduct($id: ID!) {
  adminCatalogProduct(id: $id) {
    id
    _id
    sku
    name
    type
    status
    price
    formattedPrice
    quantity
    baseImageUrl
    imagesCount
    categoryId
    categoryName
    channel
    locale
    attributeFamilyId
    attributeFamilyName
    urlKey
    visibleIndividually
    shortDescription
    description
    metaTitle
    metaDescription
    metaKeywords
    weight
    taxCategoryId
    manageStock
    inStock
    featured
    new
    createdAt
    updatedAt
    translations
    images
    categories
    inventories
    customerGroupPrices
    superAttributes
    variants
    bundleOptions
    linkedProducts
    downloadableLinks
    downloadableSamples
    channels
    attributes
  }
}
json
{
  "id": "/api/admin/catalog/products/42"
}

Example Response (simple product)

json
{
  "data": {
    "adminCatalogProduct": {
      "id": "/api/admin/catalog/products/42",
      "_id": 42,
      "sku": "SP-001",
      "name": "Classic Watch",
      "type": "simple",
      "status": 1,
      "price": "99.9900",
      "formattedPrice": "$99.99",
      "quantity": 42,
      "baseImageUrl": "http://localhost:8000/storage/product/42/image.webp",
      "imagesCount": 3,
      "categoryId": 5,
      "categoryName": "Accessories",
      "channel": "default",
      "locale": "en",
      "attributeFamilyId": 1,
      "attributeFamilyName": "Default",
      "urlKey": "classic-watch",
      "visibleIndividually": true,
      "shortDescription": "A premium timepiece.",
      "description": "Full HTML description.",
      "metaTitle": null,
      "metaDescription": null,
      "metaKeywords": null,
      "weight": 0.5,
      "taxCategoryId": null,
      "manageStock": true,
      "inStock": true,
      "featured": false,
      "new": true,
      "createdAt": "2026-01-12T08:15:00+00:00",
      "updatedAt": "2026-04-30T14:20:09+00:00",
      "translations": [
        {
          "locale": "en",
          "name": "Classic Watch",
          "description": "Full HTML description.",
          "shortDescription": "A premium timepiece.",
          "urlKey": "classic-watch",
          "metaTitle": null,
          "metaDescription": null,
          "metaKeywords": null
        }
      ],
      "images": [
        {
          "id": 1,
          "path": "product/42/img1.webp",
          "url": "http://localhost/storage/product/42/img1.webp",
          "sortOrder": 0
        }
      ],
      "categories": [
        {
          "id": 5,
          "name": "Accessories",
          "slug": "accessories"
        }
      ],
      "inventories": [
        {
          "sourceId": 1,
          "sourceCode": "default",
          "qty": 42
        }
      ],
      "customerGroupPrices": [],
      "superAttributes": null,
      "variants": null,
      "bundleOptions": null,
      "linkedProducts": null,
      "downloadableLinks": null,
      "downloadableSamples": null,
      "channels": [
        { "id": 1, "code": "default", "name": "Default Channel", "assigned": true },
        { "id": 2, "code": "mobile", "name": "Mobile Channel", "assigned": false }
      ],
      "attributes": [
        {
          "id": 1,
          "code": "sku",
          "adminName": "SKU",
          "type": "text",
          "isRequired": true,
          "valuePerChannel": false,
          "valuePerLocale": false,
          "groupCode": "general",
          "groupName": "General",
          "value": "SP-001",
          "options": null
        },
        {
          "id": 23,
          "code": "color",
          "adminName": "Color",
          "type": "select",
          "isRequired": false,
          "valuePerChannel": false,
          "valuePerLocale": false,
          "groupCode": "general",
          "groupName": "General",
          "value": null,
          "options": [
            { "id": 1, "adminName": "Red", "swatchValue": "#ff0000", "sortOrder": 1 }
          ]
        },
        {
          "id": 25,
          "code": "meta_title",
          "adminName": "Meta Title",
          "type": "textarea",
          "isRequired": false,
          "valuePerChannel": true,
          "valuePerLocale": true,
          "groupCode": "meta_description",
          "groupName": "Meta Description",
          "value": null,
          "options": null
        }
      ]
    }
  }
}

Errors

ScenarioGraphQL errors[]HTTP Status
Unknown IDerrors[] populated or data.adminCatalogProduct: null200 (GraphQL convention)
Missing auth"Unauthenticated" in errors[]200

Notes

  • Type-aware payload. The six type-specific blocks are always requested in the selection set but are null for non-matching product types. Switch on the type field to know which block to read.
  • id argument is the IRI, not the integer. Construct it as "/api/admin/catalog/products/{_id}" using the _id field from a listing query, or pass the id field directly from a listing result.
  • Same data as the REST detail endpoint. This query and GET /api/admin/catalog/products/{id} return identical data; the REST response uses camelCase JSON, this query returns the same fields with the nested arrays as whole JSON values.
  • Nested arrays are bare JSON, not sub-selections. Query attributes, channels, translations, etc. as plain fields — they return the whole array. Plain scalar fields (id, sku, name, type, price, …) are always returned.
  • Booking products are accessible. Even though booking products cannot be added to an admin draft cart, their detail record is fully readable via this query.
  • Route disambiguation. The REST endpoint carries a requirements: ['id' => '\d+'] constraint — the resolver uses the IRI path for lookup, so only numeric IDs (e.g. /api/admin/catalog/products/42) are accepted.

Released under the MIT License.