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
| Operation | Type |
|---|---|
updateAdminCatalogProduct | Mutation |
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 arg | Notes |
|---|---|
id | The product IRI. Required. |
urlKey, status, visibleIndividually, guestCheckout, new, featured | Common scalar fields. |
price, cost, specialPrice, specialPriceFrom, specialPriceTo, weight, taxCategoryId | Pricing & shipping scalars. |
categories, channels | int[] — replace the assignment when sent, preserved when omitted. |
superAttributes | Configurable super-attribute map (normally set at create). |
variants | Configurable per-variant fields, keyed by variant product id. |
bundleOptions | Bundle option groups. |
links | Grouped associated products. |
downloadableLinks, downloadableSamples | Downloadable structure. |
booking | Booking structure (type ∈ default / appointment / event / rental / table). |
translations | Optional locale-keyed override map. |
extras | Any other attribute code — name, 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 / block | simple | virtual | downloadable | grouped | bundle | configurable | booking |
|---|---|---|---|---|---|---|---|
| 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 structure | — | — | downloadableLinks / downloadableSamples | links | bundleOptions | variants | booking |
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:
| Structure | New-row key prefix |
|---|---|
bundleOptions option group | option_* |
bundleOptions → products | product_* |
links (grouped) | link_* |
downloadableLinks | link_* |
downloadableSamples | sample_* |
customizable_options | option_* (its prices → price_*) |
booking → tickets (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:
- Images → reorder images
- Inventories → update inventories
- Customer-group prices → customer-group prices
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.

