@wix/agent-skills 1.31.1 → 1.32.0

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.
Files changed (121) hide show
  1. package/README.md +4 -12
  2. package/package.json +1 -1
  3. package/skills/wix-app/SKILL.md +39 -15
  4. package/skills/wix-app/references/BACKEND_API.md +1 -1
  5. package/skills/wix-app/references/EDITOR_REACT_COMPONENT.md +11 -8
  6. package/skills/wix-app/references/SDK_MODULE_MAP.md +1 -1
  7. package/skills/wix-app/references/STORES_VERSIONING.md +24 -2
  8. package/skills/wix-app/references/dashboard-page/DATA_SOURCES.md +9 -13
  9. package/skills/wix-app/references/dashboard-page/IMAGE_RENDERING.md +61 -0
  10. package/skills/wix-app/references/editor-react-component/ACCESSIBILITY.md +54 -64
  11. package/skills/wix-app/references/editor-react-component/ANIMATED-COMPONENTS.md +14 -21
  12. package/skills/wix-app/references/editor-react-component/COMPONENT-CONTRACT.md +37 -30
  13. package/skills/wix-app/references/editor-react-component/CSS-GUIDELINES.md +43 -29
  14. package/skills/wix-app/references/editor-react-component/DESIGN-STATES.md +40 -39
  15. package/skills/wix-app/references/editor-react-component/PARTS.md +8 -6
  16. package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +22 -2
  17. package/skills/wix-app/scripts/scan-a11y-eslint.cjs +39 -16
  18. package/skills/wix-app/scripts/sdk-curated.json +45 -0
  19. package/skills/wix-app/scripts/sdk-lookup.cjs +1180 -0
  20. package/skills/wix-base44-connector/SKILL.md +4 -2
  21. package/skills/wix-base44-connector/scripts/utils.cjs +5 -2
  22. package/skills/wix-headless-kit/SKILL.md +20 -8
  23. package/skills/wix-headless-kit/guides/api-run.md +92 -68
  24. package/skills/wix-headless-kit/guides/existing-site.md +6 -0
  25. package/skills/wix-headless-kit/install/AGENTS.md +3 -2
  26. package/skills/wix-headless-kit/install/attach.mjs +32 -27
  27. package/skills/wix-headless-kit/install/background.mjs +32 -0
  28. package/skills/wix-headless-kit/install/bootstrap.mjs +28 -11
  29. package/skills/wix-headless-kit/install/check.mjs +2 -2
  30. package/skills/wix-headless-kit/install/context.mjs +49 -5
  31. package/skills/wix-headless-kit/install/deploy.mjs +33 -8
  32. package/skills/wix-headless-kit/install/env-ignore.mjs +16 -0
  33. package/skills/wix-headless-kit/install/install.mjs +95 -0
  34. package/skills/wix-headless-kit/install/pins.json +1 -1
  35. package/skills/wix-headless-kit/install/proc.mjs +46 -0
  36. package/skills/wix-headless-kit/install/setup.mjs +16 -25
  37. package/skills/wix-headless-kit/install/templates.mjs +2 -2
  38. package/skills/wix-headless-templates/blog/app/components/blog/RichContent.tsx +3 -2
  39. package/skills/wix-headless-templates/blog/project/package-lock.json +1287 -1299
  40. package/skills/wix-headless-templates/blog/project/package.json +1 -1
  41. package/skills/wix-headless-templates/blog/project/src/components/blog/RichContent.tsx +3 -2
  42. package/skills/wix-headless-templates/blog/rest/authors.ts +5 -5
  43. package/skills/wix-headless-templates/blog/rest/comments.ts +4 -4
  44. package/skills/wix-headless-templates/blog/rest/post-likes.ts +3 -3
  45. package/skills/wix-headless-templates/blog/rest/posts.ts +4 -4
  46. package/skills/wix-headless-templates/blog/rest/taxonomy.ts +5 -5
  47. package/skills/wix-headless-templates/blog/seed/seed-blog.mjs +2 -1
  48. package/skills/wix-headless-templates/bookings/rest/booking.ts +4 -4
  49. package/skills/wix-headless-templates/bookings/rest/services.ts +4 -4
  50. package/skills/wix-headless-templates/bookings/seed/seed-bookings.mjs +2 -1
  51. package/skills/wix-headless-templates/cms/rest/collections.ts +3 -3
  52. package/skills/wix-headless-templates/cms/rest/items.ts +4 -4
  53. package/skills/wix-headless-templates/cms/seed/seed-cms.mjs +2 -1
  54. package/skills/wix-headless-templates/donations/rest/campaigns.ts +4 -4
  55. package/skills/wix-headless-templates/donations/rest/donate.ts +3 -3
  56. package/skills/wix-headless-templates/donations/seed/seed-donations.mjs +2 -1
  57. package/skills/wix-headless-templates/events/rest/events.ts +4 -4
  58. package/skills/wix-headless-templates/events/rest/orders.ts +4 -4
  59. package/skills/wix-headless-templates/events/rest/registration.ts +4 -4
  60. package/skills/wix-headless-templates/events/seed/seed-events.mjs +2 -1
  61. package/skills/wix-headless-templates/faq/rest/faq.ts +4 -4
  62. package/skills/wix-headless-templates/faq/seed/seed-faq.mjs +2 -1
  63. package/skills/wix-headless-templates/forms/rest/forms.ts +4 -4
  64. package/skills/wix-headless-templates/forms/rest/submissions.ts +4 -4
  65. package/skills/wix-headless-templates/forms/seed/seed-forms.mjs +2 -1
  66. package/skills/wix-headless-templates/members/rest/auth.ts +3 -3
  67. package/skills/wix-headless-templates/members/rest/members.ts +4 -4
  68. package/skills/wix-headless-templates/members/seed/seed-members.mjs +2 -1
  69. package/skills/wix-headless-templates/portfolio/rest/portfolio.ts +4 -4
  70. package/skills/wix-headless-templates/portfolio/seed/seed-portfolio.mjs +2 -1
  71. package/skills/wix-headless-templates/pricing-plans/rest/plan-access.ts +3 -3
  72. package/skills/wix-headless-templates/pricing-plans/rest/plans.ts +4 -4
  73. package/skills/wix-headless-templates/pricing-plans/rest/purchase.ts +3 -3
  74. package/skills/wix-headless-templates/pricing-plans/seed/seed-pricing-plans.mjs +2 -1
  75. package/skills/wix-headless-templates/rentals/rest/rentals.ts +4 -4
  76. package/skills/wix-headless-templates/rentals/seed/seed-rentals.mjs +2 -1
  77. package/skills/wix-headless-templates/restaurants/rest/menu.ts +4 -4
  78. package/skills/wix-headless-templates/restaurants/rest/ordering.ts +5 -5
  79. package/skills/wix-headless-templates/restaurants/rest/reservations.ts +4 -4
  80. package/skills/wix-headless-templates/restaurants/seed/seed-restaurants.mjs +2 -1
  81. package/skills/wix-headless-templates/shared/capabilities/site-search/rest/search.ts +4 -4
  82. package/skills/wix-headless-templates/shared/capabilities/site-search/seed/install.mjs +6 -4
  83. package/skills/wix-headless-templates/shared/seed/main.mjs +15 -0
  84. package/skills/wix-headless-templates/shared/seed/wix-cli.mjs +43 -11
  85. package/skills/wix-headless-templates/storefront/INSTRUCTIONS.md +1 -1
  86. package/skills/wix-headless-templates/storefront/rest/cart.ts +5 -5
  87. package/skills/wix-headless-templates/storefront/rest/catalog.ts +5 -5
  88. package/skills/wix-headless-templates/storefront/seed/SEED.md +27 -9
  89. package/skills/wix-headless-templates/storefront/seed/seed-store.mjs +2 -1
  90. package/skills/wix-manage/SKILL.md +31 -9
  91. package/skills/wix-manage/references/app-installation/install-wix-apps.md +5 -1
  92. package/skills/wix-manage/references/app-installation/list-installed-apps.md +19 -9
  93. package/skills/wix-manage/references/automations/actions.md +134 -0
  94. package/skills/wix-manage/references/automations/activation-status.md +64 -48
  95. package/skills/wix-manage/references/automations/api-catalog.md +213 -77
  96. package/skills/wix-manage/references/automations/automation-model.md +199 -0
  97. package/skills/wix-manage/references/automations/bracket-expressions.md +132 -0
  98. package/skills/wix-manage/references/automations/build-and-manage-automations.md +305 -26
  99. package/skills/wix-manage/references/automations/triggers.md +190 -0
  100. package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +3 -0
  101. package/skills/wix-manage/references/bookings/external-calendar-integration.md +3 -0
  102. package/skills/wix-manage/references/bookings/multi-resource-service-creation.md +3 -0
  103. package/skills/wix-manage/references/cms/cms-data-items-crud.md +11 -2
  104. package/skills/wix-manage/references/cms/cms-publishing-flow.md +63 -16
  105. package/skills/wix-manage/references/collaborators/manage-site-collaborators.md +128 -0
  106. package/skills/wix-manage/references/forms/forms-dashboard-navigation.md +3 -1
  107. package/skills/wix-manage/references/forms/read-forms-and-submissions.md +277 -0
  108. package/skills/wix-manage/references/forms/update-form.md +8 -0
  109. package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +3 -0
  110. package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +3 -0
  111. package/skills/wix-manage/references/seo/manage-url-redirects.md +33 -4
  112. package/skills/wix-manage/references/sites/create-headless-site.md +16 -50
  113. package/skills/wix-manage/references/sites/manage-oauth-apps.md +4 -4
  114. package/skills/wix-manage/references/sites/read-site-context.md +4 -0
  115. package/skills/wix-manage/references/sites/upload-static-site.md +368 -261
  116. package/skills/wix-manage/references/stores/add-store-pages-to-site.md +3 -0
  117. package/skills/wix-manage/references/stores/change-store-currency.md +3 -0
  118. package/skills/wix-manage/references/stores/create-product-catalog-v3.md +3 -0
  119. package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +3 -0
  120. package/skills/wix-manage/references/stores/update-product-with-options.md +192 -22
  121. package/skills/wix-vibe-headless/references/shared/app/components/WixManageBanner.jsx +3 -3
@@ -1,93 +1,158 @@
1
1
  ---
2
2
  name: "Upload a Website or HTML Files"
3
- description: Publish a user's ready-made website — an index.html, a static build, or a zip exported from an AI builder or any other tool — as a live Wix site. Covers every way to get there — publishing straight into the user's Wix account when you hold their identity, publishing anonymously with a save link when you don't, and handing the user the Wix Headless drop page, or releasing it as a Wix Headless project — and how to get the user's identity through the Wix CLI. Use whenever the user wants to upload, publish, deploy, or host their own HTML/CSS/JS as a NEW site, including files generated for them earlier in the conversation, or to update a site published this way (replace its files on the same site and URL). Not for migrating a live store/site from another platform by URL or from CSV exports (use Site Import), not for adding HTML or custom code into an existing Wix site, and not for uploading images or documents to a site's media files.
3
+ description: Publish HTML, CSS, JavaScript or a static build as a Wix Headless website; inspect its deployed files and edit them on the same site and URL. Covers file and ZIP uploads, selective additions, replacements and deletions while preserving other files, full-site replacement, authenticated and anonymous publishing, verification, and connecting a Wix business backend. Use for files the user supplies or pages you create for them. Not for migrating a live site from another platform by URL or CSV (use Site Import), embedding code in an editor-built Wix site, or uploading assets to Media Manager.
4
4
  ---
5
5
 
6
6
  # Upload a Website or HTML Files
7
7
 
8
- The user has a finished website — hand-written HTML, a static build, a zip, a
9
- project an AI builder exported — and wants it live on Wix. Every route below ends
10
- the same way: a headless site in the user's Wix account that serves those files
11
- at a `*.wix-site-host.com` URL.
8
+ Wix serves uploaded static files at a `*.wix-site-host.com` URL. **A raw drop
9
+ replaces the entire file set: omitted files disappear.** The file helpers below
10
+ simulate a patch by downloading the current ZIP, merging changes, and dropping
11
+ the complete result. They preserve omitted files, but still transfer the full
12
+ site and are not atomic against another editor.
12
13
 
13
- ## What decides the route
14
+ ## Choose the task
14
15
 
15
- Three things about where you run decide it:
16
+ | Request | Flow |
17
+ | --- | --- |
18
+ | Publish files as a new site | [Choose an upload route](#before-the-calls), [create once](#create-the-site), upload, [verify](#verify-and-report). |
19
+ | Inspect or edit a deployed site | [Find its ID](#find-an-existing-site), then [list, read or patch](#change-it-later). Do not create another site. |
20
+ | Replace the entire deployed frontend | Confirm replacement of the serving frontend, then drop the complete intended file set on the same ID. |
21
+ | Make a shop, bookings, forms or other business controls work | [Connect a backend](#connect-a-backend) on the same site. A static upload alone does not make them functional. |
22
+ | Publish without a login | [Anonymous upload and release](#publish-anonymously), then claim or give the private save link. |
23
+ | Migrate a live site by URL or CSV/TSV | [Site Import](site-import.md), not this recipe. |
24
+ | Add an embed to an editor-built site / upload media assets | Use the editor / [Upload Media to Wix](../media/upload-media-to-wix.md), respectively. |
25
+
26
+ A request to publish or edit authorizes that work; do not ask again. A request
27
+ to inspect files authorizes no writes. Do not create from a template: that
28
+ creates an empty site rather than publishing the supplied files.
29
+
30
+ Quick reference: [upload through MCP](#drop-through-the-wix-mcp) ·
31
+ [upload with curl](#drop-with-curl) · [list/read](#list-and-read) ·
32
+ [patch](#patch-files) · [ZIP fallback](#download-edit-drop-fallback) ·
33
+ [images](#images) · [limits/errors](#limits-and-failures).
16
34
 
17
- - **Does your shell reach Wix?** `curl -sI https://www.wixapis.com` answers with an
18
- HTTP status line. When it fails, or there is no shell, it doesn't.
19
- - **Is the Wix MCP connected?** Its tools are in your tool list: `ExecuteWixAPI`,
20
- and usually `UploadHeadlessWebsiteFiles`.
21
- - **Do your files travel as files?** Some clients resolve a tool's `attachments`
22
- param themselves: a file the user attached, or one you wrote to disk, reaches
23
- the upload tool as the file. Elsewhere `attachments` comes back unresolved, and
24
- every file you send through the MCP is text you write into the call.
35
+ ## Before the calls
25
36
 
26
- | Your situation | Route |
27
- | --- | --- |
28
- | The shell reaches Wix | [Create the site](#create-the-site) and [drop the files with `curl`](#drop-with-curl) and a CLI token; without a login, [publish anonymously](#publish-anonymously). A site of text files can take the MCP route below instead, with no login. |
29
- | The shell doesn't reach Wix, or there is no shell, and the Wix MCP is connected | [Create the site](#create-the-site) and [drop through the MCP](#drop-through-the-wix-mcp): the files themselves when they travel as files, a text bundle when they don't. |
30
- | A project that needs a build (a `package.json`) | Build it where its dependencies install, then drop the build output. When the shell reaches Wix, the [headless skill](#connect-a-backend) builds and releases it. When it can't be built anywhere you are, ask the user for the build output. |
31
- | None of these, or every route failed | The [drop page](#the-drop-page): the user uploads the files. |
37
+ Choose an already-authenticated route that can access the files, not by the
38
+ client's name. Check the available tools before choosing:
39
+
40
+ - **Wix MCP connected:** use `UploadHeadlessWebsiteFiles` for a complete
41
+ upload and `ExecuteWixAPI` for API scripts and list/read/patch helpers.
42
+ `ExecuteWixAPI` supplies authenticated `wix.request({ scope: 'account', ... })`,
43
+ returning `{ status, data }`; no token or extra CLI login is needed.
44
+ - **Shell reaches Wix:** check `curl -sI https://www.wixapis.com` for an HTTP
45
+ status. Run `npx @wix/cli@latest login` once for browser approval, then
46
+ `npx @wix/cli@latest token`. Its token lasts 15 minutes; refresh after expiry
47
+ or a `403`. Use it as `$ACCESS_TOKEN`. Without login, use the anonymous route.
48
+ - **Neither route works:** use [the drop page](#the-drop-page). Never claim an
49
+ upload you could not perform.
50
+
51
+ Network access does not give access to files on the user's machine. If you
52
+ cannot read their files, ask for an attachment/export or give the drop page;
53
+ do not provision an empty site.
54
+
55
+ Build projects that need dependencies first, and upload only their static
56
+ output. If your environment cannot build the project, ask for the build output.
57
+ For a Wix business project, follow [Connect a backend](#connect-a-backend).
58
+
59
+ The JavaScript examples below run in `ExecuteWixAPI`, not directly in a shell
60
+ or browser. Without MCP, use the curl examples and edit downloaded files locally;
61
+ `wix.request`, `wix.multipart` and `wix.headless.files` are sandbox utilities,
62
+ not public SDK methods.
63
+
64
+ For external file inputs on either MCP tool, use only parameters in its visible schema.
65
+ Prefer resolved `attachments`: they transport files without retyping them.
66
+ If an attachment arrives unresolved as a local path, retrying that path cannot
67
+ work; use supported text input or [another image route](#images).
68
+ `files` text input uses this unescaped format:
69
+
70
+ ```text
71
+ === FILE: index.html ===
72
+ <!doctype html><html><head><title>Northwind Studio</title>
73
+ <link rel="stylesheet" href="assets/styles.css"></head><body><h1>Northwind Studio</h1></body></html>
74
+ === FILE: assets/styles.css ===
75
+ body { font-family: sans-serif; padding: 4rem; }
76
+ ```
32
77
 
33
- When files don't travel as files, writing them costs nothing for a page already
34
- in the conversation and a read and a rewrite for text files on disk; images never
35
- travel as text (see [Images](#images)). Publishing yourself beats the drop page
36
- whenever a route fits. Never report an upload you couldn't perform; when a route
37
- fails partway, hand over the drop page.
78
+ Each path is relative to the site root. This format cannot carry a file
79
+ containing an identical `=== FILE: … ===` delimiter line. Binary images are
80
+ not text input.
38
81
 
39
- ## Before the calls
82
+ Replace example IDs with response values: `metaSiteId` is the site ID, not
83
+ `appId` or `uploadId`. `$AGENT` / `AGENT_SLUG` is your short lowercase
84
+ attribution slug, or `unknown-agent`. Raw uploads use
85
+ `?campaign=mcp&agent=$AGENT`. Never leave a `$NAME` placeholder inside a
86
+ JavaScript URL.
40
87
 
41
- - **With a shell that reaches Wix**, `$ACCESS_TOKEN` is the user's token: run
42
- `npx @wix/cli@latest login` once (the user approves in the browser), then
43
- `npx @wix/cli@latest token` prints a token that lasts 15 minutes. Run it again
44
- when the token may have expired, and always after a `403`.
45
- - **Through the Wix MCP**, `ExecuteWixAPI` runs JavaScript
46
- whose `wix.request` calls carry the user's login: no token. Ids go into URLs as
47
- values; a `$NAME` there is sent as is. `wix.request` returns `{ status, data }`.
48
- - **`$AGENT`** is a short lowercase slug naming you (`claude-code`, `cursor`,
49
- `codex-cli`, `chatgpt`, `claude-ai`; `unknown-agent` if you can't tell). Every drop and upload
50
- carries `?campaign=mcp&agent=$AGENT`, which attributes the site to you in Wix's
51
- reports.
52
- - **`$META_SITE_ID`, `$UPLOAD_ID`, …** come from the previous response.
53
-
54
- **Reading the pages this recipe links.** A Wix skill you have installed is read
55
- from disk. Otherwise a `www.wix.com/skills/…` or `dev.wix.com/docs/…` page is read
56
- with the Wix MCP's `ReadFullDocsArticle` when the MCP is connected; it returns the
57
- page whole. A web fetch is the fallback.
88
+ Read linked skills from disk when installed; otherwise use `ReadFullDocsArticle`
89
+ when available for Wix skill/docs URLs, with web fetch as fallback.
58
90
 
59
91
  ## Create the site
60
92
 
61
- The [Create Headless Site](create-headless-site.md) call with no Wix Business
62
- Solutions. Name it after the page's `<title>` and keep `"origin": "drop"`.
93
+ Create only for a new site. Use the page title, at most 40 characters. Keep
94
+ `origin: 'drop'`, empty `seedOptions`, and both synchronous steps:
95
+
96
+ ```javascript
97
+ async function run() {
98
+ return wix.request({ scope: 'account', method: 'POST',
99
+ url: 'https://www.wixapis.com/headless-business-setup/v1/headless-business/provision',
100
+ body: { origin: 'drop',
101
+ newMetasite: { namingStrategy: { metaSiteName: 'Northwind Studio' }, seedOptions: [] },
102
+ synchronousSteps: ['SET_METASITE_NAME', 'CONFIGURE_HEADLESS_APP'] }
103
+ });
104
+ }
105
+ // result.data: { metaSiteId, appId }
106
+ ```
107
+
108
+ The shell equivalent:
63
109
 
64
110
  ```bash
65
111
  curl -sS -X POST "https://www.wixapis.com/headless-business-setup/v1/headless-business/provision" \
66
112
  -H "Authorization: Bearer $ACCESS_TOKEN" -H 'Content-Type: application/json' \
67
- -d '{"origin":"drop","newMetasite":{"namingStrategy":{"metaSiteName":"Northwind Studio"},"seedOptions":[]},
68
- "synchronousSteps":["SET_METASITE_NAME","CONFIGURE_HEADLESS_APP"]}'
69
- # {"metaSiteId":"7597a72e-bedc-4d86-af86-9a25d11f0632","appId":"9f0a8b59-1acb-4a67-aafd-f8602259cbfa"}
113
+ -d '{"origin":"drop","newMetasite":{"namingStrategy":{"metaSiteName":"Northwind Studio"},"seedOptions":[]},"synchronousSteps":["SET_METASITE_NAME","CONFIGURE_HEADLESS_APP"]}'
70
114
  ```
71
115
 
72
- In a script, the same call:
116
+ ## Drop through the Wix MCP
117
+
118
+ If `UploadHeadlessWebsiteFiles` is available, pass the existing
119
+ `metaSiteId` as `siteId` and the **complete** files. It creates no site,
120
+ replaces all files, adds attribution, and returns the live URL and dashboard.
121
+ Prefer a ZIP attachment containing the whole site, including images; a single
122
+ wrapping folder is stripped. Its limit is 10 MB per call. Otherwise use the
123
+ `files` text format above.
124
+
125
+ Without that tool, use `ExecuteWixAPI`. File inputs belong in the
126
+ external `files` or `attachments` parameter, not inside `code`; the script
127
+ receives them as the `files` global. For individual files:
73
128
 
74
129
  ```javascript
75
- const created = await wix.request({ scope: 'account', method: 'POST',
76
- url: 'https://www.wixapis.com/headless-business-setup/v1/headless-business/provision',
77
- body: { origin: 'drop', newMetasite: { namingStrategy: { metaSiteName: 'Northwind Studio' }, seedOptions: [] },
78
- synchronousSteps: ['SET_METASITE_NAME', 'CONFIGURE_HEADLESS_APP'] } });
79
- // created.data.metaSiteId
130
+ async function run() {
131
+ const siteId = 'META_SITE_ID';
132
+ const mp = wix.multipart(files);
133
+ return wix.request({ scope: 'account', method: 'POST',
134
+ url: `https://www.wixapis.com/headless-business-setup/v1/headless-business/${siteId}/drop?campaign=mcp&agent=AGENT_SLUG`,
135
+ headers: { 'Content-Type': mp.contentType }, body: mp.body });
136
+ }
137
+ // result.data: { uploadId, siteUrl }
80
138
  ```
81
139
 
82
- The site is in the user's account. When it goes live, give the user its
83
- `siteUrl` and the dashboard, `https://manage.wix.com/dashboard/{metaSiteId}`.
140
+ For a single ZIP attachment, use
141
+ `wix.multipart(await wix.unzip(files[0].content))` instead. Its entries must
142
+ already be site-root-relative; this local unzip does not strip a wrapper.
143
+ Do not hand-build multipart while `wix.multipart` exists.
144
+
145
+ An older execution schema without file inputs can pass inline entries to
146
+ `wix.multipart([{ path, content }])`. In JavaScript template literals, escape
147
+ backslashes first, then backticks and `${`; otherwise text is reinterpreted.
148
+ Only if `typeof wix.multipart !== 'function'`, construct multipart yourself:
149
+ parts named `files`, site-relative path as `filename`, CRLF line endings,
150
+ closing `--<boundary>--`, and the same boundary in the Content-Type header.
84
151
 
85
152
  ## Drop with curl
86
153
 
87
- One multipart request uploads and releases. Each file is a part named `files`
88
- whose **filename is its path relative to the site root**; that is how
89
- subdirectories survive. A single `.zip` part works too: it is unpacked
90
- server-side, a single wrapping folder stripped.
154
+ One request uploads and releases. Each part is named `files`; its
155
+ `filename` is the site-root-relative path, preserving subdirectories:
91
156
 
92
157
  ```bash
93
158
  curl -sS -X POST \
@@ -96,209 +161,283 @@ curl -sS -X POST \
96
161
  -F "files=@index.html;filename=index.html" \
97
162
  -F "files=@assets/styles.css;filename=assets/styles.css" \
98
163
  -F "files=@assets/logo.png;filename=assets/logo.png"
99
- # {"uploadId":"c0d5b3bb-…","siteUrl":"https://headless-zjfqzddjtww-northwind-1406.wix-site-host.com"}
164
+ # { "uploadId": "...", "siteUrl": "https://...wix-site-host.com" }
100
165
  ```
101
166
 
102
- `siteUrl` is final.
167
+ A single ZIP part also works: it is unpacked server-side with one wrapping
168
+ folder stripped. `siteUrl` is the final address.
103
169
 
104
- ## Drop through the Wix MCP
170
+ ## Find an existing site
171
+
172
+ Reuse the ID from the earlier upload. If only a name or URL is known, query the
173
+ user's sites and match it; ask if ambiguous. The default namespace omits
174
+ headless sites, so explicitly filter `HEADLESS`:
175
+
176
+ ```javascript
177
+ async function run() {
178
+ return wix.request({ scope: 'account', method: 'POST',
179
+ url: 'https://www.wixapis.com/site-list/v2/sites/query',
180
+ body: { query: { filter: { namespace: 'HEADLESS', id: { $in: ['META_SITE_ID'] } },
181
+ cursorPaging: { limit: 100 } } } });
182
+ }
183
+ // result.data.sites: match id/displayName/viewUrl
184
+ ```
105
185
 
106
- ### With the Wix MCP's upload tool
186
+ Omit the `id` filter when looking up by name/URL. While `data.metadata.hasNext`,
187
+ follow `data.metadata.cursors.next` with `{ query: { cursorPaging: { limit: 100,
188
+ cursor } } }`. See [Query Sites](query-sites.md) for name search on large accounts.
189
+ With a known ID, use `$in`, not a scalar ID or `$eq` (rejected).
190
+ Unclaimed anonymous sites instead use their saved ID and
191
+ [anonymous upload/release](#publish-anonymously).
107
192
 
108
- When the Wix MCP lists `UploadHeadlessWebsiteFiles`, it is the drop: pass it the
109
- `metaSiteId` from [Create the site](#create-the-site) as `siteId`, and the files.
110
- It replaces the whole file set, stamps the attribution itself, and returns
111
- `siteUrl` and the dashboard link. It creates no site and makes no other call.
193
+ ## Change it later
112
194
 
113
- - **When your files travel as files**, pass them as `attachments`: zip the whole
114
- site folder, images included, and pass the zip as one attachment. It is
115
- unpacked, a wrapping folder stripped, up to 10 MB per call. Nothing is written
116
- out by you. Where `attachments` doesn't resolve, a path passed in it fails:
117
- your files don't travel as files, and they go in the bundle below.
118
- - **When they don't**, pass a `files` text bundle: each file starts with a line
119
- `=== FILE: <path> ===` followed by its raw text, `<path>` relative to the site
120
- root. Nothing in it is escaped. It carries text files: HTML, CSS, JavaScript,
121
- SVG. Other images reach the site as [Images](#images) says.
195
+ Use the same site ID and URL. With `ExecuteWixAPI`, prefer its file helpers
196
+ for selective edits, not `UploadHeadlessWebsiteFiles`: sending only changed
197
+ files to that upload tool would remove omitted files. Without MCP, go directly
198
+ to the [ZIP fallback](#download-edit-drop-fallback).
122
199
 
123
- ```
124
- === FILE: index.html ===
125
- <!doctype html><html><head><title>Northwind Studio</title>
126
- <link rel="stylesheet" href="assets/styles.css"></head><body><h1>Northwind Studio</h1><img src="assets/logo.svg"></body></html>
127
- === FILE: assets/styles.css ===
128
- body { font-family: sans-serif; margin: 0; padding: 4rem; }
129
- === FILE: assets/logo.svg ===
130
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><circle cx="5" cy="5" r="4"/></svg>
200
+ The server may have helpers newer than the client's visible description.
201
+ Check once in `ExecuteWixAPI` without changing anything:
202
+
203
+ ```javascript
204
+ async function run() {
205
+ try {
206
+ const h = wix.headless.files;
207
+ return { fileHelpers: ['list', 'read', 'patch'].every(k => typeof h[k] === 'function') };
208
+ } catch { return { fileHelpers: false }; }
209
+ }
131
210
  ```
132
211
 
133
- The bundle can't carry a file with a line that reads exactly `=== FILE: … ===`.
212
+ If false, use the [ZIP fallback](#download-edit-drop-fallback). Do not retry a
213
+ missing helper or invent `UploadHeadlessWebsiteFiles` parameters such as `mode: 'merge'`.
214
+ These execution helpers do not change the full-replacement upload contract.
215
+ List/read/inline edits work without external file inputs.
134
216
 
135
- ### From an ExecuteWixAPI script
217
+ ### List and read
136
218
 
137
- Without the upload tool, both calls run in one script. The same bundle goes in
138
- the tool's **`files` param**, never in `code`; in `code` it is the `files` global
139
- (`[{ path, content, encoding? }]`), and `wix.multipart()` turns it into the body.
219
+ ```javascript
220
+ async function run() {
221
+ return wix.headless.files.list({ siteId: 'META_SITE_ID', prefix: 'assets/', offset: 0, limit: 100 });
222
+ }
223
+ // { files: [{ path, bytes, contentType }], total, offset, hasMore }
224
+ ```
225
+
226
+ Omit `prefix` to list all paths. Default limit is 100, maximum 200; advance
227
+ `offset` by the limit while `hasMore`. The size field is `bytes`, not `size`.
140
228
 
141
229
  ```javascript
142
230
  async function run() {
143
- const agent = 'your-agent-slug'; // $AGENT
144
- const created = await wix.request({ scope: 'account', method: 'POST',
145
- url: 'https://www.wixapis.com/headless-business-setup/v1/headless-business/provision',
146
- body: { origin: 'drop', newMetasite: { namingStrategy: { metaSiteName: 'Northwind Studio' }, seedOptions: [] },
147
- synchronousSteps: ['SET_METASITE_NAME', 'CONFIGURE_HEADLESS_APP'] } });
148
- const mp = wix.multipart(); // from the `files` param; or pass [{ path, content | base64 | bytes }]
149
- return await wix.request({ scope: 'account', method: 'POST',
150
- url: `https://www.wixapis.com/headless-business-setup/v1/headless-business/${created.data.metaSiteId}/drop?campaign=mcp&agent=${agent}`,
151
- headers: { 'Content-Type': mp.contentType }, body: mp.body });
231
+ return wix.headless.files.read({ siteId: 'META_SITE_ID', path: 'index.html' });
152
232
  }
233
+ // { path, bytes, contentType, text }
153
234
  ```
154
235
 
155
- A zip passed through `attachments` is one entry; unpack it first:
156
- `wix.multipart(await wix.unzip(files[0].content))`. Don't build a multipart body
157
- by hand while `wix.multipart()` exists (a malformed one is a bare `500`).
236
+ `text` is a **string**, not a method. Read supports UTF-8 text up to 256,000
237
+ bytes; use the ZIP fallback for larger/binary files. Helpers exclude the
238
+ generated `wix.config.json`. Each list/read fetches a fresh full snapshot, so
239
+ request only needed paths/pages; for bulk inspection download once instead.
158
240
 
159
- **An older `ExecuteWixAPI` with no `files` param** still has `wix.multipart()`:
160
- pass it the entries written in `code`, `[{ path, content }]`, the text as template
161
- literals. Escape `\` as `\\` first, then `` ` `` as `` \` `` and `${` as `\${`; an
162
- unescaped `\` is dropped or reinterpreted. Only when
163
- `typeof wix.multipart !== 'function'` is the body a string you build: parts named
164
- `files` with the path as `filename`, lines ending in `\r\n`, the body ending with
165
- `--<boundary>--`, and `Content-Type: multipart/form-data; boundary=<the same
166
- boundary>`.
241
+ ### Patch files
167
242
 
168
- ## Change it later
243
+ For a small edit, keep the original in the execution sandbox and guard the
244
+ replacement. Do not return/retype the whole file just to change one string:
169
245
 
170
- On the same `metaSiteId`, never a new site. Each drop replaces every file, and
171
- `siteUrl` stays.
246
+ ```javascript
247
+ async function run() {
248
+ const siteId = 'META_SITE_ID';
249
+ const current = await wix.headless.files.read({ siteId, path: 'index.html' });
250
+ const before = 'Welcome to Bloom Cafe';
251
+ if (current.text.split(before).length !== 2) throw new Error('Expected one headline; inspect before editing.');
252
+ return wix.headless.files.patch({ siteId, agent: 'AGENT_SLUG',
253
+ files: [{ path: current.path, content: current.text.replace(before, 'Bloom Cafe — Now Open') }] });
254
+ }
255
+ ```
172
256
 
173
- - **With a shell that reaches Wix**, edit the files and drop the full set with
174
- `curl`.
175
- - **Through the MCP**, change the site in one `ExecuteWixAPI` script: download
176
- what it serves, edit in code, and drop the full set back. Only the edit is
177
- written; images travel back as they are. When your files travel as files, a
178
- new zip of the whole site through the upload tool works as well. A full
179
- rewrite of the text bundle is for a site rewritten wholesale.
257
+ For authored additions/replacements, pass only changed files through supported
258
+ external file inputs, then:
259
+
260
+ ```javascript
261
+ async function run() {
262
+ return wix.headless.files.patch({ siteId: 'META_SITE_ID', files,
263
+ deletePaths: ['old-offer.html'], agent: 'AGENT_SLUG' });
264
+ }
265
+ ```
180
266
 
181
- For a site from an earlier conversation, find its `metaSiteId` with
182
- [Query Sites](#claim-it-into-the-users-account), matching the name or `viewUrl`.
183
- The download holds what the site serves plus a `wix.config.json`, which is left
184
- out of the drop:
267
+ If the visible `ExecuteWixAPI` schema has neither `files` nor `attachments`,
268
+ do not reference the `files` global. Supply changed text files inline as
269
+ `files: [{ path: 'hours.txt', content: 'Mon–Fri 8–5' }]` instead. Helper
270
+ availability does not imply file-input support; use the ZIP/shell fallback
271
+ for binary additions that cannot be supplied.
272
+
273
+ - Omitted paths are preserved. Delete only with explicit `deletePaths`; omit it
274
+ when nothing should be removed. Delete-only: `files: []` plus exact paths.
275
+ - Rename: supply the new path with the original bytes and delete the old path.
276
+ Never write and delete the same path.
277
+ - ZIP inputs expand without stripping a project folder. Paths must be literal,
278
+ case-sensitive, site-relative; duplicate/unsafe paths and `wix.config.json`
279
+ are rejected. Keep a root `index.html` or `index.htm` in the final site.
280
+ - Serialize edits. Neither read-then-patch nor patch's internal
281
+ download/merge/drop protects against a concurrent writer.
282
+
283
+ Inspect `summary.added/replaced/deleted/unchanged/missingDeletes`.
284
+ `unchanged` means supplied files already matched byte-for-byte; omitted files
285
+ are preserved too. `published: false` means no byte change, not failure.
286
+ A publish returns `siteUrl`, `uploadId`, `fileCount`. Then
287
+ [verify](#verify-and-report).
288
+
289
+ ### Download, edit, drop fallback
290
+
291
+ For older servers, bulk/binary reads, or a shell workflow, obtain the current
292
+ ZIP rather than reconstructing the site from memory:
185
293
 
186
294
  ```bash
187
- curl -sSL -o current.zip \
295
+ curl -sSL -H "Authorization: Bearer $ACCESS_TOKEN" -o current.zip \
188
296
  "https://www.wix.com/_api/wixstro-deployments/v1/instant-sites/$META_SITE_ID/download.zip"
189
297
  ```
190
298
 
191
- In a script, request that URL with `responseType: 'base64'` and pass `r.data` to
192
- `wix.unzip()`. Each entry is `{ path, bytes, text() }`; call `text()` only on text
193
- files, since a decoded image is corrupted. Entries go back to `wix.multipart()` as
194
- they are, an edited one as `{ path, content }`:
299
+ In an execution script, use `responseType: 'base64'` and feed `data` directly
300
+ to `wix.unzip`. Entries contain `{ path, bytes, text() }`: unlike helper
301
+ reads, **`text()` is a method**. Call it only on known text files. Here is a
302
+ complete guarded edit; untouched assets remain bytes:
195
303
 
196
304
  ```javascript
197
- const r = await wix.request({ scope: 'account', method: 'GET', responseType: 'base64',
198
- url: `https://www.wix.com/_api/wixstro-deployments/v1/instant-sites/${metaSiteId}/download.zip` });
199
- const entries = (await wix.unzip(r.data)).filter((e) => e.path !== 'wix.config.json').map((e) =>
200
- e.path === 'index.html' ? { path: e.path, content: e.text().replace('Welcome', 'Bloom Cafe — Now Open') } : e);
201
- const mp = wix.multipart(entries);
202
- // then the drop call: headers { 'Content-Type': mp.contentType }, body mp.body
305
+ async function run() {
306
+ const siteId = 'META_SITE_ID';
307
+ const r = await wix.request({ scope: 'account', method: 'GET', responseType: 'base64',
308
+ url: `https://www.wix.com/_api/wixstro-deployments/v1/instant-sites/${siteId}/download.zip` });
309
+ if (r.status !== 200) throw new Error('Snapshot unavailable; do not publish a partial site.');
310
+ const entries = (await wix.unzip(r.data)).filter(e => e.path !== 'wix.config.json');
311
+ const byPath = new Map(entries.map(e => [e.path, e]));
312
+ const page = byPath.get('index.html');
313
+ if (!page) throw new Error('Missing index.html; inspect the inventory.');
314
+ const before = 'Welcome to Bloom Cafe', text = page.text();
315
+ if (text.split(before).length !== 2) throw new Error('Expected one headline; inspect before editing.');
316
+ byPath.set(page.path, { path: page.path, content: text.replace(before, 'Bloom Cafe — Now Open') });
317
+ const mp = wix.multipart([...byPath.values()]);
318
+ return wix.request({ scope: 'account', method: 'POST',
319
+ url: `https://www.wixapis.com/headless-business-setup/v1/headless-business/${siteId}/drop?campaign=mcp&agent=AGENT_SLUG`,
320
+ headers: { 'Content-Type': mp.contentType }, body: mp.body });
321
+ }
203
322
  ```
204
323
 
205
- Never rebuild a site from memory.
324
+ Reuse the download/unzip portion for these operations:
325
+
326
+ | Operation | Script after obtaining `entries` / `byPath` |
327
+ | --- | --- |
328
+ | List only | `return entries.map(e => ({ path: e.path, bytes: e.bytes.length }));` No drop. |
329
+ | Read only | Find the exact entry, fail if missing, then `return entry.text();` for a known text file. No drop. |
330
+ | Add/replace | `byPath.set('hours.txt', { path: 'hours.txt', content: 'Mon–Fri 8–5' });` |
331
+ | Delete | `byPath.delete('old-offer.html');` |
332
+ | Merge supplied individual files | `for (const e of files) byPath.set(e.path, e);` |
333
+
334
+ For a single supplied ZIP, use `await wix.unzip(files[0].content)` instead of
335
+ `files` in that merge loop; its entries must be site-root-relative.
336
+ For mutations, validate paths and the final homepage, then drop **all** map
337
+ values. Leave `wix.config.json` out; preserve other unchanged entries as bytes.
338
+ Never pass only a delta to a raw drop. For a shell edit, likewise preserve the
339
+ downloaded files and upload the complete result.
340
+
341
+ If snapshot access is blocked by host policy, use authenticated curl or request
342
+ the complete current ZIP. Do not keep retrying, bypass the policy, or claim to
343
+ preserve files you could not retrieve. A failed file lookup is not evidence
344
+ that the site is empty.
345
+
346
+ ## Verify and report
347
+
348
+ 1. Check publication status and returned URL. For a patch, compare its change
349
+ summary with the requested paths, including missing deletions.
350
+ 2. Check the saved changed files using read or the ZIP; confirm removals and
351
+ preservation of unrelated assets. Do not treat a successful drop alone as
352
+ proof that the requested edit is correct.
353
+ 3. When available, open the live page and exercise the changed UI. HTTP/HTML
354
+ retrieval can verify delivery, but not layout or JavaScript behavior.
355
+ If live fetch/browser access is blocked, report the saved-file checks and
356
+ that limitation; do not claim a browser test.
357
+
358
+ If a call fails after publishing, inspect the current snapshot before retrying:
359
+ the write may have succeeded and only its subsequent verification failed.
360
+ Avoid repeating a mutation merely because the last call returned an error.
361
+
362
+ Give the live URL, what changed, what was verified, and any missing assets.
363
+ On first authenticated publish (or after claim), also give
364
+ `https://manage.wix.com/dashboard/{metaSiteId}` and
365
+ [domain connection](../domains/domain-search-purchase-and-connect.md) options
366
+ for a Wix-purchased or existing domain. For an unclaimed anonymous site, give
367
+ the live URL and private save link instead, not a dashboard link.
206
368
 
207
369
  ## Connect a backend
208
370
 
209
- A dropped site is static. Stores, payments, bookings, a CMS, members or forms
210
- need a **Wix Headless project**, which the headless skill builds and releases on
211
- the same site, appId and URL.
212
-
213
- **A mock that shows a business solution: publish it, then ask before connecting.**
214
- Any control on the page that promises what static files can't deliver —
215
- something to buy, book, order, join, submit or pay — is a Wix Business Solution
216
- the page pretends to have. First get the site live from what the user gave you.
217
- Then, with the live URL, name each such control, the solution that would make it
218
- work, and what connecting it involves: what gets created from the page's own
219
- content (the products, services or form). Ask whether to go ahead, and connect only after the user says
220
- yes; a request that already asks for it (a working shop, real bookings) is that
221
- yes. A page that promises nothing beyond its content stops at the pages.
222
-
223
- A site published anonymously is [claimed](#claim-it-into-the-users-account)
224
- before a backend: the headless skill works on a site in the user's account.
225
-
226
- The headless skill starts at its cold-start page,
227
- `https://www.wix.com/skills/headless-cold-start/headless-kit.md` (read it as
228
- [Before the calls](#before-the-calls) says). It installs the skills, runs a
229
- bootstrap that checks the Wix CLI login, and hands off to the kit's `SKILL.md`,
230
- which reads the folder, deploys the solution's code, seeds, builds and releases.
231
- Its commands run:
232
-
233
- - **With a shell that reaches Wix**, in a folder holding the site, from the
234
- site's own download:
235
-
236
- ```bash
237
- curl -sSL -o project.zip \
238
- "https://www.wix.com/_api/wixstro-deployments/v1/instant-sites/$META_SITE_ID/download.zip"
239
- unzip project.zip -d project
240
- ```
241
- - **Through the Wix MCP alone**, the kit's API-call guide,
242
- `https://www.wix.com/skills/wix-headless-kit/guides/api-run.md`, does the same
243
- run as Wix API calls through the Wix MCP, with the frontend dropped as this
244
- recipe says.
371
+ A static page cannot itself provide stores, payments, bookings, CMS, members
372
+ or forms. For an uploaded mock, publish it, then name the nonfunctional
373
+ buy/book/order/join/submit/pay controls, what Wix solution and content would
374
+ be created, and ask before connecting. A request for a working shop or real
375
+ bookings already supplies that consent; do not stop at a static mock.
376
+
377
+ Use the headless skill on the **same site, appId and URL**, not another site.
378
+ [Claim an anonymous site](#claim-it-into-the-users-account) first.
379
+
380
+ - With a build-capable shell, read
381
+ `https://www.wix.com/skills/headless-cold-start/headless-kit.md`. It installs
382
+ the skills, checks CLI login, then hands off to the kit for deployment,
383
+ seeding, build and release. Start from the site's downloaded ZIP, unpacked
384
+ into a project folder.
385
+ - With MCP execution only, read
386
+ `https://www.wix.com/skills/wix-headless-kit/guides/api-run.md` for the API
387
+ route, then upload the frontend as above.
245
388
 
246
389
  ## Images
247
390
 
248
- You never write an image's bytes yourself, as base64 or in any other form: model
249
- output corrupts them past a few thousand characters, and every byte costs tokens.
250
- An SVG is text and goes in like a page. Every other image reaches Wix one of four
251
- ways:
252
-
253
- 1. **With a shell that reaches Wix**, in the `curl` drop, from disk.
254
- 2. **When your files travel as files**, inside the zip you pass the upload tool.
255
- 3. **A public URL**: the page keeps the absolute URL.
256
- 4. **The user uploads it** to the site's Media Manager. This is the way for images
257
- that exist only as files you can't send. Publish the pages first, then name
258
- the missing files, give the user
259
- `https://manage.wix.com/dashboard/{metaSiteId}/media-manager`, and ask them to
260
- tell you once they're uploaded. Then [list the site's files](../media/upload-media-to-wix.md),
261
- match each to the page's reference by `displayName`, point the reference at the
262
- file's `static.wixstatic.com` URL, and drop again.
263
-
264
- Never stand in drawings or placeholders of your own for the user's images, and
265
- never shrink or re-encode them. The closing message names every image still
266
- missing.
391
+ SVG is text; other images are bytes. Prefer, in order:
392
+
393
+ 1. Local originals included in the curl drop.
394
+ 2. Resolved file/ZIP attachments.
395
+ 3. A direct public image URL kept in the page, or imported through
396
+ `UploadImageToWixSite` when available using `imageUrls`; use its returned
397
+ `static.wixstatic.com` URL. A sharing page is not a direct file URL.
398
+ 4. Tool-encoded `imageBase64` with `mimeType`, one image per call, if the
399
+ tool exposes those fields. Never synthesize base64 in
400
+ model output: it causes decoding errors or corrupt images.
401
+ 5. If bytes cannot be sent, publish the pages and name the missing images.
402
+ Ask the user to upload them at
403
+ `https://manage.wix.com/dashboard/{metaSiteId}/media-manager`.
404
+ Then [list media](../media/upload-media-to-wix.md), match `displayName`,
405
+ update references to returned public URLs and republish.
406
+
407
+ Never substitute drawings/placeholders for supplied images, shrink/re-encode
408
+ them, or decode unchanged binary files as text during edits.
267
409
 
268
410
  ## Publish anonymously
269
411
 
270
- With a shell that reaches Wix and no login: the site belongs to a temporary owner and
271
- lives one hour unless the user keeps it. Generate `anonymousId` yourself, any
272
- UUID, once per site, and reuse it with the returned `metaSiteId` for every call.
273
- After one hour every call, claim included, returns `404`.
412
+ With shell access to Wix but no login, generate one UUID as `anonymousId`
413
+ and reuse it with the returned `metaSiteId`. The temporary site expires after
414
+ one hour unless kept; expired calls, including claim, return `404`.
274
415
 
275
416
  ```bash
276
- # 1. create
417
+ # 1. Create: returns { metaSiteId, projectId }
277
418
  curl -sS -X POST "https://www.wixapis.com/headless-business-setup/v1/headless-business/anonymous/$ANONYMOUS_ID"
278
- # {"metaSiteId":"f0ad8672-…","projectId":"54528d34-…"}
279
419
 
280
- # 2. upload: the drop's multipart shape; nothing is live yet
420
+ # 2. Upload the complete file set: returns { uploadId }; not live yet
281
421
  curl -sS -X POST \
282
422
  "https://www.wixapis.com/headless-business-setup/v1/headless-business/anonymous/$ANONYMOUS_ID/$META_SITE_ID/upload?campaign=mcp&agent=$AGENT" \
283
423
  -F "files=@index.html;filename=index.html" -F "files=@assets/styles.css;filename=assets/styles.css"
284
- # {"uploadId":"03244542-…"}
285
424
 
286
- # 3. release: the site goes live
425
+ # 3. Release: returns { siteUrl }
287
426
  curl -sS -X POST \
288
427
  "https://www.wixapis.com/headless-business-setup/v1/headless-business/anonymous/$ANONYMOUS_ID/$META_SITE_ID/release" \
289
428
  -H 'Content-Type: application/json' -d "{\"uploadId\":\"$UPLOAD_ID\"}"
290
- # {"siteUrl":"https://instant-hguwrvtcrniw-headlessstack-140d.wix-site-host.com"}
291
429
  ```
292
430
 
293
- To change the site, repeat steps 2 and 3 with the full file set. When it's final,
294
- claim it with the user's identity. Without one, give the user `siteUrl` and the
295
- save link, which signs them in to keep the site. Whoever opens the link while
296
- signed in to Wix gets the site, so give it only to the user:
431
+ For edits, repeat upload and release with the full set. When finished, claim
432
+ with the user's identity or give them the live URL and this save link:
297
433
 
298
- ```
434
+ ```text
299
435
  https://www.wix.com/live-headless-site/{projectId}?anonymousId={anonymousId}
300
436
  ```
301
437
 
438
+ The link signs them in to keep the site. **Whoever opens it while signed in
439
+ gets the site; share it only with the user.**
440
+
302
441
  ### Claim it into the user's account
303
442
 
304
443
  ```bash
@@ -307,66 +446,34 @@ curl -sS -X POST \
307
446
  -H "Authorization: Bearer $ACCESS_TOKEN"
308
447
  ```
309
448
 
310
- Claim last: it ends the anonymous record, and later changes are
311
- [drops](#change-it-later). **The URL changes on claim.** Read the new `viewUrl`
312
- with Query Sites in the `HEADLESS` namespace; the default query omits headless
313
- sites and rejects an `id` filter, so match the id yourself, paging with
314
- `metadata.cursors.next`:
315
-
316
- ```bash
317
- curl -sS -X POST "https://www.wixapis.com/site-list/v2/sites/query" \
318
- -H "Authorization: Bearer $ACCESS_TOKEN" -H 'Content-Type: application/json' \
319
- -d '{"query":{"filter":{"namespace":"HEADLESS"},"cursorPaging":{"limit":100}}}'
320
- ```
449
+ Claim last: it ends the anonymous record. Later edits use authenticated drops
450
+ or patches. **The URL changes on claim**; obtain the new `sites[0].viewUrl`
451
+ with the [HEADLESS site query](#find-an-existing-site).
321
452
 
322
453
  ## The drop page
323
454
 
324
- ```
325
- https://www.wix.com/headless/drop?utm_campaign=mcp&agent=<your-agent-id>
326
- ```
455
+ `https://www.wix.com/headless/drop?utm_campaign=mcp&agent=<your-agent-id>`
327
456
 
328
- The user drags in the files without logging in, the site is live at once, and a
329
- banner offers to keep it. Tell them the limits below first.
330
-
331
- When no route reached Wix from where you are, say what would let you publish it
332
- yourself: a shell whose network reaches Wix, or the Wix MCP connected (the Wix
333
- plugin or connector in a chat client).
457
+ When no upload route works, the user can drag in files without login; the site
458
+ goes live and a banner offers to keep it. Explain the limits below and what
459
+ would enable you to publish directly: a network-enabled shell or connected
460
+ Wix MCP.
334
461
 
335
462
  ## Limits and failures
336
463
 
337
- - **A top-level HTML file.** A lone one of any name is the homepage; with more
338
- than one, `index.html` must be among them.
339
- - **3 MB per file, 20 MB per site.**
340
- - **Static files only** in a drop. A project that needs a build is built first,
341
- and its build output is dropped.
464
+ - Raw drop: a lone top-level HTML file of any name becomes the homepage; with
465
+ multiple HTML files, include `index.html`. The patch helper requires a root
466
+ `index.html` or `index.htm`.
467
+ - 20 MB per file and site; `UploadHeadlessWebsiteFiles` limits each call
468
+ to 10 MB. Patch also limits the final snapshot to 2,000 files.
469
+ - Drop serves static files, not unbuilt project source.
342
470
 
343
- | Failure | Meaning |
471
+ | Failure | Action |
344
472
  | --- | --- |
345
- | `400` `MISSING_INDEX_HTML`, `FILE_TOO_LARGE`, `TOTAL_TOO_LARGE` | In `details.applicationError.code`; fix the files. |
346
- | `403 PERMISSION_DENIED` on a drop | The token expired or is missing, or the site isn't the caller's. An anonymous site takes upload and release, not a drop. |
347
- | `500` on a drop or upload | A malformed multipart body; rebuild it as shown. The same body fails again. |
348
- | `404` on the anonymous route | The hour passed or the site was claimed. |
349
-
350
- ## Send feedback to Wix
351
-
352
- When this flow didn't work well enough, offer to send it to Wix as feedback,
353
- following [Send Feedback to Wix](send-feedback-to-wix.md): a route failed and you
354
- fell back, a call errored or needed retries, images had to wait on the user, or
355
- the recipe left you guessing and you had to invent a
356
- workaround.
357
-
358
- ## Route the request correctly
359
-
360
- - **A new site from the user's files**: [What decides the route](#what-decides-the-route).
361
- - **A change to a site published this way**: the [same site](#change-it-later);
362
- upload and release while it's anonymous.
363
- - **An anonymous site the user wants to keep**: [claim it](#claim-it-into-the-users-account), or the save link.
364
- - **A site that now needs a backend**: [Connect a backend](#connect-a-backend).
365
- - **Migrating a live site or store from another platform by URL, or CSV/TSV
366
- exports**: [Site Import](site-import.md).
367
- - **HTML, an embed or code inside an existing Wix site**: not this recipe; that is
368
- custom code in the editor.
369
- - **Images, videos or documents for a site's media**: [Upload Media to Wix](../media/upload-media-to-wix.md).
370
-
371
- Don't create the site from a template: that makes an empty site, not a copy of
372
- the user's files.
473
+ | `400` with `MISSING_INDEX_HTML`, `FILE_TOO_LARGE`, `TOTAL_TOO_LARGE` | Read `details.applicationError.code` and fix the files. |
474
+ | Drop `403 PERMISSION_DENIED` | Check token freshness and access to this site. An unclaimed anonymous site requires upload/release, not drop. |
475
+ | Drop/upload `500` | Inspect current state before retrying once; retain the request ID if it fails again and offer the drop page. Hand-built malformed multipart can also cause this: use `wix.multipart`. |
476
+ | Anonymous `404` | The hour expired or the site was claimed; do not create a replacement without explaining. |
477
+
478
+ Offer [feedback to Wix](send-feedback-to-wix.md) when a route fails, retries or
479
+ workarounds are needed, images must wait for the user, or guidance is missing.