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