@wix/agent-skills 1.31.2 → 1.33.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 (43) 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 +47 -45
  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 +25 -27
  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 +42 -42
  15. package/skills/wix-app/references/editor-react-component/DISABLED-INVALID.md +31 -0
  16. package/skills/wix-app/references/editor-react-component/MANIFEST-ERRORS.md +14 -1
  17. package/skills/wix-app/references/editor-react-component/PARTS.md +40 -9
  18. package/skills/wix-app/references/editor-react-component/PROPS-VS-CSS.md +22 -2
  19. package/skills/wix-app/references/editor-react-component/SSR.md +6 -3
  20. package/skills/wix-app/scripts/scan-a11y-eslint.cjs +39 -16
  21. package/skills/wix-app/scripts/sdk-curated.json +45 -0
  22. package/skills/wix-app/scripts/sdk-lookup.cjs +1180 -0
  23. package/skills/wix-base44-connector/SKILL.md +4 -2
  24. package/skills/wix-base44-connector/scripts/utils.cjs +5 -2
  25. package/skills/wix-headless-kit/SKILL.md +4 -1
  26. package/skills/wix-headless-kit/guides/api-run.md +14 -20
  27. package/skills/wix-headless-kit/install/pins.json +1 -1
  28. package/skills/wix-manage/SKILL.md +30 -8
  29. package/skills/wix-manage/references/automations/actions.md +134 -0
  30. package/skills/wix-manage/references/automations/activation-status.md +64 -48
  31. package/skills/wix-manage/references/automations/api-catalog.md +213 -77
  32. package/skills/wix-manage/references/automations/automation-model.md +199 -0
  33. package/skills/wix-manage/references/automations/bracket-expressions.md +132 -0
  34. package/skills/wix-manage/references/automations/build-and-manage-automations.md +305 -26
  35. package/skills/wix-manage/references/automations/triggers.md +190 -0
  36. package/skills/wix-manage/references/collaborators/manage-site-collaborators.md +128 -0
  37. package/skills/wix-manage/references/forms/forms-dashboard-navigation.md +3 -1
  38. package/skills/wix-manage/references/forms/read-forms-and-submissions.md +277 -0
  39. package/skills/wix-manage/references/forms/update-form.md +5 -0
  40. package/skills/wix-manage/references/seo/manage-url-redirects.md +33 -4
  41. package/skills/wix-manage/references/sites/create-headless-site.md +14 -5
  42. package/skills/wix-manage/references/sites/upload-static-site.md +373 -302
  43. package/skills/wix-vibe-headless/references/shared/app/components/WixManageBanner.jsx +3 -3
@@ -1,114 +1,158 @@
1
1
  ---
2
2
  name: "Upload a Website or HTML Files"
3
- description: Create and update a Wix Headless website by uploading its files — an index.html, a static build, a zip exported from an AI builder or any other tool, or pages you write for the user — as a live site in the user's Wix account. Covers every route: uploading with the user's identity (curl with a Wix CLI token, or the Wix MCP), publishing anonymously with a save link when you don't hold it, and the Wix Headless drop page; then updating the same site and URL, and connecting a Wix backend (stores, bookings, forms) through the headless skill. Use when the user wants to upload, publish, deploy or host HTML/CSS/JS as a new Wix site, their own or written for them, or to change a site published this way. 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
- A website goes live on Wix as a Wix Headless site: its files are uploaded to a
9
- site in the user's Wix account and served at a `*.wix-site-host.com` URL. The
10
- files are ones the user has (hand-written HTML, a static build, a zip, a project
11
- an AI builder exported) or ones you write for them as you upload. Later changes
12
- upload to [the same site](#change-it-later), and the URL stays.
13
-
14
- The flow: pick the route that fits where you run, create the site, upload the
15
- files, and give the user the live URL. Later changes go to the same site, and a
16
- backend, when the site needs one, comes once it is live.
17
-
18
- - [What decides the route](#what-decides-the-route): which route fits where you run
19
- - [Before the calls](#before-the-calls): the user's token, the Wix MCP, the attribution slug
20
- - [Create the site](#create-the-site): one call, the site in the user's account
21
- - Upload the files [with curl](#drop-with-curl) or [through the Wix MCP](#drop-through-the-wix-mcp)
22
- - [Change it later](#change-it-later): edits on the same site and URL
23
- - [Connect a backend](#connect-a-backend): stores, bookings, forms and more through the headless skill
24
- - [Images](#images): how images reach the site
25
- - [Publish anonymously](#publish-anonymously): no login, a temporary site the user claims or saves
26
- - [The drop page](#the-drop-page): the user uploads the files when no route reaches Wix
27
- - [Limits and failures](#limits-and-failures), [Send feedback to Wix](#send-feedback-to-wix), [Route the request correctly](#route-the-request-correctly)
28
-
29
- ## What decides the route
30
-
31
- The user's request to publish is the consent to create the site and upload: do
32
- not ask again before either. Ask only where this recipe says to (connecting a
33
- backend, replacing a frontend that is serving).
34
-
35
- Three things about where you run decide it:
36
-
37
- - **Does your shell reach Wix?** `curl -sI https://www.wixapis.com` answers with an
38
- HTTP status line. When it fails, or there is no shell, it doesn't.
39
- - **Is the Wix MCP connected?** Its tools are in your tool list: `ExecuteWixAPI`,
40
- and usually `UploadHeadlessWebsiteFiles`.
41
- - **Do your files travel as files?** Some clients resolve a tool's `attachments`
42
- param themselves: a file the user attached, or one you wrote to disk, reaches
43
- the upload tool as the file. Elsewhere `attachments` comes back unresolved, and
44
- every file you send through the MCP is text you write into the call.
45
-
46
- | Your situation | Route |
47
- | --- | --- |
48
- | 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. |
49
- | 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. |
50
- | 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. |
51
- | None of these, or every route failed | The [drop page](#the-drop-page): the user uploads the files. |
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.
13
+
14
+ ## Choose the task
52
15
 
53
- When files don't travel as files, writing them costs nothing for a page already
54
- in the conversation and a read and a rewrite for text files on disk; images never
55
- travel as text (see [Images](#images)). Publishing yourself beats the drop page
56
- whenever a route fits. Never report an upload you couldn't perform; when a route
57
- fails partway, hand over the drop page.
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).
58
34
 
59
35
  ## Before the calls
60
36
 
61
- - **With a shell that reaches Wix**, `$ACCESS_TOKEN` is the user's token: run
62
- `npx @wix/cli@latest login` once (the user approves in the browser), then
63
- `npx @wix/cli@latest token` prints a token that lasts 15 minutes. Run it again
64
- when the token may have expired, and always after a `403`.
65
- - **Through the Wix MCP**, `ExecuteWixAPI` runs JavaScript
66
- whose `wix.request` calls carry the user's login: no token. Ids go into URLs as
67
- values; a `$NAME` there is sent as is. `wix.request` returns `{ status, data }`.
68
- - **`$AGENT`** is a short lowercase slug naming you (`claude-code`, `cursor`,
69
- `codex-cli`, `chatgpt`, `claude-ai`; `unknown-agent` if you can't tell). Every drop and upload
70
- carries `?campaign=mcp&agent=$AGENT`, which attributes the site to you in Wix's
71
- reports.
72
- - **`$META_SITE_ID`, `$UPLOAD_ID`, …** come from the previous response.
73
-
74
- **Reading the pages this recipe links.** A Wix skill you have installed is read
75
- from disk. Otherwise a `www.wix.com/skills/…` or `dev.wix.com/docs/…` page is read
76
- with the Wix MCP's `ReadFullDocsArticle` when the MCP is connected; it returns the
77
- page whole. A web fetch is the fallback.
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
+ ```
77
+
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.
81
+
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.
87
+
88
+ Read linked skills from disk when installed; otherwise use `ReadFullDocsArticle`
89
+ when available for Wix skill/docs URLs, with web fetch as fallback.
78
90
 
79
91
  ## Create the site
80
92
 
81
- One account-level call creates the headless site, with no Wix Business
82
- Solutions. Name it after the page's `<title>`, at most 40 characters (a longer
83
- name is rejected), 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:
84
109
 
85
110
  ```bash
86
111
  curl -sS -X POST "https://www.wixapis.com/headless-business-setup/v1/headless-business/provision" \
87
112
  -H "Authorization: Bearer $ACCESS_TOKEN" -H 'Content-Type: application/json' \
88
- -d '{"origin":"drop","newMetasite":{"namingStrategy":{"metaSiteName":"Northwind Studio"},"seedOptions":[]},
89
- "synchronousSteps":["SET_METASITE_NAME","CONFIGURE_HEADLESS_APP"]}'
90
- # {"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"]}'
91
114
  ```
92
115
 
93
- 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:
94
128
 
95
129
  ```javascript
96
- const created = await wix.request({ scope: 'account', method: 'POST',
97
- url: 'https://www.wixapis.com/headless-business-setup/v1/headless-business/provision',
98
- body: { origin: 'drop', newMetasite: { namingStrategy: { metaSiteName: 'Northwind Studio' }, seedOptions: [] },
99
- synchronousSteps: ['SET_METASITE_NAME', 'CONFIGURE_HEADLESS_APP'] } });
100
- // 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 }
101
138
  ```
102
139
 
103
- The site is in the user's account. When it goes live, give the user its
104
- `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.
105
151
 
106
152
  ## Drop with curl
107
153
 
108
- One multipart request uploads and releases. Each file is a part named `files`
109
- whose **filename is its path relative to the site root**; that is how
110
- subdirectories survive. A single `.zip` part works too: it is unpacked
111
- 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:
112
156
 
113
157
  ```bash
114
158
  curl -sS -X POST \
@@ -117,223 +161,283 @@ curl -sS -X POST \
117
161
  -F "files=@index.html;filename=index.html" \
118
162
  -F "files=@assets/styles.css;filename=assets/styles.css" \
119
163
  -F "files=@assets/logo.png;filename=assets/logo.png"
120
- # {"uploadId":"c0d5b3bb-…","siteUrl":"https://headless-zjfqzddjtww-northwind-1406.wix-site-host.com"}
164
+ # { "uploadId": "...", "siteUrl": "https://...wix-site-host.com" }
121
165
  ```
122
166
 
123
- `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.
124
169
 
125
- ## Drop through the Wix MCP
170
+ ## Find an existing site
126
171
 
127
- ### With the Wix MCP's upload tool
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`:
128
175
 
129
- When the Wix MCP lists `UploadHeadlessWebsiteFiles`, it is the drop: pass it the
130
- `metaSiteId` from [Create the site](#create-the-site) as `siteId`, and the files.
131
- It replaces the whole file set, stamps the attribution itself, and returns
132
- `siteUrl` and the dashboard link. It creates no site and makes no other call.
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
+ ```
133
185
 
134
- - **When your files travel as files**, pass them as `attachments`: zip the whole
135
- site folder, images included, and pass the zip as one attachment. It is
136
- unpacked, a wrapping folder stripped, up to 10 MB per call. Nothing is written
137
- out by you. Where `attachments` doesn't resolve, a path passed in it fails:
138
- your files don't travel as files, and they go in the bundle below.
139
- - **When they don't**, pass a `files` text bundle: each file starts with a line
140
- `=== FILE: <path> ===` followed by its raw text, `<path>` relative to the site
141
- root. Nothing in it is escaped. It carries text files: HTML, CSS, JavaScript,
142
- SVG. Other images reach the site as [Images](#images) says.
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).
143
192
 
193
+ ## Change it later
194
+
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).
199
+
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
+ }
144
210
  ```
145
- === FILE: index.html ===
146
- <!doctype html><html><head><title>Northwind Studio</title>
147
- <link rel="stylesheet" href="assets/styles.css"></head><body><h1>Northwind Studio</h1><img src="assets/logo.svg"></body></html>
148
- === FILE: assets/styles.css ===
149
- body { font-family: sans-serif; margin: 0; padding: 4rem; }
150
- === FILE: assets/logo.svg ===
151
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 10 10"><circle cx="5" cy="5" r="4"/></svg>
152
- ```
153
211
 
154
- 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.
216
+
217
+ ### List and read
155
218
 
156
- ### From an ExecuteWixAPI script
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
+ ```
157
225
 
158
- Without the upload tool, both calls run in one script. The same bundle goes in
159
- the tool's **`files` param**, never in `code`; in `code` it is the `files` global
160
- (`[{ path, content, encoding? }]`), and `wix.multipart()` turns it into the body.
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`.
161
228
 
162
229
  ```javascript
163
230
  async function run() {
164
- const agent = 'your-agent-slug'; // $AGENT
165
- const created = await wix.request({ scope: 'account', method: 'POST',
166
- url: 'https://www.wixapis.com/headless-business-setup/v1/headless-business/provision',
167
- body: { origin: 'drop', newMetasite: { namingStrategy: { metaSiteName: 'Northwind Studio' }, seedOptions: [] },
168
- synchronousSteps: ['SET_METASITE_NAME', 'CONFIGURE_HEADLESS_APP'] } });
169
- const mp = wix.multipart(); // from the `files` param; or pass [{ path, content | base64 | bytes }]
170
- return await wix.request({ scope: 'account', method: 'POST',
171
- url: `https://www.wixapis.com/headless-business-setup/v1/headless-business/${created.data.metaSiteId}/drop?campaign=mcp&agent=${agent}`,
172
- headers: { 'Content-Type': mp.contentType }, body: mp.body });
231
+ return wix.headless.files.read({ siteId: 'META_SITE_ID', path: 'index.html' });
173
232
  }
233
+ // { path, bytes, contentType, text }
174
234
  ```
175
235
 
176
- A zip passed through `attachments` is one entry; unpack it first:
177
- `wix.multipart(await wix.unzip(files[0].content))`. Don't build a multipart body
178
- 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.
179
240
 
180
- **An older `ExecuteWixAPI` with no `files` param** still has `wix.multipart()`:
181
- pass it the entries written in `code`, `[{ path, content }]`, the text as template
182
- literals. Escape `\` as `\\` first, then `` ` `` as `` \` `` and `${` as `\${`; an
183
- unescaped `\` is dropped or reinterpreted. Only when
184
- `typeof wix.multipart !== 'function'` is the body a string you build: parts named
185
- `files` with the path as `filename`, lines ending in `\r\n`, the body ending with
186
- `--<boundary>--`, and `Content-Type: multipart/form-data; boundary=<the same
187
- boundary>`.
241
+ ### Patch files
188
242
 
189
- ## 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:
245
+
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
+ ```
256
+
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
+ ```
190
266
 
191
- On the same `metaSiteId`, never a new site. Each drop replaces every file, and
192
- `siteUrl` stays.
193
-
194
- - **With a shell that reaches Wix**, edit the files and drop the full set with
195
- `curl`.
196
- - **Through the MCP**, by the kind of change:
197
- - **An edit to files the site serves** (a price, a line, a link): one
198
- `ExecuteWixAPI` script downloads what it serves, edits in code, and drops the
199
- full set back. Only the edit is written; images travel back as they are.
200
- - **New or rewritten files**: when your files travel as files, zip the whole
201
- site, images included, and send it through the upload tool. When they don't,
202
- the script carries them in its `files` param and adds them to the download
203
- before the drop.
204
- - **A site rewritten wholesale**: a full text bundle through the upload tool.
205
-
206
- For a site from an earlier conversation, find its `metaSiteId` with
207
- [Query Sites](#claim-it-into-the-users-account), matching the name or `viewUrl`.
208
- The download holds what the site serves plus a `wix.config.json`, which is left
209
- 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:
210
293
 
211
294
  ```bash
212
- curl -sSL -o current.zip \
295
+ curl -sSL -H "Authorization: Bearer $ACCESS_TOKEN" -o current.zip \
213
296
  "https://www.wix.com/_api/wixstro-deployments/v1/instant-sites/$META_SITE_ID/download.zip"
214
297
  ```
215
298
 
216
- In a script, request that URL with `responseType: 'base64'` and pass `r.data` to
217
- `wix.unzip()`. Each entry is `{ path, bytes, text() }`; call `text()` only on text
218
- files, since a decoded image is corrupted. Entries go back to `wix.multipart()` as
219
- 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:
220
303
 
221
304
  ```javascript
222
- const r = await wix.request({ scope: 'account', method: 'GET', responseType: 'base64',
223
- url: `https://www.wix.com/_api/wixstro-deployments/v1/instant-sites/${metaSiteId}/download.zip` });
224
- const entries = (await wix.unzip(r.data)).filter((e) => e.path !== 'wix.config.json').map((e) =>
225
- e.path === 'index.html' ? { path: e.path, content: e.text().replace('Welcome', 'Bloom Cafe — Now Open') } : e);
226
- const mp = wix.multipart(entries);
227
- // 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
+ }
228
322
  ```
229
323
 
230
- 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.
231
368
 
232
369
  ## Connect a backend
233
370
 
234
- A dropped site is static. Stores, payments, bookings, a CMS, members or forms
235
- need a **Wix Headless project**, which the headless skill builds and releases on
236
- the same site, appId and URL.
237
-
238
- **A mock that shows a business solution: publish it, then ask before connecting.**
239
- Any control on the page that promises what static files can't deliver —
240
- something to buy, book, order, join, submit or pay — is a Wix Business Solution
241
- the page pretends to have. First get the site live from the pages as they are.
242
- Then, with the live URL, name each such control, the solution that would make it
243
- work, and what connecting it involves: what gets created from the page's own
244
- content (the products, services or form). Ask whether to go ahead, and connect only after the user says
245
- yes; a request that already asks for it (a working shop, real bookings) is that
246
- yes. A page that promises nothing beyond its content stops at the pages.
247
-
248
- A site published anonymously is [claimed](#claim-it-into-the-users-account)
249
- before a backend: the headless skill works on a site in the user's account.
250
-
251
- The headless skill starts at its cold-start page,
252
- `https://www.wix.com/skills/headless-cold-start/headless-kit.md` (read it as
253
- [Before the calls](#before-the-calls) says). It installs the skills, runs a
254
- bootstrap that checks the Wix CLI login, and hands off to the kit's `SKILL.md`,
255
- which reads the folder, deploys the solution's code, seeds, builds and releases.
256
- Its commands run:
257
-
258
- - **With a shell that reaches Wix**, in a folder holding the site, from the
259
- site's own download:
260
-
261
- ```bash
262
- curl -sSL -o project.zip \
263
- "https://www.wix.com/_api/wixstro-deployments/v1/instant-sites/$META_SITE_ID/download.zip"
264
- unzip project.zip -d project
265
- ```
266
- - **Through the Wix MCP alone**, the kit's API-call guide,
267
- `https://www.wix.com/skills/wix-headless-kit/guides/api-run.md`, does the same
268
- run as Wix API calls through the Wix MCP, with the frontend dropped as this
269
- 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.
270
388
 
271
389
  ## Images
272
390
 
273
- An SVG is text and goes in like a page. Every other image is bytes, and bytes
274
- reach Wix one of these ways, in this order of preference:
275
-
276
- 1. **With a shell that reaches Wix**, in the `curl` drop, from disk.
277
- 2. **When your files travel as files**, inside the zip you pass the upload tool.
278
- 3. **A public URL**: the page keeps the absolute URL, or the Wix MCP's
279
- `UploadImageToWixSite` imports it into the site's media (`imageUrls`) and the
280
- page points at the returned `static.wixstatic.com` address. A share page
281
- (Dropbox, Drive) is not a file URL; a direct link is.
282
- 4. **`imageBase64` on `UploadImageToWixSite`**, when you can read the file and
283
- encode it yourself (a shell, a file API): one image per call, the raw base64
284
- with its `mimeType`. Encoding it from a file works; typing it out does not: a
285
- model cannot reproduce a long base64 string faithfully, so a string that was
286
- not produced by a tool comes back as an `atob` error or a corrupt image.
287
- Never put image bytes in the `files` bundle beyond a few KB (an icon).
288
- 5. **The user uploads it** to the site's Media Manager. This is the way for images
289
- that exist only as files you can't send. Publish the pages first, then name
290
- the missing files, give the user
291
- `https://manage.wix.com/dashboard/{metaSiteId}/media-manager`, and ask them to
292
- tell you once they're uploaded. Then [list the site's files](../media/upload-media-to-wix.md),
293
- match each to the page's reference by `displayName`, point the reference at the
294
- file's `static.wixstatic.com` URL, and drop again.
295
-
296
- `attachments` on a Wix MCP tool carries a file only from ChatGPT or Codex, which
297
- swap it for a download URL before the call reaches Wix. From any other client it
298
- arrives as the path you wrote, and Wix cannot read a path on your machine; the
299
- answer does not change on a retry. An image you could not send is named in the
300
- closing message. Never stand in drawings or placeholders of your own for the
301
- user's images, and never shrink or re-encode them.
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.
302
409
 
303
410
  ## Publish anonymously
304
411
 
305
- With a shell that reaches Wix and no login: the site belongs to a temporary owner and
306
- lives one hour unless the user keeps it. Generate `anonymousId` yourself, any
307
- UUID, once per site, and reuse it with the returned `metaSiteId` for every call.
308
- 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`.
309
415
 
310
416
  ```bash
311
- # 1. create
417
+ # 1. Create: returns { metaSiteId, projectId }
312
418
  curl -sS -X POST "https://www.wixapis.com/headless-business-setup/v1/headless-business/anonymous/$ANONYMOUS_ID"
313
- # {"metaSiteId":"f0ad8672-…","projectId":"54528d34-…"}
314
419
 
315
- # 2. upload: the drop's multipart shape; nothing is live yet
420
+ # 2. Upload the complete file set: returns { uploadId }; not live yet
316
421
  curl -sS -X POST \
317
422
  "https://www.wixapis.com/headless-business-setup/v1/headless-business/anonymous/$ANONYMOUS_ID/$META_SITE_ID/upload?campaign=mcp&agent=$AGENT" \
318
423
  -F "files=@index.html;filename=index.html" -F "files=@assets/styles.css;filename=assets/styles.css"
319
- # {"uploadId":"03244542-…"}
320
424
 
321
- # 3. release: the site goes live
425
+ # 3. Release: returns { siteUrl }
322
426
  curl -sS -X POST \
323
427
  "https://www.wixapis.com/headless-business-setup/v1/headless-business/anonymous/$ANONYMOUS_ID/$META_SITE_ID/release" \
324
428
  -H 'Content-Type: application/json' -d "{\"uploadId\":\"$UPLOAD_ID\"}"
325
- # {"siteUrl":"https://instant-hguwrvtcrniw-headlessstack-140d.wix-site-host.com"}
326
429
  ```
327
430
 
328
- To change the site, repeat steps 2 and 3 with the full file set. When it's final,
329
- claim it with the user's identity. Without one, give the user `siteUrl` and the
330
- save link, which signs them in to keep the site. Whoever opens the link while
331
- 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:
332
433
 
333
- ```
434
+ ```text
334
435
  https://www.wix.com/live-headless-site/{projectId}?anonymousId={anonymousId}
335
436
  ```
336
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
+
337
441
  ### Claim it into the user's account
338
442
 
339
443
  ```bash
@@ -342,67 +446,34 @@ curl -sS -X POST \
342
446
  -H "Authorization: Bearer $ACCESS_TOKEN"
343
447
  ```
344
448
 
345
- Claim last: it ends the anonymous record, and later changes are
346
- [drops](#change-it-later). **The URL changes on claim.** Read the new `viewUrl`
347
- with Query Sites in the `HEADLESS` namespace (the default query omits headless
348
- sites). An `id` filter takes the `$in` form; a bare `"id": "<uuid>"` is a `400`:
349
-
350
- ```bash
351
- curl -sS -X POST "https://www.wixapis.com/site-list/v2/sites/query" \
352
- -H "Authorization: Bearer $ACCESS_TOKEN" -H 'Content-Type: application/json' \
353
- -d '{"query":{"filter":{"namespace":"HEADLESS","id":{"$in":["'$META_SITE_ID'"]}},"cursorPaging":{"limit":10}}}'
354
- # sites[0].viewUrl is the live address; the same query without the id filter lists every
355
- # headless site with its viewUrl, which is how a site is found from a URL the user gives
356
- ```
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).
357
452
 
358
453
  ## The drop page
359
454
 
360
- ```
361
- https://www.wix.com/headless/drop?utm_campaign=mcp&agent=<your-agent-id>
362
- ```
455
+ `https://www.wix.com/headless/drop?utm_campaign=mcp&agent=<your-agent-id>`
363
456
 
364
- The user drags in the files without logging in, the site is live at once, and a
365
- banner offers to keep it. Tell them the limits below first.
366
-
367
- When no route reached Wix from where you are, say what would let you publish it
368
- yourself: a shell whose network reaches Wix, or the Wix MCP connected (the Wix
369
- 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.
370
461
 
371
462
  ## Limits and failures
372
463
 
373
- - **A top-level HTML file.** A lone one of any name is the homepage; with more
374
- than one, `index.html` must be among them.
375
- - **20 MB per file and per site.** The Wix MCP's upload tool takes 10 MB per call.
376
- - **Static files only** in a drop. A project that needs a build is built first,
377
- 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.
378
470
 
379
- | Failure | Meaning |
471
+ | Failure | Action |
380
472
  | --- | --- |
381
- | `400` `MISSING_INDEX_HTML`, `FILE_TOO_LARGE`, `TOTAL_TOO_LARGE` | In `details.applicationError.code`; fix the files. |
382
- | `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. |
383
- | `500` on a drop or upload | A failure on Wix's side, with a request id and no body. Retry once; if it fails again, keep the request id for feedback and hand over the drop page. A body built by hand (not `wix.multipart()`) can also answer `500`: rebuild it as shown. |
384
- | `404` on the anonymous route | The hour passed or the site was claimed. |
385
-
386
- ## Send feedback to Wix
387
-
388
- When this flow didn't work well enough, offer to send it to Wix as feedback,
389
- following [Send Feedback to Wix](send-feedback-to-wix.md): a route failed and you
390
- fell back, a call errored or needed retries, images had to wait on the user, or
391
- the recipe left you guessing and you had to invent a
392
- workaround.
393
-
394
- ## Route the request correctly
395
-
396
- - **A new site from files, the user's or ones you write**: [What decides the route](#what-decides-the-route).
397
- - **A change to a site published this way**: the [same site](#change-it-later);
398
- upload and release while it's anonymous.
399
- - **An anonymous site the user wants to keep**: [claim it](#claim-it-into-the-users-account), or the save link.
400
- - **A site that now needs a backend**: [Connect a backend](#connect-a-backend).
401
- - **Migrating a live site or store from another platform by URL, or CSV/TSV
402
- exports**: [Site Import](site-import.md).
403
- - **HTML, an embed or code inside an existing Wix site**: not this recipe; that is
404
- custom code in the editor.
405
- - **Images, videos or documents for a site's media**: [Upload Media to Wix](../media/upload-media-to-wix.md).
406
-
407
- Don't create the site from a template: that makes an empty site, not the site's
408
- 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.