Skill 16 · Wix Headless Templates
Subchapter 16.756
shared/CUSTOM_OPERATIONS.mdMarkdown5 KBView on GitHub
Shipped vertical code covers its advertised contract. A brief can also require an operation outside that contract: a member submission, a file derived in the browser, moderation, a custom business write, or a third-party service.
src/wix/<vertical>/src/pages/api/ endpoint.
Authenticate/authorize the caller and validate the exact input before elevating the one SDK
call with auth.elevate(). On another stack, the equivalent belongs on a server using
server-only credentials. Never expose an elevated method or credential to the browser.node_modules.Read the relevant shipped playbook first. For anything it doesn’t cover, use wix-docs to
read the official method or feature guide, then implement that contract. One documentation
lookup and one type check are enough before coding. Investigate further only after a concrete error.
Use the CMS vertical when a visitor or member submits content that the app must later list or show publicly. Seed the collection with the appropriate permission preset and never trust the browser to choose an owner, collection, or privileged action.
For a small browser-created artifact, the official Wix-managed Astro pattern is a validated server endpoint that writes the contribution with elevation. For binary media, first confirm the Media Files API’s authorization requirements: generating a media upload URL requires Manage Media Manager permission, so it is not a browser-side member call. Validate identity, MIME type, size, and destination before any elevated call. The authoritative references are:
wix-docs: Upload Images to CMS for the secure CMS contribution flow.wix-docs: Generate File Upload URL and Upload API for Media Manager files.Keep the endpoint specific to the allowed contribution. An endpoint that accepts arbitrary SDK method names, collection ids, or upload destinations is a privilege-escalation bug.
Use this only when a site actually needs a normal file upload (not a small canvas artifact stored as a CMS data URL). Put the policy in the site plan; the Fast deployer ships the shared client helper and Astro endpoint once, plus a generated read-only policy module:
{
"capabilities": {
"mediaUpload": {
"policies": [{
"id": "gallery-artwork",
"accept": ["image/png", "image/jpeg"],
"maxBytes": 5242880,
"audience": "members"
}]
}
}
}audience is who may use the policy: members (the default) admits a logged-in member only —
the endpoint reads the caller’s own session server-side and answers 401 to anyone else, before
anything is elevated; it needs the Wix Members Area app, which the members seed installs.
visitors admits anyone, and is only for a policy the product means for the public (a form’s
file field on a free site). The generated policy lives at src/wix/media-upload/policies.generated.ts; do not hand-edit
it. The shared browser helper is src/wix/media-upload/client.ts:
const media = await uploadMedia("gallery-artwork", pngBlob, "my-drawing.png");
// media.id and media.url are the Wix Media reference to store in the intended CMS image field.The browser can select only the named policy and the bytes. The deployed API route fixes
the destination and elevates only files.generateFileUploadUrl. A vertical uses the same
capability by putting its own policy in its plan. Do not copy, fork, or widen the endpoint in
vertical code.
A search box with suggestions and a /search?q= results page across the deployed verticals’
products, services, posts and events, linking to this site’s own routes. Put the entry in the site
plan; the Fast deployer ships the data layer, stores, hooks, components and the search page once,
plus a generated read-only config module:
{
"capabilities": {
"siteSearch": { "install": true, "types": ["products", "services", "posts", "events"] }
}
}Every call is a visitor read — no endpoint, no elevation. What it needs from the site is one
mutation the deploy does not make: the Wix Site Search app must be installed, or every search
answers zero documents. install: true marks that for the seed step, which runs
node <SKILL_ROOT>/templates/shared/capabilities/site-search/seed/install.mjs after the content
seed; the install indexes the existing content within about half a minute. The playbook, the plan
fields and the contracts are in templates/shared/capabilities/site-search/INSTRUCTIONS.md.