Skill 08 · Wix Headless Cold Start
Subchapter 8.1
headless-kit.mdMarkdown27 KBView on GitHub
This page tells you how to build the site, step by step. Read this page in full. Read each skill page that this page names in full. A fetch that makes a summary removes the calls. Do not use one.
The Wix plugin connects you to Wix. It has the Wix tools (the Wix MCP, signed in as the user) and the skills that this page names. You do not install anything.
WixREADME, ExecuteWixAPI, UploadHeadlessWebsiteFiles
and the documentation search tools, you have the plugin. These tools are signed in as the user.Steps 1 to 4 of the build are the same for every route. Step 5, the pages, has two routes: the
Astro build of wix-headless-kit, server-rendered pages from the shipped templates, and pages
written by hand on the modules. Decide the route now, before anything else, with two checks. The
checks are commands; their output decides, not what the environment says about its network.
The build check: wix-headless-kit runs on this machine. Run these in one shell call:
node -v
timeout 25 npm ping
ls {SKILL_ROOT}/install/setup.mjs 2>/dev/null || git clone --depth 1 https://github.com/wix/skills wix-skillsThe check passes when node -v prints 22.12 or higher (the requirement of Astro and of the hosting
adapter; this route does not run the Wix CLI), npm ping prints PONG, and setup.mjs is on the
disk, found in the plugin folder or cloned. timeout is a Linux command; elsewhere run npm ping
and give it 25 seconds. The clone brings the kit and the templates together; {SKILL_ROOT} is then
wix-skills/skills/wix-headless-kit. Without git, install the kit as “Where the skills are” says.
The upload check: a build can reach the upload tool. One of these must be true:
attachments as files. A client that shows attachments as a local path
replaces it with a download URL when the call is made. The description of attachments in the
upload tool names the clients that do this.curl -sI -m 25 https://s3.amazonaws.com. S3 answers with a status line and the header
x-amz-request-id. Use a timeout of 25 seconds or more. A proxy can rewrite the status and
drop the headers; when a status line
comes back without x-amz-request-id, the first upload call settles it: { siteId, prepare: true, size }
returns a URL, and curl -sI of that URL answers with x-amz-request-id.If both checks pass, make the pages with the Astro build of wix-headless-kit (“The Astro build”
below). If one fails, write the pages by hand on the modules (step 5 below).
Every call runs as the site owner through ExecuteWixAPI. This tool carries the login of the user.
Files go to the site through UploadHeadlessWebsiteFiles.
The reference for each step is the code of wix-headless-kit. Read it online with ReadFullDocsArticle from
https://www.wix.com/skills/{skill}/{path}. In this page:
{SKILL_ROOT} is wix-headless-kit{TEMPLATES} is headless-templates{MANAGE} is wix-manage{DOCS} is wix-docsA folder URL lists the files in the folder. For example,
https://www.wix.com/skills/headless-templates/blog/rest/ names the five files there. Read the
folder listing first. Then read the files by the names that the listing gives. Do not use a file
name that you supply yourself. The online copy is the current release. A copy that your client
serves, or that is on the disk, is the release it came with (“Where the skills are”). Read the
file. Then make the same calls that the file makes.
One file per script. A script that calls the docs tool calls it once and returns its text,
nothing else: a script that returns several files returns more than one result carries, and a
file loses lines. Every reference file fits in one result on its own. If a file arrives cut short,
or with a gap, read it again in parts until you have every line. An ExecuteWixAPI script can fetch() any
https://www.wix.com/skills/... URL and return the lines you name, for example
text.split("\n").slice(100, 220). Each part is one call of the size you choose. Return one file
per result.
The manifest of a skill, https://www.wix.com/skills/<skill>.manifest.json, gives the size of each
file. The _content URL of a folder returns all its files in one result. Use _content for a
folder under 30K bytes. For a bigger folder, read the files one by one.
A complete site has the whole solution: the apps installed (step 3), the content created (step 4), pages that read that content through the modules (step 5), and a visitor’s read that returns the content (the check in step 5). You can upload a first version before all of this is in place. Then tell the user what this version is: which pages read from the site, which pages are static, and which steps remain. Do this in every message that gives the user a link.
Do the six steps in this order. For each step: what you do, the call, and the reference.
Step 1: choose the solutions.
{solution} is the template
folder, for example storefront, bookings, blog.{SKILL_ROOT}/SKILL.md, section “Verticals”; {TEMPLATES}/{solution}/static.md.Step 2: create the site.
metaSiteId and the OAuth client appId.Step 3: install the other apps.
POST /apps-installer-service/v1/app-instance/install with
{ appInstance: { appDefId, enabled: true } } and scope: "site". You can repeat this call
safely.install…App function at the top of
{TEMPLATES}/{solution}/seed/seed-{solution}.mjs.
{MANAGE}/references/app-installation/install-wix-apps.md shows the same call for any app.Step 4: set the region, then create the content.
PATCH for a place. Then the calls of the seed script, in its order, with
its bodies, through ExecuteWixAPI with scope: "site" and siteId. Create. Do not delete.
Report what the site already had.seed-{solution}.mjs and the modules it imports from its folder;
{TEMPLATES}/{solution}/seed/SEED.md (the plan and its fields);
{TEMPLATES}/shared/seed/images.mjs (how to make an image and put its file id on the item);
{MANAGE}/references/site-properties/change-payment-currency-site-properties.md (currency, time
zone, region).Step 5: write the pages, upload them, install the modules.
client.ts, rest/*.ts
and the cores, already built). The pages use what the module functions return.
UploadHeadlessWebsiteFiles with the pages, then one ExecuteWixAPI call that copies the
modules into the site (“Step 5: the modules” below). The design of the pages is the design job
of the solution.{TEMPLATES}/{solution}/rest/ folder, its
listing first, then its files. The modules export the same functions. If a file imports a
function and exports it again, the function is written in the file it imports from.{TEMPLATES}/{solution}/app/wix/{solution}/types.ts.{TEMPLATES}/{solution}/static.md, the whole playbook for pages on the
modules in one file, with {TEMPLATES}/shared/DESIGN.md and {TEMPLATES}/shared/CONTENT.md.
For a call that these files do not cover: {DOCS}.Step 6: close.
appId for a later run.Send this body. Change only the name, the solutions and agent.
seedOptions is a list inside newMetasite. It has one entry per solution. Set businessSolution
to one of STORES, BLOG, BOOKINGS, EVENTS, PORTFOLIO, PRICING_PLANS. If the site needs
none of these, leave seedOptions out.
agent names what is building the site, three parts joined by /: the client product as its vendor
writes it, lowercase; the surface, one of chat, work, web, cli, desktop, ide, app; the
model as the client’s selector shows it. chatgpt/work/gpt-6.1, claude-code/cli/opus-5.5. A part
you cannot tell is unknown.
Caution: the call accepts any other shape, installs nothing, and gives no error.
async function run() {
return wix.request({ scope: 'account', method: 'POST',
url: 'https://www.wixapis.com/headless-business-setup/v1/headless-business/provision',
body: {
origin: 'agent',
agent: 'chatgpt/work/gpt-6.1',
newMetasite: {
namingStrategy: { metaSiteName: 'The Light Journal' },
seedOptions: [{ businessSolution: 'BLOG', clearTemplateContent: true, seedDemoContent: false }]
},
synchronousSteps: ['SET_METASITE_NAME', 'CONFIGURE_HEADLESS_APP']
}
});
}
// result.data: { metaSiteId, appId }The new site has a hosting address, and GetSiteContext shows it as “Published”. It serves nothing
until the upload in step 5: the address answers 404. Do not give the user a URL before step 6.
The provision call is the only call that creates a headless site. Do not use it on a site that
exists. First read the site. Its dynamic context names its apps: use GetSiteContext, or
POST /_api/dynamic-context/v1/dynamic-context/markdown with { siteId }. A site with no files also
shows a URL and “Published”; the URL answers 404 until the first upload. Then follow
{SKILL_ROOT}/guides/existing-site.md. Seed a site that exists only if the user asks for it.
Set the region settings first:
A new site starts with default settings. These are not the settings of the business. If you change a setting after you create the content, the change takes minutes to reach the content.
A new install finishes its provisioning in the background. Each seed script waits for what its app needs. Run its calls in its order, with its waits.
wix.request returns { status, data }. The response body is data. A write that succeeds does
not tell you the shape of a visitor’s read. A create body and a query response are different
objects. The shape of the read is in the *-core.ts file of the solution.
The pages read their content from the site. Do not write the content into the pages. The pages call
the modules of the solution and show what the modules return. Each field that a page shows (a name,
an amount, a date, a count, a body of text) is a field of a shape in the types.ts of the
solution. Do not show a field of a raw Wix response. Do not make a Wix call from a page. The
modules are the code of wix-headless-kit. Do not port the cores.
Do not repeat a value from the modules in the text around it (a price, a currency, a list of options). Show the field, or keep the text general. Then a change by the owner reaches every line. A field can be empty (an image, a description, a price on request). Design an empty state for it in each place where it appears.
A page that shows one item also takes its controls from the modules, not only its values. This is true for every type of item: a product, a service, a rental, an event, a plan, a campaign, a menu dish, a form, a post, a project, a collection item. Some controls depend on a setting of the item: a choice of amounts, a frequency, a goal, a date, a ticket type, a price, a custom field. Show such a control only if the modules return its setting. Decide this when the page loads, not when you write the page. Do not build the controls from the content that you made in step 4. The owner changes the settings in the dashboard, and the page follows on the next load.
The modules carry the data. The pages are the design job. static.md of the solution tells you
how to do it, with DESIGN.md and CONTENT.md.
If the pages show an item with a picture, put the picture on the item itself in step 4
({TEMPLATES}/shared/seed/images.mjs). Then the pages of Wix, for example checkout, show it too.
Put every other picture on a page (a hero, a banner) in the Wix Media of the site, in the same way.
Do not link to a picture on another website. If the user gave no pictures, you can suggest to
generate them. You can generate them yourself and upload them with UploadImageToWixSite. Or you
can use the image generation of Wix (generateImage in images.mjs).
The pages import the modules from the js/wix/ folder of the site. Use an absolute path. Then a
page in a subfolder imports the same files:
<script type="module">
import { … } from "/js/wix/<rest file>.js"; // e.g. /js/wix/posts.js
</script>Wix static hosting serves files. It does not serve a folder, and it does not serve the
index.html of a folder at the path of the folder. Make every page a file in the root, for
example shop.html and product.html, and link to the file: /shop.html, not /shop/ and not
/shop. A link to a folder gives the visitor a 404 page.
Each module file has the name of the rest/ file or store it was built from. It exports the same
functions. It starts with its declarations: what it exports, the arguments, and what each function
returns. The files of every solution on the site share the one folder. This is the layout that
INSTRUCTIONS.md of the solution describes for a static site.
Upload the pages first, with UploadHeadlessWebsiteFiles. Then make one ExecuteWixAPI call with
the siteId of the site. This call copies the modules of the solutions and the shared client into
the site, as the templates build them. It writes the appId of the site as the client id:
async function run() {
return wix.headless.modules.install({
siteId,
clientId: '<appId from step 2>',
solutions: ['blog'] // the template folders, as in step 1
});
}
// { entrypoints: ['/js/wix/client.js', '/js/wix/posts.js', …], files: { added, replaced, unchanged }, … }
// The modules carry data and state and render nothing. Every control on a page is yours to write on the
// stores; static.md of the solution shows how to drive them.The call keeps the pages. It returns the entry points and the file counts. The modules do not pass
through your reply. If wix.headless.modules is missing, use this script. It does the same steps:
async function run() {
const solutions = ['blog']; // the template folders, as in step 1
const appId = '<appId from step 2>';
const files = [];
for (const name of ['shared', ...solutions]) {
const res = await fetch('https://www.wix.com/skills/wix-headless-templates/static/' + name + '.json');
if (!res.ok) throw new Error('no modules for ' + name);
for (const [path, content] of Object.entries((await res.json()).files)) files.push({ path, content });
}
files.push({ path: 'js/wix/config.js', content: `export const WIX_CLIENT_ID = "${appId}";\n` });
const result = await wix.headless.files.patch({ siteId, files });
return { copied: files.length, result };
}The site is done when a visitor’s response shows the fields that the pages show. A successful
upload is not enough. Write one ExecuteWixAPI script that reads as a visitor:
client.ts does.fetch() and that token. Take the bodies from
the .ts file that holds each function.Caution: wix.request always sends the owner token. It does not matter which token you give
it. A check through wix.request reads what the owner sees, not what a visitor sees.
The check passes when the read returns the content that step 4 created, by name. An empty 200
response right after the seed can come from the new-install window, or from the query. Read again.
Then compare your query with the file of wix-headless-kit. Read the site files back with
wix.headless.files.list. The modules must be next to the pages.
A response has a size limit. Send pages as text one or two files per call. Add a later file through
“Change it later” in the upload recipe; it keeps the other files. If your client passes
attachments as files, send the pages as one zip attachment.
Use this route when the build check and the upload check pass. Steps 1 to 4 are the same calls.
Step 5 is different: you do not write the pages by hand, and its references, static.md and the
module install, belong to the hand-written route. The Astro project of wix-headless-kit is
composed from the shipped, verified templates, built, and released through
UploadHeadlessWebsiteFiles as a server-rendered site. Its source is stored in the Code Store
repository of the site. The shipped code is copied into the project, not written again from a
reference.
Do these steps:
wix-headless-kit is on the disk from the build check ({SKILL_ROOT}; “Where the skills are”).node {SKILL_ROOT}/install/setup.mjs --vertical {solution} --business-name … --site {metaSiteId} --app {appId}.
It places the project in the folder it runs in and names that folder in its last event. It
copies the solution’s project, writes the env file from the two ids and installs the
dependencies in the foreground; npm-install.log in the project holds the install’s output and
.install-exit its exit code. The install is done once: do not run npm ci or npm install
after setup. When .install-exit is not 0, read the log and run
node {SKILL_ROOT}/install/install.mjs in the project.INSTRUCTIONS.md of the solution, DESIGN.md
and CONTENT.md.npx astro build..wix/ and dist/ from the project root (zip -r, or zipfile in Python).UploadHeadlessWebsiteFiles: one call with the zip as an attachment where
the client passes attachments; through S3, the release is two calls:
{ siteId, prepare: true, size }, then the curl commands it returns, then the second call it
names.{SKILL_ROOT}/SKILL.md owns this run (publisher: plugin). install/context.mjs prints
publisher, npm and carrier.s3.
To change a site that was released as a build, continue from its Code Store repository
({SKILL_ROOT}/guides/existing-site.md). Do not upload hand-written pages over it.
There are four skills: wix-headless-kit, wix-headless-templates, wix-docs, wix-manage.
There are three ways to get them:
On the disk, from the plugin. A client with the Wix plugin has the skills in the plugin
folder. The skill tool names that folder when it loads a skill. The wix-headless-kit scripts run from there.
{SKILL_ROOT} is its wix-headless-kit folder. There is nothing to install. A chat client that
shows the skill text without a folder can read the skills, but cannot run them.
Installed on the disk. Use this on a machine with no plugin folder where wix-headless-kit must run
(the Astro build, the CLI route). A shallow clone of the repository brings every skill and the
templates:
git clone --depth 1 https://github.com/wix/skills wix-skills{SKILL_ROOT} is then wix-skills/skills/wix-headless-kit. Without git, the skills installer
does it; repeat --skill for each skill, and CI=1 keeps the output plain:
CI=1 npx skills@latest add wix/skills --skill wix-headless-kit --skill wix-docs --skill wix-manage --yesThe skills then go under .agents/skills/, and {SKILL_ROOT} is .agents/skills/wix-headless-kit.
Read online. Use https://www.wix.com/skills/<skill>/<path> (headless-templates for
wix-headless-templates), through ReadFullDocsArticle of the Wix MCP, or the fetch tool of
your client. A folder URL lists its files. Read the listing, then the files by the names it
gives. The _content URL of a folder returns its files in one response, for a folder under 30K
bytes (“How to read a reference file”). The same files are in https://github.com/wix/skills
under skills/<skill>/. This is the current release. node {SKILL_ROOT}/install/check.mjs tells
you if a disk copy is behind it.
The templates are not in the plugin folder. A clone of the repository has them beside the kit, and
the scripts use that copy. Otherwise each wix-headless-kit script downloads them on first use, as
a sparse clone of their folder. node {SKILL_ROOT}/install/templates.mjs downloads them alone.
Use this route on a machine with no Wix plugin or connector, where the Wix CLI runs and reaches Wix.
The CLI carries the login. wix create makes the site. wix release publishes the Astro build of
wix-headless-kit. If the machine has a Wix CLI session (~/.wix/auth/account.json, written by wix login),
use this route, even if other tools are on the machine.
The folder. Work from the folder that holds the project, or that will hold it. For a new build,
use an empty folder. If the current folder holds unrelated things, make a new folder named for the
business. For a project on the disk, use its root folder. Put the files from the brief into that
folder first: extract a zip there, or download a URL and extract it there. Then everything the
brief gives, a wix.config.json included, is at the root. Do not interpret what is in the folder.
The skill reads the folder and knows what it is.
Node. This route requires Node 24.18 or higher. Run node -v. If it fails, or prints a lower
version, install or upgrade Node first. Do not work around it. macOS: brew install node, or
nvm install 24 && nvm use 24. Linux: nvm install 24 && nvm use 24. Windows:
winget install OpenJS.NodeJS.LTS.
The skills. Install them as “Where the skills are” says. There is no plugin, so there is no plugin folder.
The login. Run the bootstrap script of the skill. It is a normal foreground command. It exits on
its own. It checks the Wix CLI and runs wix login (a device-code flow). It prints
one JSON event per line. Run it, and pass its events on to the user:
node .agents/skills/wix-headless-kit/install/bootstrap.mjsThe events, and what to do for each:
cli_ok: the Wix CLI is reachable. Continue.awaiting_user (with verificationUri, userCode, message): the script has exited. The next
step is for the user. Send them message as it is. The login continues on its own. When the user
says they have logged in, run the script again. It then reports logged_in.logged_in or success: the login is done. Continue.cli_unreachable or login_failed (with detail): show the user the detail. Do not make a
parallel setup by hand. The device-code login completes on a machine with a browser. In a sandbox
without a browser, it does not complete. Then use “The build, through the Wix tools” above, with
the plugin connected.Hand off. Open .agents/skills/wix-headless-kit/SKILL.md and follow it. It finds the stack and
the operation. It owns the whole build: scaffold, deploy the shipped code, seed, brand layer,
release. Do not scaffold, install apps, or seed by hand on this route. The skill does all of that.
For a request outside the shipped verticals, build from the Wix API reference through wix-docs, on
the same project. SKILL.md says how.