Update Product with Options (Catalog V3)

Download skillThe skill is a reference md and part of wix-manage skill. You can use the following command to add the full wix-manage skill to your project:
Copy

RECIPE: Business Recipe - Updating a Wix Store Product (Catalog V3)

Use this recipe to update an existing Catalog V3 product: storefront visibility, description, media, options, variants, prices, or stock-related inventory records.

Before Any Product Update

Every Catalog V3 product update is revision-based:

  • If the user gives a product name instead of a product ID, use Search Products and choose the exact product name match.
  • Use Get Product to retrieve the current product, its product.revision, and its existing variants. Search Products and Query Products responses do not include variantsInfo.variants, so a variant or price update assembled from a search result sends an empty variants array and is rejected. Re-read the product before every variant-level update.
  • Include product.id and the current product.revision in every Update Product PATCH body.
  • Update Product is a partial update: only product, product.id, and product.revision are required, and top-level fields you omit (for example name, ribbon, brand) are left unchanged. The full-array overwrite rule applies only to the repeated fields options, modifiers, and variantsInfo.variants.
  • For simple text/HTML description updates, prefer plainDescription. Use description only when sending a Rich Content object.

Find the product by name

Copy

For product-name lookup, prefer Search Products before retrieving the product by ID. Search only resolves the product ID; it does not replace the Get Product call.

Get the current revision

Copy

Common Update Patterns

Hide or Show a Product

"Hide this product", "make it not show in my store", "unhide it", "put it back in the store" are all product-level visibility changes. Set the visible boolean on the product in an Update Product PATCH. Do not delete the product, and do not change variant visibility to hide the product.

Copy

Send "visible": true to show it again. Nothing else needs to be in the body — name, options, variantsInfo and the other top-level fields you omit are left unchanged. Confirm the result from product.visible in the response.

Visibility behaviour to report back accurately:

  • visible defaults to true.
  • For a product without options, updating product.visible automatically updates the default variant's visible to match.
  • For a product with options, product and variant visibility are independent: setting product.visible to false leaves each variantsInfo.variants[].visible as it was.
  • Point-of-sale visibility is a separate field, visibleInPos. Only change it when the user asks about POS. It is always false for productType: DIGITAL.

Update Description Only

For a normal user request like "set the product description to X", use plainDescription with valid HTML. The API converts it to rich content.

Do not send a plain string in description. description is a Rich Content object.

Copy

Use description only when you intentionally need to send Rich Content:

Copy

Update Options and Variants

When adding or changing options and variants, send the full option definitions and one variant for each option-choice combination. Use optionChoiceNames to reference choices.

Copy

When updating existing variants, include each existing variant id. If no GUID is passed, a variant is created with a new GUID. Each variant object is replaced whole rather than merged, so carry over the fields you are not changing: rebuilding a variant from just its id plus the field you want to set drops everything else and is rejected on the first required field it lost (price must not be empty). Start from the variant as returned by Get Product and override only what the user asked to change.

Convert a Simple Product to Color Variants

When adding the first option to a simple product, do not preserve a choice-less default variant unchanged. A simple product often has one existing variant with price or stock but no choices. After you add a Color option, every variant in variantsInfo.variants must include choices that match the product options.

Use the existing default variant as source data only. For example, copy its price if the user did not ask to change price, then send a complete optioned variants list where each variant has:

Copy

After the product update returns the new variant IDs, use those IDs to set inventory.

Set Stock for New Variants

Inventory is handled separately from product updates. After the product update returns variant IDs, use Bulk Create Inventory Items with productId, variantId, and quantity.

If the store has multiple inventory locations, include locationId; otherwise the store's default location is used. After bulk inventory create, check bulkActionMetadata.totalSuccesses and results[].itemMetadata.success. Returned inventory entities are under results[].item, not a top-level inventoryItems field; confirm stock from results[].item.quantity.

Copy

Update Media Only

Copy

Update Variant Price Only

Read {existingVariantId} off the Get Product response; a Search or Query Products result does not carry it.

Copy

Important Notes

  • A request to hide a product is a visible: false update on the product, never a Delete Product call and never a variant-only change.
  • To update array fields like options, modifiers, variantsInfo.variants, and any others, pass the entire existing array. Passing only the changed item overwrites the whole array.
  • To update variantsInfo.variants, also pass options, and vice versa. Variants and options are mutually dependent and must stay aligned.
  • When converting a simple product to an optioned product, rebuild the variants list so every variant has choices; do not keep an existing choice-less default variant unchanged.
  • Always include choicesSettings with the complete list of choices when updating a product with options.
  • Use optionChoiceNames rather than optionChoiceIds in variants for more reliable updates. Reading them back is not symmetric: Get Product returns each variant's choices with optionChoiceIds only, and fills in optionChoiceNames just when the request's fields array includes "VARIANT_OPTION_CHOICE_NAMES". So to find the variant for a named choice such as Large, either pass that field and match on the name, or take the choice GUID from options[].choicesSettings.choices[].choiceId and match it against variants[].choices[].optionChoiceIds.choiceId. Matching on a name the response never carried raises nothing — it just selects no variant.
  • Include the renderType in optionChoiceNames.

Error Message Reference

Error MessageMeaningFix
revision must not be emptyMissing optimistic lockGET product first and include product.revision in PATCH
revision mismatchStale revisionRe-GET product and retry with the new revision
Expected an object for descriptionSent description as a stringUse plainDescription for HTML strings, or send description as Rich Content
choicesSettings must not be emptyMissing choices arrayInclude full choicesSettings.choices array
Missing product option choicesVariant references non-existent optionUse optionChoiceNames with exact option and choice names
price must not be emptyA variant was sent without a price — including an existing variant rebuilt from only its id and the field being changedCarry price.actualPrice.amount on every variant you send, not just new ones; copy it from the Get Product response for variants you are not repricing
variantsInfo is invalid: variants has size 0, expected 1 or moreVariants were read from a Search or Query Products response, which does not return themRe-read the product with Get Product and send its variantsInfo.variants
Missing option choices or INVALID_DEFAULT_VARIANTProduct has options but at least one variant has no matching choicesRebuild variantsInfo.variants so every variant includes choices for all product options
DIGITAL_PRODUCT_CANNOT_BE_VISIBLE_IN_POSSent visibleInPos: true on a digital productDigital products can't be visible in POS; leave visibleInPos out of the body

Last updated: 9 August 2026

Did this help?