@wix/agent-skills 1.31.1 → 1.31.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/wix-app/references/STORES_VERSIONING.md +1 -1
- package/skills/wix-headless-kit/SKILL.md +16 -7
- package/skills/wix-headless-kit/guides/api-run.md +81 -51
- package/skills/wix-headless-kit/guides/existing-site.md +6 -0
- package/skills/wix-headless-kit/install/AGENTS.md +3 -2
- package/skills/wix-headless-kit/install/attach.mjs +32 -27
- package/skills/wix-headless-kit/install/background.mjs +32 -0
- package/skills/wix-headless-kit/install/bootstrap.mjs +28 -11
- package/skills/wix-headless-kit/install/check.mjs +2 -2
- package/skills/wix-headless-kit/install/context.mjs +49 -5
- package/skills/wix-headless-kit/install/deploy.mjs +33 -8
- package/skills/wix-headless-kit/install/env-ignore.mjs +16 -0
- package/skills/wix-headless-kit/install/install.mjs +95 -0
- package/skills/wix-headless-kit/install/pins.json +1 -1
- package/skills/wix-headless-kit/install/proc.mjs +46 -0
- package/skills/wix-headless-kit/install/setup.mjs +16 -25
- package/skills/wix-headless-kit/install/templates.mjs +2 -2
- package/skills/wix-headless-templates/blog/app/components/blog/RichContent.tsx +3 -2
- package/skills/wix-headless-templates/blog/project/package-lock.json +1287 -1299
- package/skills/wix-headless-templates/blog/project/package.json +1 -1
- package/skills/wix-headless-templates/blog/project/src/components/blog/RichContent.tsx +3 -2
- package/skills/wix-headless-templates/blog/rest/authors.ts +5 -5
- package/skills/wix-headless-templates/blog/rest/comments.ts +4 -4
- package/skills/wix-headless-templates/blog/rest/post-likes.ts +3 -3
- package/skills/wix-headless-templates/blog/rest/posts.ts +4 -4
- package/skills/wix-headless-templates/blog/rest/taxonomy.ts +5 -5
- package/skills/wix-headless-templates/blog/seed/seed-blog.mjs +2 -1
- package/skills/wix-headless-templates/bookings/rest/booking.ts +4 -4
- package/skills/wix-headless-templates/bookings/rest/services.ts +4 -4
- package/skills/wix-headless-templates/bookings/seed/seed-bookings.mjs +2 -1
- package/skills/wix-headless-templates/cms/rest/collections.ts +3 -3
- package/skills/wix-headless-templates/cms/rest/items.ts +4 -4
- package/skills/wix-headless-templates/cms/seed/seed-cms.mjs +2 -1
- package/skills/wix-headless-templates/donations/rest/campaigns.ts +4 -4
- package/skills/wix-headless-templates/donations/rest/donate.ts +3 -3
- package/skills/wix-headless-templates/donations/seed/seed-donations.mjs +2 -1
- package/skills/wix-headless-templates/events/rest/events.ts +4 -4
- package/skills/wix-headless-templates/events/rest/orders.ts +4 -4
- package/skills/wix-headless-templates/events/rest/registration.ts +4 -4
- package/skills/wix-headless-templates/events/seed/seed-events.mjs +2 -1
- package/skills/wix-headless-templates/faq/rest/faq.ts +4 -4
- package/skills/wix-headless-templates/faq/seed/seed-faq.mjs +2 -1
- package/skills/wix-headless-templates/forms/rest/forms.ts +4 -4
- package/skills/wix-headless-templates/forms/rest/submissions.ts +4 -4
- package/skills/wix-headless-templates/forms/seed/seed-forms.mjs +2 -1
- package/skills/wix-headless-templates/members/rest/auth.ts +3 -3
- package/skills/wix-headless-templates/members/rest/members.ts +4 -4
- package/skills/wix-headless-templates/members/seed/seed-members.mjs +2 -1
- package/skills/wix-headless-templates/portfolio/rest/portfolio.ts +4 -4
- package/skills/wix-headless-templates/portfolio/seed/seed-portfolio.mjs +2 -1
- package/skills/wix-headless-templates/pricing-plans/rest/plan-access.ts +3 -3
- package/skills/wix-headless-templates/pricing-plans/rest/plans.ts +4 -4
- package/skills/wix-headless-templates/pricing-plans/rest/purchase.ts +3 -3
- package/skills/wix-headless-templates/pricing-plans/seed/seed-pricing-plans.mjs +2 -1
- package/skills/wix-headless-templates/rentals/rest/rentals.ts +4 -4
- package/skills/wix-headless-templates/rentals/seed/seed-rentals.mjs +2 -1
- package/skills/wix-headless-templates/restaurants/rest/menu.ts +4 -4
- package/skills/wix-headless-templates/restaurants/rest/ordering.ts +5 -5
- package/skills/wix-headless-templates/restaurants/rest/reservations.ts +4 -4
- package/skills/wix-headless-templates/restaurants/seed/seed-restaurants.mjs +2 -1
- package/skills/wix-headless-templates/shared/capabilities/site-search/rest/search.ts +4 -4
- package/skills/wix-headless-templates/shared/capabilities/site-search/seed/install.mjs +6 -4
- package/skills/wix-headless-templates/shared/seed/main.mjs +15 -0
- package/skills/wix-headless-templates/shared/seed/wix-cli.mjs +43 -11
- package/skills/wix-headless-templates/storefront/INSTRUCTIONS.md +1 -1
- package/skills/wix-headless-templates/storefront/rest/cart.ts +5 -5
- package/skills/wix-headless-templates/storefront/rest/catalog.ts +5 -5
- package/skills/wix-headless-templates/storefront/seed/SEED.md +27 -9
- package/skills/wix-headless-templates/storefront/seed/seed-store.mjs +2 -1
- package/skills/wix-manage/SKILL.md +3 -3
- package/skills/wix-manage/references/app-installation/install-wix-apps.md +5 -1
- package/skills/wix-manage/references/app-installation/list-installed-apps.md +19 -9
- package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +3 -0
- package/skills/wix-manage/references/bookings/external-calendar-integration.md +3 -0
- package/skills/wix-manage/references/bookings/multi-resource-service-creation.md +3 -0
- package/skills/wix-manage/references/cms/cms-data-items-crud.md +11 -2
- package/skills/wix-manage/references/cms/cms-publishing-flow.md +63 -16
- package/skills/wix-manage/references/forms/update-form.md +3 -0
- package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +3 -0
- package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +3 -0
- package/skills/wix-manage/references/sites/create-headless-site.md +7 -50
- package/skills/wix-manage/references/sites/manage-oauth-apps.md +4 -4
- package/skills/wix-manage/references/sites/read-site-context.md +4 -0
- package/skills/wix-manage/references/sites/upload-static-site.md +67 -31
- package/skills/wix-manage/references/stores/add-store-pages-to-site.md +3 -0
- package/skills/wix-manage/references/stores/change-store-currency.md +3 -0
- package/skills/wix-manage/references/stores/create-product-catalog-v3.md +3 -0
- package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +3 -0
- package/skills/wix-manage/references/stores/update-product-with-options.md +192 -22
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: "Update Product with Options (Catalog V3)"
|
|
3
|
-
description:
|
|
3
|
+
description: "Start here for existing Catalog V3 product updates, including digital products that fail at add-to-cart with ITEM_NOT_FOUND_IN_CATALOG. Includes name lookup, Get Product, and PATCH in one flow, plus importing a supplied PDF and attaching it to the existing variant. Covers options, variant prices and SKUs, product visibility (hide/unhide through `visible`, never delete), description edits that preserve Rich Content, and revision-based updates. Read another recipe only for a field or operation this flow does not cover."
|
|
4
4
|
---
|
|
5
5
|
**RECIPE**: Business Recipe - Updating a Wix Store Product (Catalog V3)
|
|
6
6
|
|
|
@@ -14,7 +14,8 @@ Every Catalog V3 product update is revision-based:
|
|
|
14
14
|
- Use [Get Product](https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/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.
|
|
15
15
|
- Include `product.id` and the current `product.revision` in every [Update Product](https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/update-product) PATCH body.
|
|
16
16
|
- 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`.
|
|
17
|
-
-
|
|
17
|
+
- Get Product returns a default set of fields. When an update keeps or carries over existing projected data, request that data in `fields` before building the PATCH. For any edit that keeps part of the existing product description, request `DESCRIPTION`; a read without it has no Rich Content document to preserve.
|
|
18
|
+
- For description changes, see [Update Description](#update-description): replacing the whole description uses `plainDescription`; editing any existing content uses the Rich Content `description` field.
|
|
18
19
|
|
|
19
20
|
### Find the product by name
|
|
20
21
|
|
|
@@ -24,12 +25,16 @@ curl -X POST "https://www.wixapis.com/stores/v3/products/search" \
|
|
|
24
25
|
-H "Authorization: <AUTH>" \
|
|
25
26
|
-d '{
|
|
26
27
|
"search": {
|
|
27
|
-
"
|
|
28
|
+
"search": {
|
|
29
|
+
"expression": "Product name",
|
|
30
|
+
"fields": ["name"],
|
|
31
|
+
"fuzzy": false
|
|
32
|
+
}
|
|
28
33
|
}
|
|
29
34
|
}'
|
|
30
35
|
```
|
|
31
36
|
|
|
32
|
-
|
|
37
|
+
Read `products` from the search response. Prefer an exact name match; otherwise select a clear, unambiguous match, such as a name differing only in capitalization. If no result clearly identifies the requested product, or multiple products could match, ask the user which product they mean. Use the selected `products[].id` in Get Product; search only resolves the ID.
|
|
33
38
|
|
|
34
39
|
### Get the current revision
|
|
35
40
|
|
|
@@ -38,6 +43,15 @@ curl -X GET "https://www.wixapis.com/stores/v3/products/{productId}" \
|
|
|
38
43
|
-H "Authorization: <AUTH>"
|
|
39
44
|
```
|
|
40
45
|
|
|
46
|
+
To edit an existing description, request its Rich Content document in the same read:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
curl -X GET "https://www.wixapis.com/stores/v3/products/{productId}?fields=DESCRIPTION" \
|
|
50
|
+
-H "Authorization: <AUTH>"
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`product.description` is returned only when `DESCRIPTION` is requested. Request every other projected field that you need to carry over with its documented `fields` value as well.
|
|
54
|
+
|
|
41
55
|
## Common Update Patterns
|
|
42
56
|
|
|
43
57
|
### Hide or Show a Product
|
|
@@ -66,9 +80,16 @@ Visibility behaviour to report back accurately:
|
|
|
66
80
|
- For a product **with** options, product and variant visibility are independent: setting `product.visible` to `false` leaves each `variantsInfo.variants[].visible` as it was.
|
|
67
81
|
- 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`.
|
|
68
82
|
|
|
69
|
-
### Update Description
|
|
83
|
+
### Update Description
|
|
84
|
+
|
|
85
|
+
Choose the flow from the user's request:
|
|
86
|
+
|
|
87
|
+
- "Set the description to X", "replace the description", or "write a new description": **Replace the Description**.
|
|
88
|
+
- "Add", "append", "prepend", "insert", "fix a typo", or "remove" existing text: **Edit the Existing Description**. Any request that keeps part of the current description is an edit.
|
|
89
|
+
|
|
90
|
+
#### Replace the Description
|
|
70
91
|
|
|
71
|
-
For a
|
|
92
|
+
For a request like "set the product description to X", use `plainDescription` with valid HTML. The API converts it to rich content.
|
|
72
93
|
|
|
73
94
|
Do not send a plain string in `description`. `description` is a Rich Content object.
|
|
74
95
|
|
|
@@ -85,7 +106,7 @@ curl -X PATCH "https://www.wixapis.com/stores/v3/products/{productId}" \
|
|
|
85
106
|
}'
|
|
86
107
|
```
|
|
87
108
|
|
|
88
|
-
|
|
109
|
+
For a full replacement with node types beyond the paragraph below, read [Author Ricos Rich Content](../rich-content/author-ricos-rich-content.md). Existing-document edits use the read-modify-write flow below:
|
|
89
110
|
|
|
90
111
|
```bash
|
|
91
112
|
curl -X PATCH "https://www.wixapis.com/stores/v3/products/{productId}" \
|
|
@@ -123,6 +144,77 @@ curl -X PATCH "https://www.wixapis.com/stores/v3/products/{productId}" \
|
|
|
123
144
|
}'
|
|
124
145
|
```
|
|
125
146
|
|
|
147
|
+
Both fields replace the whole description. To keep any existing content, use **Edit the Existing Description**.
|
|
148
|
+
|
|
149
|
+
#### Edit the Existing Description
|
|
150
|
+
|
|
151
|
+
For prepend, append, and text removal, execute the documented calls directly: the examples in this recipe and the request/response contract below provide the fields this flow needs. Reuse this contract rather than rediscovering the Search, Get, and Update schemas. Consult further API documentation when the request requires a field or node type not covered here, or when a documented call fails. Read [Author Ricos Rich Content](../rich-content/author-ricos-rich-content.md) when creating other node types.
|
|
152
|
+
|
|
153
|
+
| Call | Request | Response fields used next |
|
|
154
|
+
|---|---|---|
|
|
155
|
+
| Search Products, when given a name | Use [Find the product by name](#find-the-product-by-name); `search.search` contains `expression`, `fields: ["name"]`, and `fuzzy: false`. | `products[]` contains `id` and `name`; select the product using the name-matching guidance above. |
|
|
156
|
+
| Get Product | `GET https://www.wixapis.com/stores/v3/products/{productId}?fields=DESCRIPTION` | `product.id`, `product.revision`, and the full `product.description`. |
|
|
157
|
+
| Update Product | `PATCH https://www.wixapis.com/stores/v3/products/{productId}` with `{ product: { id, revision, description }, fields: ["DESCRIPTION"] }`, using the read ID/revision and complete edited document. | `product.description` verifies the edit; `product.revision` is the new revision. |
|
|
158
|
+
|
|
159
|
+
The request-level `fields` array projects response data; it is separate from `search.search.fields`, which selects the fields searched. A description-only PATCH needs only the three product fields shown above; variant, option, price, and physical-property fields belong to other update flows.
|
|
160
|
+
|
|
161
|
+
Use a single read-modify-write operation: locate the product, read its description and revision, make the requested change in memory, then PATCH once and verify the response.
|
|
162
|
+
|
|
163
|
+
1. Read [Get Product](https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/get-product) with `?fields=DESCRIPTION`. Its response wraps the document as `product.description` and the current revision as `product.revision`. If the description is missing or has no `nodes`, stop and ask before replacing it.
|
|
164
|
+
2. Copy the complete returned `product.description`, including node IDs, decorations, `metadata`, and `documentStyle`, **before locating any nodes to edit**. Traverse the copy and keep references to its nodes; edit that same copy and send it in the PATCH. For prepend/append, insert one new `PARAGRAPH` at the beginning/end of its `nodes`. For a wording change, modify only the matching `TEXT` node's `textData.text`.
|
|
165
|
+
3. For removal, trim only the requested substring from the matching TEXT run and keep its decorations. When the whole run or node is targeted, remove that entry from its parent `nodes` array. If text spans runs, trim the matching portion of each run. Preserve all other nodes, spacer paragraphs, and document properties. If the requested change is already present, report that state and finish without a write.
|
|
166
|
+
4. Check the in-memory PATCH document before sending: the targeted text has the requested value and untouched content matches the read document. Then send [Update Product](https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/update-product) to `PATCH https://www.wixapis.com/stores/v3/products/{productId}` with `product.id`, the read revision, the full edited `product.description`, and top-level `fields: ["DESCRIPTION"]`. Leave other product fields out of this description-only update; `plainDescription` is for whole-description replacements.
|
|
167
|
+
5. Verify `product.description` in the PATCH response: the requested change is present and untouched nodes, decorations, and document properties remain. Confirm completion from that response and finish. A successful PATCH has already performed the edit; verification does not require another PATCH. If the response is incomplete, read once with `?fields=DESCRIPTION` to verify. If a revision conflict rejects the write, read the latest document and reapply the requested change only if it is still needed.
|
|
168
|
+
|
|
169
|
+
For a prepend, build the complete PATCH body from the Get Product response (`getResponse` below). For an append, use `push` instead of `unshift`:
|
|
170
|
+
|
|
171
|
+
```javascript
|
|
172
|
+
const product = getResponse.product;
|
|
173
|
+
const description = structuredClone(product.description);
|
|
174
|
+
description.nodes.unshift({
|
|
175
|
+
type: "PARAGRAPH",
|
|
176
|
+
nodes: [{
|
|
177
|
+
type: "TEXT",
|
|
178
|
+
textData: { text: "New text.", decorations: [] }
|
|
179
|
+
}],
|
|
180
|
+
paragraphData: { textStyle: { textAlignment: "AUTO" } }
|
|
181
|
+
});
|
|
182
|
+
const patchBody = {
|
|
183
|
+
product: { id: product.id, revision: product.revision, description },
|
|
184
|
+
fields: ["DESCRIPTION"]
|
|
185
|
+
};
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
Send `patchBody` as the JSON body of the PATCH above. The copy retains the returned document's other properties and existing nodes, including links and buttons; the response's `product.description` includes the edited document because the request projects `DESCRIPTION`.
|
|
189
|
+
|
|
190
|
+
For example, remove only `read ` from a TEXT run containing `read the guide`, retaining its BOLD and LINK decorations and siblings. Locate the run in the cloned document, including nested nodes, rather than assuming a paragraph/run index. This example handles a phrase within one TEXT run; a phrase spanning runs uses the per-run trimming in step 3, with all run references taken from the copy.
|
|
191
|
+
|
|
192
|
+
```javascript
|
|
193
|
+
const product = getResponse.product;
|
|
194
|
+
const description = structuredClone(product.description);
|
|
195
|
+
const target = "read the guide";
|
|
196
|
+
const replacement = "the guide";
|
|
197
|
+
const matches = [];
|
|
198
|
+
function locate(node) {
|
|
199
|
+
if (node.type === "TEXT" && node.textData.text.includes(target)) matches.push(node.textData);
|
|
200
|
+
for (const child of node.nodes ?? []) locate(child);
|
|
201
|
+
}
|
|
202
|
+
locate(description);
|
|
203
|
+
if (matches.length !== 1) throw new Error("Clarify which text occurrence to edit");
|
|
204
|
+
const textData = matches[0];
|
|
205
|
+
const originalText = textData.text;
|
|
206
|
+
const start = originalText.indexOf(target);
|
|
207
|
+
if (start !== originalText.lastIndexOf(target)) throw new Error("Clarify which text occurrence to edit");
|
|
208
|
+
textData.text = originalText.slice(0, start) + replacement + originalText.slice(start + target.length);
|
|
209
|
+
if (textData.text === originalText || textData.text.includes(target)) {
|
|
210
|
+
throw new Error("The PATCH document must contain the requested edit before writing");
|
|
211
|
+
}
|
|
212
|
+
const patchBody = {
|
|
213
|
+
product: { id: product.id, revision: product.revision, description },
|
|
214
|
+
fields: ["DESCRIPTION"]
|
|
215
|
+
};
|
|
216
|
+
```
|
|
217
|
+
|
|
126
218
|
### Update Options and Variants
|
|
127
219
|
|
|
128
220
|
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.
|
|
@@ -339,8 +431,11 @@ its `id`, its `choices` (by `optionChoiceIds` — or `optionChoiceNames`, see *G
|
|
|
339
431
|
|
|
340
432
|
```bash
|
|
341
433
|
# A choice image + a variant's sale price, one PATCH. Both arrays are complete and keep their ids —
|
|
342
|
-
|
|
343
|
-
|
|
434
|
+
|
|
435
|
+
> These calls need the Wix Stores app on the site (`appDefId` `215238eb-22a5-4c36-9e7b-e7c08025e04e`); a `428`, a `400` naming the app, or an empty result on a site that should have content means it is not there. [List Installed Apps](../app-installation/list-installed-apps.md) shows what the site has; [Install Wix Apps](../app-installation/install-wix-apps.md) adds it by that id.
|
|
436
|
+
|
|
437
|
+
# keep the option and choice IDs when rebuilding the options array, and each variant
|
|
438
|
+
# with its choices and price. Omitting those identities or required variant fields can reject the update.
|
|
344
439
|
curl -X PATCH "https://www.wixapis.com/stores/v3/products/{productId}" \
|
|
345
440
|
-H "Content-Type: application/json" -H "Authorization: <AUTH>" \
|
|
346
441
|
-d '{ "product": { "id": "{productId}", "revision": "{currentRevision}",
|
|
@@ -357,9 +452,67 @@ curl -X PATCH "https://www.wixapis.com/stores/v3/products/{productId}" \
|
|
|
357
452
|
"choices": [ { "optionChoiceIds": { "optionId": "{optionId}", "choiceId": "{choiceId2}" } } ] } ] } } }'
|
|
358
453
|
```
|
|
359
454
|
|
|
455
|
+
### Prepare a Price or SKU Update
|
|
456
|
+
|
|
457
|
+
For an existing product's price or SKU, use the name lookup above, then Get Product. Request `?fields=VARIANT_OPTION_CHOICE_NAMES&fields=MERCHANT_DATA&fields=PRODUCT_CHOICES_MEDIA_REFERENCES&fields=PRODUCT_CHOICES_DISPLAY_IMAGE` so the same read supplies variant choice names, permitted cost data, and choice media to preserve. The response is `{ product: { id, revision, options, variantsInfo: { variants } } }`; search results cannot supply the variants.
|
|
458
|
+
|
|
459
|
+
Build the complete writable options and variants from that response, then change only the requested field. **Every variants PATCH also includes the complete `options` array**, even for an SKU-only change; for a product without options, send `options: []`. Omitting options caused `428 MISSING_OPTIONS_ON_UPDATE_VARIANTS`. A variant retains its `id`, `choices`, price, and other writable fields. The example below copies the writable fields used by these flows and strips calculated monetary values; inventory status and variant media are read-only and are not part of this update.
|
|
460
|
+
|
|
461
|
+
```javascript
|
|
462
|
+
const product = getResponse.product;
|
|
463
|
+
const pick = (source, keys) => Object.fromEntries(keys
|
|
464
|
+
.filter(key => source[key] !== undefined)
|
|
465
|
+
.map(key => [key, structuredClone(source[key])]));
|
|
466
|
+
const amountOnly = value => ({ amount: value.amount });
|
|
467
|
+
const options = (product.options ?? []).map(option => ({
|
|
468
|
+
...pick(option, ["id", "name", "optionRenderType"]),
|
|
469
|
+
choicesSettings: { choices: option.choicesSettings.choices.map(choice =>
|
|
470
|
+
pick(choice, ["choiceId", "name", "choiceType", "colorCode", "media", "displayImage"])) }
|
|
471
|
+
}));
|
|
472
|
+
const variants = product.variantsInfo.variants.map(variant => {
|
|
473
|
+
const copy = pick(variant, ["id", "visible", "sku", "barcode", "physicalProperties"]);
|
|
474
|
+
copy.choices = (variant.choices ?? []).map(choice => ({
|
|
475
|
+
optionChoiceNames: pick(choice.optionChoiceNames, ["optionName", "choiceName", "renderType"])
|
|
476
|
+
}));
|
|
477
|
+
copy.price = { actualPrice: amountOnly(variant.price.actualPrice) };
|
|
478
|
+
if (variant.price.compareAtPrice) copy.price.compareAtPrice = amountOnly(variant.price.compareAtPrice);
|
|
479
|
+
if (variant.revenueDetails?.cost) copy.revenueDetails = { cost: amountOnly(variant.revenueDetails.cost) };
|
|
480
|
+
if (variant.digitalProperties) {
|
|
481
|
+
copy.digitalProperties = variant.digitalProperties.digitalFile
|
|
482
|
+
? { digitalFile: { id: variant.digitalProperties.digitalFile.id } } : {};
|
|
483
|
+
}
|
|
484
|
+
if (copy.physicalProperties?.pricePerUnit) delete copy.physicalProperties.pricePerUnit.value;
|
|
485
|
+
return copy;
|
|
486
|
+
});
|
|
487
|
+
const variantPatchProduct = {
|
|
488
|
+
id: product.id, revision: product.revision, options,
|
|
489
|
+
variantsInfo: { variants }
|
|
490
|
+
};
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
For the single-variant product case (a user asking to change a simple product's price), use the prepared body above:
|
|
494
|
+
|
|
495
|
+
```javascript
|
|
496
|
+
if (variants.length !== 1) throw new Error("Clarify which variants should receive the price change");
|
|
497
|
+
variants[0].price.actualPrice.amount = "25"; // requested price
|
|
498
|
+
const pricePatchBody = { product: variantPatchProduct };
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
For a named option choice such as `Size = Large`, use its returned choice names to select one variant, then change its SKU:
|
|
502
|
+
|
|
503
|
+
```javascript
|
|
504
|
+
const matches = variants.filter(variant => variant.choices.some(choice =>
|
|
505
|
+
choice.optionChoiceNames.optionName === "Size" && choice.optionChoiceNames.choiceName === "Large"));
|
|
506
|
+
if (matches.length !== 1) throw new Error("Clarify which variant should receive the SKU change");
|
|
507
|
+
matches[0].sku = "MUG-L-001"; // requested SKU
|
|
508
|
+
const skuPatchBody = { product: variantPatchProduct };
|
|
509
|
+
```
|
|
510
|
+
|
|
511
|
+
Send the selected body to `PATCH https://www.wixapis.com/stores/v3/products/{productId}` in the same ExecuteWixAPI invocation as the name lookup and Get Product. Its response is `{ product: { id, revision, variantsInfo: { variants } } }`; verify the changed variant by its retained ID and confirm from that response. These examples provide the request fields and response paths for price and SKU changes; proceed directly after reading this recipe. Discover further schemas only for fields not covered here or a documented call that fails.
|
|
512
|
+
|
|
360
513
|
### Update Variant Price Only
|
|
361
514
|
|
|
362
|
-
Read `{existingVariantId}` off the Get Product response; a Search or Query Products result does not carry it.
|
|
515
|
+
Read `{existingVariantId}` off the Get Product response; a Search or Query Products result does not carry it. The curl below is for a single-variant product without options. For an optioned product, use the complete options/variants body in **Prepare a Price or SKU Update**.
|
|
363
516
|
|
|
364
517
|
```bash
|
|
365
518
|
curl -X PATCH "https://www.wixapis.com/stores/v3/products/{productId}" \
|
|
@@ -369,10 +522,12 @@ curl -X PATCH "https://www.wixapis.com/stores/v3/products/{productId}" \
|
|
|
369
522
|
"product": {
|
|
370
523
|
"id": "{productId}",
|
|
371
524
|
"revision": "{currentRevision}",
|
|
525
|
+
"options": [],
|
|
372
526
|
"variantsInfo": {
|
|
373
527
|
"variants": [
|
|
374
528
|
{
|
|
375
529
|
"id": "{existingVariantId}",
|
|
530
|
+
"choices": [],
|
|
376
531
|
"price": {
|
|
377
532
|
"actualPrice": {
|
|
378
533
|
"amount": "29.99"
|
|
@@ -387,7 +542,23 @@ curl -X PATCH "https://www.wixapis.com/stores/v3/products/{productId}" \
|
|
|
387
542
|
|
|
388
543
|
### Attach a Digital File
|
|
389
544
|
|
|
390
|
-
|
|
545
|
+
For an existing digital product rejected at add-to-cart with `ITEM_NOT_FOUND_IN_CATALOG`, use this repair flow. For a supplied external PDF URL, the table below is the complete request/response contract; execute it directly after reading this recipe. Use its linked method URLs as source citations. Further schema discovery is needed only for a field not covered here or a documented call that fails.
|
|
546
|
+
|
|
547
|
+
First locate the existing product with the name lookup above, then Get Product for its revision and variants. If the requested product is absent or ambiguous, ask for the correct product or site and stop before uploading media. Repairing an existing product does not authorize creating a replacement.
|
|
548
|
+
|
|
549
|
+
A `DIGITAL` product is sellable only when its variant has both a digital file and stock. For a product already in stock, keep that stock unchanged and attach only the missing file. `digitalProperties` belongs to the variant.
|
|
550
|
+
|
|
551
|
+
| Call | Request | Response fields used next |
|
|
552
|
+
|---|---|---|
|
|
553
|
+
| [Search Products](https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/search-products) | Use the `search.search` name lookup above. | `products[].id` and `name` select the existing product. |
|
|
554
|
+
| [Get Product](https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/get-product) | `GET https://www.wixapis.com/stores/v3/products/{productId}?fields=VARIANT_OPTION_CHOICE_NAMES&fields=MERCHANT_DATA&fields=PRODUCT_CHOICES_MEDIA_REFERENCES&fields=PRODUCT_CHOICES_DISPLAY_IMAGE` | `product.id`, `revision`, `productType`, `options`, and `variantsInfo.variants` supply the complete writable state. |
|
|
555
|
+
| [Import File](https://dev.wix.com/docs/api-reference/assets/media/media-manager/files/import-file) | `POST https://www.wixapis.com/site-media/v1/files/import` with `{ "url": "{suppliedPdfUrl}", "mimeType": "application/pdf", "displayName": "download.pdf", "private": true }` | `file.id` and `file.operationStatus`. Import the exact supplied URL once; retain this ID. |
|
|
556
|
+
| [Get File Descriptor](https://dev.wix.com/docs/api-reference/assets/media/media-manager/files/get-file-descriptor), only while PENDING | `GET https://www.wixapis.com/site-media/v1/files/get-file-by-id?fileId={fileId}` | `file.operationStatus`: wait for `READY`, stop on `FAILED`. The response is wrapped in `file`. |
|
|
557
|
+
| [Update Product](https://dev.wix.com/docs/api-reference/business-solutions/stores/catalog-v3/products-v3/update-product) | `PATCH https://www.wixapis.com/stores/v3/products/{productId}` with `{ product: { id, revision, options, variantsInfo: { variants } } }` | `product.variantsInfo.variants[].digitalProperties.digitalFile.id` confirms the attachment on the retained variant ID. |
|
|
558
|
+
|
|
559
|
+
Chain these requests in one ExecuteWixAPI invocation; with `wix.request`, the REST response body is in `response.data`. Private import keeps the stored download private. For a local file rather than a supplied URL, read [Upload Media to Wix](../media/upload-media-to-wix.md) and use its Generate Upload URL flow instead.
|
|
560
|
+
|
|
561
|
+
Prepare the complete options/variants body as in **Prepare a Price or SKU Update**, retain every variant ID, choice and price, and set the requested variant's `digitalProperties.digitalFile.id` to the imported file ID. For one existing variant with no options:
|
|
391
562
|
|
|
392
563
|
```bash
|
|
393
564
|
curl -X PATCH "https://www.wixapis.com/stores/v3/products/{productId}" \
|
|
@@ -397,22 +568,21 @@ curl -X PATCH "https://www.wixapis.com/stores/v3/products/{productId}" \
|
|
|
397
568
|
"product": {
|
|
398
569
|
"id": "{productId}",
|
|
399
570
|
"revision": "{currentRevision}",
|
|
571
|
+
"options": [],
|
|
400
572
|
"variantsInfo": {
|
|
401
|
-
"variants": [
|
|
402
|
-
{
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
409
|
-
]
|
|
573
|
+
"variants": [{
|
|
574
|
+
"id": "{existingVariantId}",
|
|
575
|
+
"choices": [],
|
|
576
|
+
"price": { "actualPrice": { "amount": "{existingPrice}" } },
|
|
577
|
+
"visible": true,
|
|
578
|
+
"digitalProperties": { "digitalFile": { "id": "{fileId}" } }
|
|
579
|
+
}]
|
|
410
580
|
}
|
|
411
581
|
}
|
|
412
582
|
}'
|
|
413
583
|
```
|
|
414
584
|
|
|
415
|
-
Confirm from `product.variantsInfo.variants[].digitalProperties.digitalFile` in the response.
|
|
585
|
+
Copy any other writable variant fields from the read product using the preparation example. Chain the product lookup, read, selected upload path, and one PATCH in one ExecuteWixAPI invocation. Confirm from `product.variantsInfo.variants[].digitalProperties.digitalFile.id` in the PATCH response; no extra product read is needed when that response supplies it.
|
|
416
586
|
|
|
417
587
|
## Important Notes
|
|
418
588
|
|
|
@@ -439,4 +609,4 @@ Confirm from `product.variantsInfo.variants[].digitalProperties.digitalFile` in
|
|
|
439
609
|
| `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 |
|
|
440
610
|
| `DIGITAL_PRODUCT_CANNOT_BE_VISIBLE_IN_POS` | Sent `visibleInPos: true` on a digital product | Digital products can't be visible in POS; leave `visibleInPos` out of the body |
|
|
441
611
|
| `ITEM_NOT_FOUND_IN_CATALOG` at add-to-cart, product exists | A `DIGITAL` variant has no `digitalProperties.digitalFile` | Attach a file — see [Attach a Digital File](#attach-a-digital-file) |
|
|
442
|
-
| `exceeds available inventory` at add-to-cart, product exists | The variant has no stock (`DIGITAL` products included) |
|
|
612
|
+
| `exceeds available inventory` at add-to-cart, product exists | The variant has no stock (`DIGITAL` products included) | Update its stock through the Inventory API; inventory is separate from an Update Product PATCH |
|