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.

Prerequisites

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:

Response

Returns the updated product. The mutation result resolves the product's scalar fields — select { adminCatalogProduct { _id sku type status urlKey price weight warnings } }.

Select _id, not id

On a create/update mutation result the auto-injected id IRI points at an internal route — query _id for the numeric product id. To read the full type-specific detail back (variants, bundle options, links, …) re-query the detail query, which resolves every nested connection.

specialPrice resolves to null until its window opens

If you set specialPriceFrom to a future date, the stored special price is saved but specialPrice reads null until that date — it only resolves while the from/to window is active.

Released under the MIT License.