@wix/agent-skills 1.31.0 → 1.31.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (115) hide show
  1. package/package.json +1 -1
  2. package/skills/wix-app/SKILL.md +7 -8
  3. package/skills/wix-app/references/DASHBOARD_PAGE.md +1 -1
  4. package/skills/wix-app/references/STORES_VERSIONING.md +1 -1
  5. package/skills/wix-app/references/WIX_PATTERNS_DOCS.md +11 -50
  6. package/skills/wix-app/references/dashboard-page/DATA_SOURCES.md +14 -10
  7. package/skills/wix-app/references/dashboard-page/DRAFT_TEMPLATE.md +5 -8
  8. package/skills/wix-app/references/dashboard-page/TABLE_STATE.md +5 -4
  9. package/skills/wix-headless-kit/SKILL.md +31 -14
  10. package/skills/wix-headless-kit/guides/api-run.md +116 -31
  11. package/skills/wix-headless-kit/guides/existing-site.md +9 -2
  12. package/skills/wix-headless-kit/guides/reference-mode.md +9 -1
  13. package/skills/wix-headless-kit/install/AGENTS.md +10 -7
  14. package/skills/wix-headless-kit/install/attach.mjs +35 -30
  15. package/skills/wix-headless-kit/install/background.mjs +32 -0
  16. package/skills/wix-headless-kit/install/bootstrap.mjs +28 -11
  17. package/skills/wix-headless-kit/install/check.mjs +2 -2
  18. package/skills/wix-headless-kit/install/context.mjs +62 -8
  19. package/skills/wix-headless-kit/install/deploy.mjs +36 -11
  20. package/skills/wix-headless-kit/install/env-ignore.mjs +16 -0
  21. package/skills/wix-headless-kit/install/install.mjs +95 -0
  22. package/skills/wix-headless-kit/install/pins.json +1 -1
  23. package/skills/wix-headless-kit/install/proc.mjs +46 -0
  24. package/skills/wix-headless-kit/install/setup.mjs +18 -27
  25. package/skills/wix-headless-kit/install/templates.mjs +4 -3
  26. package/skills/wix-headless-templates/blog/app/components/blog/RichContent.tsx +3 -2
  27. package/skills/wix-headless-templates/blog/project/package-lock.json +1287 -1299
  28. package/skills/wix-headless-templates/blog/project/package.json +1 -1
  29. package/skills/wix-headless-templates/blog/project/src/components/blog/RichContent.tsx +3 -2
  30. package/skills/wix-headless-templates/blog/rest/authors.ts +5 -5
  31. package/skills/wix-headless-templates/blog/rest/comments.ts +4 -4
  32. package/skills/wix-headless-templates/blog/rest/post-likes.ts +3 -3
  33. package/skills/wix-headless-templates/blog/rest/posts.ts +4 -4
  34. package/skills/wix-headless-templates/blog/rest/taxonomy.ts +5 -5
  35. package/skills/wix-headless-templates/blog/seed/SEED.md +1 -1
  36. package/skills/wix-headless-templates/blog/seed/seed-blog.mjs +4 -3
  37. package/skills/wix-headless-templates/bookings/rest/booking.ts +4 -4
  38. package/skills/wix-headless-templates/bookings/rest/services.ts +4 -4
  39. package/skills/wix-headless-templates/bookings/seed/SEED.md +1 -1
  40. package/skills/wix-headless-templates/bookings/seed/seed-bookings.mjs +4 -2
  41. package/skills/wix-headless-templates/cms/rest/collections.ts +3 -3
  42. package/skills/wix-headless-templates/cms/rest/items.ts +4 -4
  43. package/skills/wix-headless-templates/cms/seed/seed-cms.mjs +2 -1
  44. package/skills/wix-headless-templates/donations/rest/campaigns.ts +4 -4
  45. package/skills/wix-headless-templates/donations/rest/donate.ts +3 -3
  46. package/skills/wix-headless-templates/donations/seed/SEED.md +1 -1
  47. package/skills/wix-headless-templates/donations/seed/seed-donations.mjs +5 -3
  48. package/skills/wix-headless-templates/events/rest/events.ts +4 -4
  49. package/skills/wix-headless-templates/events/rest/orders.ts +4 -4
  50. package/skills/wix-headless-templates/events/rest/registration.ts +4 -4
  51. package/skills/wix-headless-templates/events/seed/SEED.md +1 -1
  52. package/skills/wix-headless-templates/events/seed/seed-events.mjs +5 -3
  53. package/skills/wix-headless-templates/faq/rest/faq.ts +4 -4
  54. package/skills/wix-headless-templates/faq/seed/seed-faq.mjs +2 -1
  55. package/skills/wix-headless-templates/forms/rest/forms.ts +4 -4
  56. package/skills/wix-headless-templates/forms/rest/submissions.ts +4 -4
  57. package/skills/wix-headless-templates/forms/seed/seed-forms.mjs +2 -1
  58. package/skills/wix-headless-templates/members/rest/auth.ts +3 -3
  59. package/skills/wix-headless-templates/members/rest/members.ts +4 -4
  60. package/skills/wix-headless-templates/members/seed/seed-members.mjs +2 -1
  61. package/skills/wix-headless-templates/portfolio/rest/portfolio.ts +4 -4
  62. package/skills/wix-headless-templates/portfolio/seed/SEED.md +4 -2
  63. package/skills/wix-headless-templates/portfolio/seed/seed-portfolio.mjs +8 -7
  64. package/skills/wix-headless-templates/pricing-plans/rest/plan-access.ts +3 -3
  65. package/skills/wix-headless-templates/pricing-plans/rest/plans.ts +4 -4
  66. package/skills/wix-headless-templates/pricing-plans/rest/purchase.ts +3 -3
  67. package/skills/wix-headless-templates/pricing-plans/seed/seed-pricing-plans.mjs +2 -1
  68. package/skills/wix-headless-templates/rentals/rest/rentals.ts +4 -4
  69. package/skills/wix-headless-templates/rentals/seed/SEED.md +1 -1
  70. package/skills/wix-headless-templates/rentals/seed/seed-rentals.mjs +4 -2
  71. package/skills/wix-headless-templates/restaurants/rest/menu.ts +4 -4
  72. package/skills/wix-headless-templates/restaurants/rest/ordering.ts +5 -5
  73. package/skills/wix-headless-templates/restaurants/rest/reservations.ts +4 -4
  74. package/skills/wix-headless-templates/restaurants/seed/SEED.md +1 -1
  75. package/skills/wix-headless-templates/restaurants/seed/seed-restaurants.mjs +6 -4
  76. package/skills/wix-headless-templates/shared/capabilities/site-search/rest/search.ts +4 -4
  77. package/skills/wix-headless-templates/shared/capabilities/site-search/seed/install.mjs +6 -4
  78. package/skills/wix-headless-templates/shared/seed/images.mjs +41 -5
  79. package/skills/wix-headless-templates/shared/seed/main.mjs +15 -0
  80. package/skills/wix-headless-templates/shared/seed/wix-cli.mjs +43 -11
  81. package/skills/wix-headless-templates/storefront/INSTRUCTIONS.md +1 -1
  82. package/skills/wix-headless-templates/storefront/rest/cart.ts +5 -5
  83. package/skills/wix-headless-templates/storefront/rest/catalog.ts +5 -5
  84. package/skills/wix-headless-templates/storefront/seed/SEED.md +44 -14
  85. package/skills/wix-headless-templates/storefront/seed/seed-store.mjs +23 -15
  86. package/skills/wix-manage/SKILL.md +28 -18
  87. package/skills/wix-manage/references/app-installation/install-wix-apps.md +5 -1
  88. package/skills/wix-manage/references/app-installation/list-installed-apps.md +19 -9
  89. package/skills/wix-manage/references/automations/activation-status.md +52 -0
  90. package/skills/wix-manage/references/automations/api-catalog.md +81 -0
  91. package/skills/wix-manage/references/automations/build-and-manage-automations.md +34 -0
  92. package/skills/wix-manage/references/bookings/booking-service-policy-setup.md +3 -0
  93. package/skills/wix-manage/references/bookings/create-and-update-booking-services.md +277 -363
  94. package/skills/wix-manage/references/bookings/external-calendar-integration.md +3 -0
  95. package/skills/wix-manage/references/bookings/multi-resource-service-creation.md +3 -0
  96. package/skills/wix-manage/references/cms/cms-data-items-crud.md +11 -2
  97. package/skills/wix-manage/references/cms/cms-publishing-flow.md +63 -16
  98. package/skills/wix-manage/references/custom-apps/use-app-skills-and-app-tools.md +3 -1
  99. package/skills/wix-manage/references/forms/update-form.md +3 -0
  100. package/skills/wix-manage/references/pricing-plans/create-and-update-pricing-plans.md +3 -0
  101. package/skills/wix-manage/references/restaurants/wix-restaurants-setup.md +3 -0
  102. package/skills/wix-manage/references/sites/create-headless-site.md +7 -50
  103. package/skills/wix-manage/references/sites/manage-oauth-apps.md +4 -4
  104. package/skills/wix-manage/references/sites/read-site-context.md +4 -0
  105. package/skills/wix-manage/references/sites/send-feedback-to-wix.md +92 -0
  106. package/skills/wix-manage/references/sites/upload-static-site.md +298 -283
  107. package/skills/wix-manage/references/stores/add-store-pages-to-site.md +3 -0
  108. package/skills/wix-manage/references/stores/change-store-currency.md +3 -0
  109. package/skills/wix-manage/references/stores/create-product-catalog-v3.md +3 -0
  110. package/skills/wix-manage/references/stores/find-products-query-and-search-catalog-v3.md +3 -0
  111. package/skills/wix-manage/references/stores/update-product-with-options.md +192 -22
  112. package/skills/wix-manage/references/bookings/create-appointment-service.md +0 -243
  113. package/skills/wix-manage/references/bookings/create-booking-service-from-prompt.md +0 -31
  114. package/skills/wix-manage/references/bookings/create-class-service.md +0 -222
  115. package/skills/wix-manage/references/bookings/create-course-service.md +0 -251
@@ -1,291 +1,339 @@
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: 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.
4
4
  ---
5
5
 
6
6
  # Upload a Website or HTML Files
7
7
 
8
- The user has a finished website as files — hand-written HTML, a static build, a
9
- zip, or the output of an AI site builder — and wants it live on Wix as a static,
10
- Wix-hosted site.
11
-
12
- ## Choose the route
13
-
14
- Five ways to get the files live; what you have decides which are open to you.
15
-
16
- | Option | Needs | Carries | The user ends up with |
17
- | --- | --- | --- | --- |
18
- | **A.** `curl` + CLI token → [into the account](#publish-into-the-users-account) | A shell; a Wix CLI login | Anything on disk | A site in their account, final URL |
19
- | **B.** `ExecuteWixAPI` → [into the account](#publish-into-the-users-account) | The Wix MCP | Files already in the conversation — text as is, small binaries as base64 — and anything downloaded from the site | A site in their account, final URL |
20
- | **C.** `curl` → [anonymous](#publish-anonymously) | A shell | Anything on disk | A live site for one hour; kept by a [claim](#claim-it-into-the-users-account) (through the Wix MCP or a CLI token) or the save link |
21
- | **D.** [The drop page](#the-drop-page) | Nothing | Whatever the user uploads | The same, after they upload it themselves |
22
- | **E.** [The headless skill](#keep-building-add-a-backend-when-you-need-one) | A shell; Node; a Wix CLI login | A project folder, source included (built for you) | A site in their account as a Wix Headless project, released with the Wix CLI, ready for Wix Business Solutions |
23
-
24
- What sets them apart:
25
-
26
- - **`curl -F` streams files from disk** — the bytes never pass through you: any type, any
27
- number, up to the [limits](#what-the-upload-accepts-and-how-it-fails).
28
- - **`ExecuteWixAPI` has no filesystem.** The Wix MCP's tool runs JavaScript whose
29
- `wix.request` calls carry the user's login — no install, no token — but every
30
- byte is written out inside the call. That costs nothing extra for a page you
31
- generated or the user pasted (it's already in the conversation); for files on
32
- disk it means reading them in and writing them back out, and each change
33
- resends all of it. Files travel in the tool's `files` param — text raw, a
34
- binary file (PNG, JPG, fonts) as base64 — and `wix.multipart()` builds the
35
- upload body (below). Base64 costs about a third more than the file and every
36
- byte is tokens, so it suits small assets (an icon, a logo, a font) and files
37
- you downloaded from the site to change; a photo goes in by absolute URL
38
- (`<img src="https://…">`) or with `curl` from a shell. The bundle is capped at
39
- 4M characters.
40
- - **A CLI login** is one approval by the user in the browser: run
41
- `npx @wix/cli login` and have them approve; `npx @wix/cli token` then prints a
42
- token (see [Before the calls](#before-the-calls)). It also unlocks later
43
- changes from disk and
44
- [Keep building](#keep-building-add-a-backend-when-you-need-one).
45
- - **Anonymous** needs no identity, but the record expires after an hour and the
46
- URL changes on claim.
47
- - **The headless skill** is the heaviest — an install, a project, a build — and
48
- the only one that takes framework source as is and leaves a project ready for a
49
- backend. A drop site can still move to it [later](#keep-building-add-a-backend-when-you-need-one).
50
-
51
- So: a site already in the conversation — pages, styles, a logo — with the Wix
52
- MCP connected — B, shell or not. Static files on disk — A with a CLI login, else C (claimed through
53
- the Wix MCP when it's connected). A framework project (a `package.json`), or a
54
- site that needs stores, bookings, a CMS or members from the start — E. Files out
55
- of your reach, or nothing above fits — D.
56
-
57
- Publishing yourself beats the drop page whenever an option fits — the user gets a
58
- live site without uploading anything. Never report an upload you couldn't
59
- perform; whenever a route fails partway, hand over the drop page.
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. |
52
+
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.
60
58
 
61
59
  ## Before the calls
62
60
 
63
- The `curl` examples here and in the anonymous route read shell variables.
64
-
65
- - **`$ACCESS_TOKEN`** is the user's access token, from wherever you have it. A
66
- token from the Wix CLI (`npx @wix/cli token`) lasts 15 minutes; running the
67
- command again returns a valid one, refreshed if needed, so set `$ACCESS_TOKEN`
68
- again when it may have expired, and always after a `403`.
69
- - **`$META_SITE_ID`, `$UPLOAD_ID`, …** come from the previous response; set each
70
- one before the next call.
71
-
72
- In an `ExecuteWixAPI` script there is no token to handle, and the ids go into the
73
- URL as values; a `$NAME` there is sent as is.
74
-
75
- ## Publish into the user's account
76
-
77
- ### 1. Create the site
78
-
79
- The [Create Headless Site](create-headless-site.md) call with no Wix Business
80
- Solutions. Name it after the page's `<title>`, and keep `"origin": "drop"`: it marks
81
- the site as a dropped one, the same as the drop page and the anonymous route do.
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.
78
+
79
+ ## Create the site
80
+
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"`.
82
84
 
83
85
  ```bash
84
86
  curl -sS -X POST "https://www.wixapis.com/headless-business-setup/v1/headless-business/provision" \
85
87
  -H "Authorization: Bearer $ACCESS_TOKEN" -H 'Content-Type: application/json' \
86
88
  -d '{"origin":"drop","newMetasite":{"namingStrategy":{"metaSiteName":"Northwind Studio"},"seedOptions":[]},
87
89
  "synchronousSteps":["SET_METASITE_NAME","CONFIGURE_HEADLESS_APP"]}'
90
+ # {"metaSiteId":"7597a72e-bedc-4d86-af86-9a25d11f0632","appId":"9f0a8b59-1acb-4a67-aafd-f8602259cbfa"}
88
91
  ```
89
92
 
90
- ```json
91
- { "metaSiteId": "7597a72e-bedc-4d86-af86-9a25d11f0632", "appId": "9f0a8b59-1acb-4a67-aafd-f8602259cbfa" }
93
+ In a script, the same call:
94
+
95
+ ```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
92
101
  ```
93
102
 
94
- ### 2. Drop the files — the site goes live
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}`.
105
+
106
+ ## Drop with curl
95
107
 
96
108
  One multipart request uploads and releases. Each file is a part named `files`
97
- whose **filename is its path relative to the site root** — that is how
98
- subdirectories survive; with `curl`, set it with `;filename=` whenever it isn't
99
- just the basename. A single `.zip` part works too — it's unpacked server-side, a
100
- single wrapping folder stripped.
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.
101
112
 
102
113
  ```bash
103
114
  curl -sS -X POST \
104
- "https://www.wixapis.com/headless-business-setup/v1/headless-business/$META_SITE_ID/drop" \
115
+ "https://www.wixapis.com/headless-business-setup/v1/headless-business/$META_SITE_ID/drop?campaign=mcp&agent=$AGENT" \
105
116
  -H "Authorization: Bearer $ACCESS_TOKEN" \
106
117
  -F "files=@index.html;filename=index.html" \
107
118
  -F "files=@assets/styles.css;filename=assets/styles.css" \
108
119
  -F "files=@assets/logo.png;filename=assets/logo.png"
120
+ # {"uploadId":"c0d5b3bb-…","siteUrl":"https://headless-zjfqzddjtww-northwind-1406.wix-site-host.com"}
109
121
  ```
110
122
 
111
- ```json
112
- { "uploadId": "c0d5b3bb-60a9-43f9-9d27-7ca8df967825",
113
- "siteUrl": "https://headless-zjfqzddjtww-northwind-1406.wix-site-host.com" }
114
- ```
123
+ `siteUrl` is final.
124
+
125
+ ## Drop through the Wix MCP
115
126
 
116
- Option B — the same two calls as one `ExecuteWixAPI` script, for files already
117
- in the conversation. The files go in the tool's **`files` param**, not in
118
- `code`: one bundle, each file introduced by a line `=== FILE: <path> ===` and
119
- followed by its raw text, `<path>` relative to the site root. A binary file is
120
- introduced by `=== FILE: <path> base64 ===` and followed by its base64. Nothing
121
- in it is escaped, so quotes, backticks, `${}` and backslashes arrive as written.
127
+ ### With the Wix MCP's upload tool
128
+
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.
133
+
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.
122
143
 
123
144
  ```
124
145
  === FILE: index.html ===
125
146
  <!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.png"></body></html>
147
+ <link rel="stylesheet" href="assets/styles.css"></head><body><h1>Northwind Studio</h1><img src="assets/logo.svg"></body></html>
127
148
  === FILE: assets/styles.css ===
128
149
  body { font-family: sans-serif; margin: 0; padding: 4rem; }
129
- === FILE: assets/logo.png base64 ===
130
- iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNkYPhfDwAChwGA60e6kgAAAABJRU5ErkJggg==
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>
131
152
  ```
132
153
 
133
- In `code`, the bundle is the `files` global (`[{ path, content, encoding? }]`,
134
- `encoding: 'base64'` on the binary entries) and `wix.multipart()` turns it into
135
- the upload body: one part named `files` per file, the path as its filename, a
136
- content type guessed from the extension, base64 entries decoded to their bytes.
154
+ The bundle can't carry a file with a line that reads exactly `=== FILE: … ===`.
155
+
156
+ ### From an ExecuteWixAPI script
157
+
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.
137
161
 
138
162
  ```javascript
139
163
  async function run() {
164
+ const agent = 'your-agent-slug'; // $AGENT
140
165
  const created = await wix.request({ scope: 'account', method: 'POST',
141
166
  url: 'https://www.wixapis.com/headless-business-setup/v1/headless-business/provision',
142
167
  body: { origin: 'drop', newMetasite: { namingStrategy: { metaSiteName: 'Northwind Studio' }, seedOptions: [] },
143
168
  synchronousSteps: ['SET_METASITE_NAME', 'CONFIGURE_HEADLESS_APP'] } });
144
- const mp = wix.multipart(); // the `files` param; or pass [{ path, content | base64 | bytes }]
169
+ const mp = wix.multipart(); // from the `files` param; or pass [{ path, content | base64 | bytes }]
145
170
  return await wix.request({ scope: 'account', method: 'POST',
146
- url: `https://www.wixapis.com/headless-business-setup/v1/headless-business/${created.data.metaSiteId}/drop`,
147
- headers: { 'Content-Type': mp.contentType },
148
- body: mp.body });
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 });
149
173
  }
150
174
  ```
151
175
 
152
- `wix.request` returns `{ status, data }`; read a response's fields from `data`
153
- (`created.data.metaSiteId`). Don't build the multipart body by hand — a missing
154
- `\r\n` or a boundary mismatch is a bare `500` — and don't put file text inside
155
- `code` as string literals: that second layer of escaping is what corrupts
156
- backslashes and `${}`. Don't put image bytes in `code` either — they're a
157
- `base64` entry in `files`. The one thing `files` cannot carry is a file with a
158
- line that reads exactly `=== FILE: … ===`.
159
-
160
- `siteUrl` is the site's final address — it's already in the user's account. Give
161
- the user two links: `siteUrl`, and its dashboard at
162
- `https://manage.wix.com/dashboard/{metaSiteId}`.
163
-
164
- ### Change it later
165
-
166
- Re-run step 2 on the same `metaSiteId` with the **full** file set: each drop
167
- replaces the site's files (a file left out is gone), and `siteUrl` stays the same.
168
- Never create another site for a change. The same call updates any site the user
169
- owns that was published this way, including one claimed from an
170
- [anonymous publish](#publish-anonymously). For a site from an earlier conversation,
171
- find its `metaSiteId` with the [Query Sites](#claim-it-into-the-users-account) call
172
- below, matching the site's name or `viewUrl`.
173
-
174
- **When you no longer have the files** (a small change to a site from an earlier
175
- conversation), download what the site serves, edit it, and drop the full set
176
- back. Leave out `wix.config.json`; the download adds it, and it isn't part of the
177
- site.
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`).
179
+
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>`.
188
+
189
+ ## Change it later
190
+
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:
178
210
 
179
211
  ```bash
180
212
  curl -sSL -o current.zip \
181
213
  "https://www.wix.com/_api/wixstro-deployments/v1/instant-sites/$META_SITE_ID/download.zip"
182
- unzip -o current.zip -d current # the site's files + wix.config.json
183
214
  ```
184
215
 
185
- In an `ExecuteWixAPI` script, request the same URL with `responseType: 'base64'`
186
- and unzip it in memory with `wix.unzip()`. Each entry is `{ path, bytes, text() }`:
187
- `bytes` is the file as stored, `text()` decodes it when it's text. Don't decode
188
- every entry — an image run through a text decoder is corrupted.
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 }`:
189
220
 
190
221
  ```javascript
191
222
  const r = await wix.request({ scope: 'account', method: 'GET', responseType: 'base64',
192
223
  url: `https://www.wix.com/_api/wixstro-deployments/v1/instant-sites/${metaSiteId}/download.zip` });
193
- const entries = await wix.unzip(r.data);
194
- // entries: [{ path: 'index.html', bytes, text() }, { path: 'assets/logo.png', bytes, text() }, { path: 'wix.config.json', … }]
195
- ```
196
-
197
- Edit in memory — text through `text()`, binaries left as they are — then drop
198
- the full set back in the same script, leaving `wix.config.json` out. Entries go
199
- to `wix.multipart()` as they are; an edited file replaces its entry with
200
- `{ path, content }`:
201
-
202
- ```javascript
203
- const edited = entries.filter((e) => e.path !== 'wix.config.json').map((e) =>
204
- e.path === 'index.html' ? { path: e.path, content: e.text().replace('Northwind Studio', 'Northwind Studio — Est. 1998') } : e);
205
- const mp = wix.multipart(edited);
206
- await wix.request({ scope: 'account', method: 'POST', headers: { 'Content-Type': mp.contentType }, body: mp.body,
207
- url: `https://www.wixapis.com/headless-business-setup/v1/headless-business/${metaSiteId}/drop` });
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
208
228
  ```
209
229
 
210
- The live URL itself (`*.wix-site-host.com`) can't be read from a script; this
211
- download is the way back to the files. Don't rebuild the site from memory.
230
+ Never rebuild a site from memory.
231
+
232
+ ## Connect a backend
233
+
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.
270
+
271
+ ## Images
272
+
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.
212
302
 
213
303
  ## Publish anonymously
214
304
 
215
- No identity needed: the site is created under a temporary owner and lives for one
216
- hour unless the user keeps it.
217
-
218
- Generate `anonymousId` yourself — any UUID, **once per site, not once per
219
- request** — and reuse it, with the returned `metaSiteId`, for every call for that
220
- site. **Finish within one hour of step 1**: after that the record expires and
221
- every later call, claim included, returns `404`.
222
-
223
- ### 1. Create the site
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`.
224
309
 
225
310
  ```bash
226
- curl -sS -X POST \
227
- "https://www.wixapis.com/headless-business-setup/v1/headless-business/anonymous/$ANONYMOUS_ID"
228
- ```
229
-
230
- ```json
231
- { "metaSiteId": "f0ad8672-09e9-4111-b6fe-070c70bd2df5",
232
- "projectId": "54528d34-b23c-4fbe-b07d-2c522350abd7" }
233
- ```
234
-
235
- Keep both: `metaSiteId` addresses the site, `projectId` builds the save link.
311
+ # 1. create
312
+ curl -sS -X POST "https://www.wixapis.com/headless-business-setup/v1/headless-business/anonymous/$ANONYMOUS_ID"
313
+ # {"metaSiteId":"f0ad8672-…","projectId":"54528d34-…"}
236
314
 
237
- ### 2. Upload the files
238
-
239
- Same multipart shape as the [drop](#2-drop-the-files--the-site-goes-live), to the
240
- upload path, with the attribution parameters (in a script: `wix.multipart()` with
241
- the `files` param, posted to this URL):
242
-
243
- ```bash
315
+ # 2. upload: the drop's multipart shape; nothing is live yet
244
316
  curl -sS -X POST \
245
317
  "https://www.wixapis.com/headless-business-setup/v1/headless-business/anonymous/$ANONYMOUS_ID/$META_SITE_ID/upload?campaign=mcp&agent=$AGENT" \
246
- -F "files=@index.html;filename=index.html" \
247
- -F "files=@assets/styles.css;filename=assets/styles.css"
248
- ```
249
-
250
- ```json
251
- { "uploadId": "03244542-d820-42f6-acfa-166c6658b1a6" }
252
- ```
253
-
254
- Keep `campaign=mcp` (the referral tag — don't change it) and set `agent` to your
255
- own identifier: a short, stable, lowercase-hyphenated slug for the coding agent or
256
- tool you are (e.g. `claude-code`, `cursor`, `codex-cli`, `windsurf`,
257
- `github-copilot`, or your product's name; `unknown-agent` if you can't name
258
- yourself). Nothing is live yet; this only stages and validates.
259
-
260
- ### 3. Release — the site goes live
318
+ -F "files=@index.html;filename=index.html" -F "files=@assets/styles.css;filename=assets/styles.css"
319
+ # {"uploadId":"03244542-…"}
261
320
 
262
- ```bash
321
+ # 3. release: the site goes live
263
322
  curl -sS -X POST \
264
323
  "https://www.wixapis.com/headless-business-setup/v1/headless-business/anonymous/$ANONYMOUS_ID/$META_SITE_ID/release" \
265
324
  -H 'Content-Type: application/json' -d "{\"uploadId\":\"$UPLOAD_ID\"}"
325
+ # {"siteUrl":"https://instant-hguwrvtcrniw-headlessstack-140d.wix-site-host.com"}
266
326
  ```
267
327
 
268
- ```json
269
- { "siteUrl": "https://instant-hguwrvtcrniw-headlessstack-140d.wix-site-host.com" }
270
- ```
271
-
272
- **To change it**, re-run steps 2–3 with the same `anonymousId` and `metaSiteId` and
273
- the full file set; `siteUrl` stays the same. Never go back to step 1 for a change.
274
- Iterate first, claim last: after a claim, changes are a [drop](#change-it-later),
275
- which needs the user's identity — a CLI token for files on disk.
276
-
277
- **When it's final:** with the user's identity, [claim it](#claim-it-into-the-users-account).
278
- Without it, stop here — a finished result. Give the user `siteUrl` plus the save
279
- link, which is how the site survives:
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:
280
332
 
281
333
  ```
282
334
  https://www.wix.com/live-headless-site/{projectId}?anonymousId={anonymousId}
283
335
  ```
284
336
 
285
- That page shows the site with a countdown and signs the user in to keep it. Treat
286
- the link as a secret — whoever opens it while signed in to Wix claims the site
287
- into *their* account — so give it only to the user who asked.
288
-
289
337
  ### Claim it into the user's account
290
338
 
291
339
  ```bash
@@ -294,100 +342,67 @@ curl -sS -X POST \
294
342
  -H "Authorization: Bearer $ACCESS_TOKEN"
295
343
  ```
296
344
 
297
- Returns `{}`. Claim after the release, never before — it consumes the anonymous
298
- record, so the anonymous endpoints stop working for this site; later changes go
299
- through the [drop](#change-it-later).
300
-
301
- **The URL changes on claim**: the step-3 host stops resolving. Read the new one
302
- with [Query Sites](https://dev.wix.com/docs/api-reference/account-level/sites/sites/query-sites),
303
- filtered to the `HEADLESS` namespace (the default query omits headless sites, and
304
- an `id` filter is rejected, so match the id yourself):
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`:
305
349
 
306
350
  ```bash
307
351
  curl -sS -X POST "https://www.wixapis.com/site-list/v2/sites/query" \
308
352
  -H "Authorization: Bearer $ACCESS_TOKEN" -H 'Content-Type: application/json' \
309
- -d '{"query":{"filter":{"namespace":"HEADLESS"},"cursorPaging":{"limit":100}}}'
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
310
356
  ```
311
357
 
312
- Take `viewUrl` from the entry whose `id` is your `metaSiteId` (page with
313
- `metadata.cursors.next` if needed), and give the user it plus
314
- `https://manage.wix.com/dashboard/{metaSiteId}`.
315
-
316
358
  ## The drop page
317
359
 
318
360
  ```
319
361
  https://www.wix.com/headless/drop?utm_campaign=mcp&agent=<your-agent-id>
320
362
  ```
321
363
 
322
- Keep `utm_campaign=mcp` and set `agent` to your own identifier, as in the
323
- [upload](#2-upload-the-files). The user drags in their files (no login), Wix hosts
324
- them on a live URL at once, and a banner offers to sign in and keep the site. Tell
325
- them the [requirements](#what-the-upload-accepts-and-how-it-fails) so it doesn't
326
- fail on the first try.
327
-
328
- ## What the upload accepts, and how it fails
329
-
330
- These apply to every route:
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.
331
366
 
332
- - **A top-level HTML file is required.** A lone top-level HTML of any name becomes
333
- the homepage; with more than one, an `index.html` must be among them.
334
- - **3 MB per file, 20 MB per site.**
335
- - **Static files only** — HTML, CSS, JS, images, fonts. Framework source that
336
- needs a build step (a `package.json`, React/Vue sources) must be built first;
337
- upload the build output, or take the project to the headless skill (option E).
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).
338
370
 
339
- Failures come back as HTTP 400 with a code in `details.applicationError.code`:
340
- `MISSING_INDEX_HTML`, `FILE_TOO_LARGE`, `TOTAL_TOO_LARGE`. Beyond those:
371
+ ## Limits and failures
341
372
 
342
- - **`403 PERMISSION_DENIED` on a drop** — the token expired or is missing (see
343
- [Before the calls](#before-the-calls)), or the site isn't the caller's. A site
344
- that's still anonymous is changed by upload + release, not by a drop.
345
- - **`500` on a drop or upload** — the multipart body was built by hand and is malformed (see the shape
346
- above). Rebuild it from the example; sending it again unchanged fails the
347
- same way.
348
- - **`404` on the anonymous route after step 1** — the hour passed or the site was
349
- claimed; start again.
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.
350
378
 
351
- **If publishing fails for any reason you can't quickly fix, hand the user the
352
- [drop page](#the-drop-page).** Never leave them with a failed publish and no way
353
- forward.
379
+ | Failure | Meaning |
380
+ | --- | --- |
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. |
354
385
 
355
- ## Keep building: add a backend when you need one
356
-
357
- The headless skill, `https://wix.com/headless/skill.md`, builds and releases a
358
- **Wix Headless project** with the Wix CLI: it adopts a project folder (a
359
- `package.json`, or an `index.html` at its root) into a new site, or takes a
360
- dropped one. A dropped site is **static**; when it needs a real backend — stores,
361
- payments, bookings, a CMS, members, forms — it moves to a headless project,
362
- keeping the same site, appId and URL. This is a choice the user makes when the
363
- need appears; static changes never need it, they're a [drop](#change-it-later).
364
-
365
- To move a dropped site, in a shell, once it's in the user's account:
366
-
367
- ```bash
368
- curl -sSL -o project.zip \
369
- "https://www.wix.com/_api/wixstro-deployments/v1/instant-sites/$META_SITE_ID/download.zip"
370
- unzip project.zip -d project # the site's files + wix.config.json
371
- ```
386
+ ## Send feedback to Wix
372
387
 
373
- Then follow the headless skill from that folder: it turns the files into a
374
- headless project bound to the same site, released with the Wix CLI from then on.
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.
375
393
 
376
394
  ## Route the request correctly
377
395
 
378
- - **A new site from the user's files** — [Choose the route](#choose-the-route).
379
- - **A change to a site published this way** — the same site, full file set: a
380
- [drop](#change-it-later) when it's in the user's account, upload + release while
381
- it's anonymous.
382
- - **An anonymous site the user wants to keep** — [claim](#claim-it-into-the-users-account)
383
- it, else the save link.
384
- - **A site that now needs a backend** — [Keep building](#keep-building-add-a-backend-when-you-need-one).
385
- - **Migrating a live site/store from another platform by URL, or CSV/TSV
386
- exports** — [Site Import](site-import.md).
387
- - **Adding HTML, an embed, or code to an existing Wix site** — not this recipe
388
- (that's custom code in the editor).
389
- - **Images, videos, or documents for a site** —
390
- [Upload Media to Wix](../media/upload-media-to-wix.md).
391
-
392
- Don't create the site from a template — that makes an empty site, not a published
393
- copy of the user's files.
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.