Skip to content

Catalog Product — Update

Equivalent to PUT /api/admin/catalog/products/{id}.

This is a partial patch — send only the fields you want to change inside input. Omitted fields keep their current value. Pass the product IRI as id (e.g. "/api/admin/catalog/products/42").

Every field the admin Edit Product screen exposes is editable here. Pick a product type in the Examples dropdown (top-right) to see the complete edit-form body for that type.

The examples use illustrative IRIs and ids. Replace them with ids that exist in your store — use the adminCatalogProducts query to find products, and the detail query variants connection to discover a configurable product's variant ids.

Operation

OperationType
updateAdminCatalogProductMutation

Input shape — named args vs extras

The input has named camelCase args for the common/structural fields, plus an extras object for every other attribute code:

Named argNotes
idThe product IRI. Required.
urlKey, status, visibleIndividually, guestCheckout, new, featuredCommon scalar fields.
price, cost, specialPrice, specialPriceFrom, specialPriceTo, weight, taxCategoryIdPricing & shipping scalars.
categories, channelsint[] — replace the assignment when sent, preserved when omitted.
superAttributesConfigurable super-attribute map (normally set at create).
variantsConfigurable per-variant fields, keyed by variant product id.
bundleOptionsBundle option groups.
linksGrouped associated products.
downloadableLinks, downloadableSamplesDownloadable structure.
bookingBooking structure (typedefault / appointment / event / rental / table).
translationsOptional locale-keyed override map.
extrasAny other attribute codename, color, size, brand, product_number, GST, short_description, description, meta_title, meta_keywords, meta_description, length, width, height, manage_stock, up_sells, cross_sells, related_products, customizable_options — as a JSON object keyed by attribute code.

Anything not in the named-args list goes in extras (it is merged into the payload as a top-level attribute by code). Structure args replace that structure when sent — send the full set.

Field applicability by type

Field / blocksimplevirtualdownloadablegroupedbundleconfigurablebooking
Common attrs (name, sku, url_key, meta, color/size/brand, dimensions, settings)✅ (colour/size on variants)
price / cost / specialPrice— (sells linked products)price:"0" (dynamic)— (per variant)
categories, channels, up_sells, cross_sells, related_products
customizable_options (custom options)
Type structuredownloadableLinks / downloadableSampleslinksbundleOptionsvariantsbooking

Custom options are a Bagisto simple/virtual-only feature — sending customizable_options on any other type is ignored by the store.

Keying rules for nested structures

New nested rows are keyed by a prefixed marker; a numeric/bare key is treated as an existing row id:

StructureNew-row key prefix
bundleOptions option groupoption_*
bundleOptionsproductsproduct_*
links (grouped)link_*
downloadableLinkslink_*
downloadableSamplessample_*
customizable_optionsoption_* (its pricesprice_*)
bookingtickets (event)ticket_*
variants (configurable)the existing variant product id (numeric)

Locale & channel

GraphQL has no query string, so translatable fields are written to the store's default locale and channel. To target a specific locale (e.g. write the French translation while leaving English untouched), use the REST endpoint with its ?locale=fr&channel=default query parameter — see the REST Update page.

Sub-resources are not updated here

images, videos, inventories, and customerGroupPrices are not handled by this mutation — they have dedicated operations. If sent, they are ignored and noted in the response warnings array:

Reading the Payload

Select whatever you need — the payload is the product itself:

graphql
adminCatalogProduct {
  _id
  sku
  type
  status
  urlKey
  price
  weight
  warnings
}

Connections resolve on the payload too, so you can read nested data back in the same round trip — images { edges { node { _id url } } } returns this product's images.

One value is easy to misread: specialPrice reads null until its window opens. Setting specialPriceFrom to a future date stores the price but leaves the field null until that date arrives. The value is saved; it is simply not the active price yet.

Errors

MessageCause
Product not found.Unknown id
The sku has already been taken.Duplicate SKU
You do not have permission to manage products.Token lacks catalog.products.edit

Other validation failures — a duplicate URL key, a non-boolean value in a boolean field, a special price at or above the price, or an inverted date range — surface the same way, in errors[] with null data.

Released under the MIT License.