RECIPE: Business Recipe - Updating a Wix Store Product (Catalog V3)
Use this recipe to update an existing Catalog V3 product: description, media, options, variants, prices, or stock-related inventory records.
Every Catalog V3 product update is revision-based:
product.revision.product.id and the current product.revision in every Update Product PATCH body.plainDescription. Use description only when sending a Rich Content object.For product-name lookup, prefer Search Products before retrieving the product by ID.
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.
Use description only when you intentionally need to send Rich Content:
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.
When updating existing variants, include each existing variant id. If no GUID is passed, a variant is created with a new GUID.
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:
After the product update returns the new variant IDs, use those IDs to set inventory.
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.
options, modifiers, variantsInfo.variants, and any others, pass the entire existing array. Passing only the changed item overwrites the whole array.variantsInfo.variants, also pass options, and vice versa. Variants and options are mutually dependent and must stay aligned.choices; do not keep an existing choice-less default variant unchanged.choicesSettings with the complete list of choices when updating a product with options.optionChoiceNames rather than optionChoiceIds in variants for more reliable updates.renderType in optionChoiceNames.| Error Message | Meaning | Fix |
|---|---|---|
revision must not be empty | Missing optimistic lock | GET product first and include product.revision in PATCH |
revision mismatch | Stale revision | Re-GET product and retry with the new revision |
Expected an object for description | Sent description as a string | Use plainDescription for HTML strings, or send description as Rich Content |
choicesSettings must not be empty | Missing choices array | Include full choicesSettings.choices array |
Missing product option choices | Variant references non-existent option | Use optionChoiceNames with exact option and choice names |
price must not be empty | A variant was created or replaced without a price | Include price.actualPrice.amount on every new variant |
Missing option choices or INVALID_DEFAULT_VARIANT | Product has options but at least one variant has no matching choices | Rebuild variantsInfo.variants so every variant includes choices for all product options |