Weaverse content api
Skill Weaverse/shopify-hydrogen-skills/skills/weaverse-content-api
Use when reading or updating live Weaverse content programmatically — pulling projects/pages/theme settings, bulk-editing page content, pushing AI-generated copy, deleting pages, or uploading media to Shopify for use in Weaverse. Triggers on requests to update a Weaverse project via API, push content to a live project, run bulk content edits, or upload images/assets to Shopify from automation.From its SKILL.md
npx -y skills add Weaverse/shopify-hydrogen-skills --skill weaverse-content-apiAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- no licenseNo license file was found in the repository. Code published without one is not open source by default, so using it at work is a question for whoever answers licensing questions where you are.
SKILL.md
11.3 KB, ~2.7k tokens by cl100k_base, as published. Nobody here has run it
Weaverse Content API
Read and edit live Weaverse content (projects, pages, theme settings, languages) outside the Studio editor, over an authenticated REST API. Use it for bulk edits, AI/automation content pipelines, and pushing updates into a project that already exists.
- Base URL:
https://studio.weaverse.io/api/v1/content - Machine spec:
GET https://studio.weaverse.io/api/v1/content/openapi.json(OpenAPI 3.1, no auth) — the authoritative contract - Full endpoint details:
references/endpoints.md. Rich-text/Portable Text details:references/portable-text.md. - Helper script:
scripts/weaverse_content_api.mjs(zero-dependency, Node 18+).
The one thing you must understand first
The Content API updates content — it does NOT create pages or projects.
PATCH .../pages/... shallow-merges data into items already on the page. Item ids that don't exist are reported as notFound and silently skipped — never created. There is no "create page" or "create project" endpoint.
So the lifecycle is:
Create initial structure → import a project JSON into Studio (use generating-weaverse-project-json)
Update content afterwards → Content API (this skill)
If you need to build a brand-new storefront, page, or section, this is the wrong tool — generate import JSON with generating-weaverse-project-json and import it once. Come back here for everything after that: editing copy, swapping images, localizing, bulk edits, deletes.
When to Use
- Push AI-generated or translated copy into an existing live project
- Bulk-edit content across many pages/items
- Read current page content/items to diff or round-trip
- Delete pages in bulk
- Upload an image/video to Shopify and reference its CDN URL in a Weaverse item
Do not use it to create pages, create projects, or add new sections/blocks to a page.
Authentication
Every endpoint except openapi.json needs a bearer token:
Authorization: Bearer <WEAVERSE_API_KEY>
- Get the key from Weaverse Dashboard → Account → Content APIs.
- A token is scoped to one shop. Requests for a project owned by another shop return
403 FORBIDDEN. - The same token also authorizes the Shopify proxy (see "Upload resources to Shopify").
- Store it in an env var (
WEAVERSE_API_KEY). Never hardcode it, never pass it as a?apiKey=query param outside local testing — query params leak into server/CDN logs.
Core update workflow
Updating content is always read ids first, then patch by id. You cannot patch blindly — you must target existing item ids.
- Find the project —
GET /projects, match by name, keep itsid. - Pick a locale —
GET /projects/:projectId/languages. Keep theisDefault: truecode (e.g.en-us). You need it for the next steps. - Read the page —
GET /projects/:projectId/pages/:type/*handle?locale=<code>. Always passlocale. With nolocalethe resolver only tries the empty locale and the legacy defaulten-us, so a market-first project or any project whose default locale isn'ten-usreturnsPAGE_NOT_FOUNDeven though the page exists. The defaultweaverseformat already returns every item with itsid— that id is exactly what the patch needs, so?meta=trueis not required (it only matters forportable-textreads). - Build the patch — for each item you want to change, send only the fields that change inside
data(it shallow-merges, so untouched fields stay). Include the samelocaleyou read with:{ "locale": "en-us", "items": [ { "id": "itm1", "data": { "heading": "New heading" } } ] } - Patch —
PATCH /projects/:projectId/pages/:type/*handle(usePOSTif your client/proxy can't send aPATCHbody). The page is resolved with the same locale rules as the read — a missing/wronglocalecan hitPAGE_NOT_FOUNDor patch the wrong locale's page. Max 100 items per request — chunk larger edits. - Check the response —
{ object: "page_update", updated, notFound, updatedIds, notFoundIds }. A non-emptynotFoundIdsmeans those ids aren't on the resolved page (wrong page, wrong locale, or stale ids) — re-read the page with the rightlocale, don't retry the same ids.
A successful patch invalidates caches and goes live through api.weaverse.io — the same path a Studio save takes.
Page addressing
Pages are addressed by Prisma page type + handle:
INDEX, PRODUCT, ALL_PRODUCTS, COLLECTION, COLLECTION_LIST, PAGE, BLOG,
ARTICLE, CART, CUSTOMER, NOT_FOUND, PASSWORD, SEARCH, CUSTOM
- Singletons (
INDEX,ALL_PRODUCTS,COLLECTION_LIST,CART,CUSTOMER,NOT_FOUND,PASSWORD,SEARCH) — one page per project, omit the handle. - CUSTOM — addressed by its path (the splat may contain slashes, e.g.
blogs/news). - Templated (
PRODUCT,COLLECTION,PAGE,BLOG,ARTICLE) — keep a shared default template at the empty handle, so a missing handle is rejected (it won't silently edit the template). Pass the real handle.
Locale always matters. On reads/updates, always pass a real locale code (from List languages). In list-pages responses, a row's locale may be null for market-first projects (rows are keyed by market, not locale) — don't echo null back; pass a real code and let resolution map it to the market (e.g. locale=en-us resolves market us).
See references/endpoints.md for the full endpoint list, query params, and response shapes.
Upload resources to Shopify
The Content API itself has no upload endpoint. To get media into a Weaverse item, upload it to Shopify first, then reference the returned CDN URL.
Upload goes through the Weaverse Shopify proxy, which accepts the same Weaverse token:
POST https://studio.weaverse.io/api/admin-graphql
Authorization: Bearer <WEAVERSE_API_KEY>
Content-Type: application/json
The body is a normal Shopify Admin GraphQL request ({ "query": "...", "variables": {...} }). Upload is the standard two-step Shopify flow:
stagedUploadsCreate→ get aurl+parameters(a presigned target) and aresourceUrl.- Upload the file bytes to that staged
urlwith the returnedparameters(multipart POST, not through the proxy). fileCreatewithoriginalSource: <resourceUrl>→ Shopify ingests it and returns the permanent CDN file.- Read back the file's
image.url/sourcesand put that CDN URL into the Weaverse itemdatavia the update workflow above.
Reference implementation in the builder repo: app/backend/admin/file.server.ts (generateStagedUploadLinks → stagedUploadsCreate, then fileCreate). When in doubt, mirror its mutations and field selections.
Alternatively, when a connected Shopify MCP is available, its image-upload /
graphql_mutationtools do the same job without the proxy. Use whichever is connected.
Helper script
scripts/weaverse_content_api.mjs wraps auth and the common calls. It reads WEAVERSE_API_KEY from the environment.
export WEAVERSE_API_KEY=...
node scripts/weaverse_content_api.mjs projects
node scripts/weaverse_content_api.mjs languages <projectId>
node scripts/weaverse_content_api.mjs theme <projectId>
node scripts/weaverse_content_api.mjs pages <projectId> [type]
node scripts/weaverse_content_api.mjs page <projectId> <type> [handle] [locale] # reads with ?locale
node scripts/weaverse_content_api.mjs update <projectId> <type> <handle> <patch.json>
node scripts/weaverse_content_api.mjs delete <projectId> <type> <handle...>
Use it to inspect a project quickly and to apply patch files. For anything the script doesn't cover, call the REST endpoints directly or read openapi.json.
Red Flags
- Trying to create a page/project/section via the API — it can't. Use
generating-weaverse-project-json+ import for new structure. - Patching without reading ids first — you must target existing item ids. Read the page first (with the right
locale); the defaultweaverseread already includes every itemid, so you do not need?meta=true. - Omitting
localeon a page read/update — with nolocalethe resolver only tries the empty locale and legacyen-us, so non-en-usor market-first projects returnPAGE_NOT_FOUNDeven when the page exists. Always pass a reallocalefrom List languages. - "My published edit is missing from the API" — silent wrong-locale page (not a 404). Content is stored per locale (
PageAssignmentkeyed byprojectId, locale, type, handle). When a merchant edits/publishes with a market locale selected (e.g.en-us), the change saves to theen-usassignment, not the base locale"". Becauselocaledefaults to"", a request like…/pages/PRODUCT/default(no?locale) can succeed (200) but return the base-locale assignment — a different, often empty/stale page — so the edit looks "missing" even though it published fine. This is distinct fromPAGE_NOT_FOUND: the request works, it just returns the wrong locale's page. Fix: always pass?locale=<market>(e.g.en-us). To find which locale a product/page uses: Studio top-bar template dropdown (shows active template + "Assigned to N products") with the market/locale selector beside it; orGET /pages(locale per row); or readdata-weaverse-template-idfrom the live storefront HTML. Verified live (PwC/Westside, projectlzum53gvsbhehjr3in906myu): edit lived onlocale=en-us(active, freshly published), baselocale=""was the stale one the no-locale call returned. - Echoing back
locale: null— list-pages rows can benullfor market-first projects. Don't sendnull; pass a real code and let resolution map it to the market. - Adding
?meta=truefor normal edits — it only affectsportable-textreads (where it restores_weaverse.id). On aweaverse-format read it changes nothing. - Ignoring
notFoundIdsin the response — it means your ids aren't on the resolved page (wrong page, wrong locale, or stale ids). Re-read with the right locale, don't retry. - Sending more than 100 items in one update (or 500 targets in one delete) — chunk the request.
- Editing a templated type with an empty handle — rejected by design. Pass the real handle.
- Hardcoding the token or using
?apiKey=— useAuthorization: Bearerfrom an env var. - Replacing whole
dataobjects — updates shallow-merge. Send only changed fields; don't resend the entiredataand risk wiping nested values you didn't read. - Putting a non-Shopify URL into a media field after "upload" — finish the
fileCreatestep and use the returned Shopify CDN URL, not the staged/temporaryresourceUrl.
Related skills
generating-weaverse-project-json— creates the import JSON that establishes the structure this API then updates. The item ids you patch here come from that JSON (or from a page read back with the rightlocale).cloning-websites-to-weaverse/figma-to-weaverse— produce the section plan that feeds the JSON generator.
What ships with it: 3 files
12.8 KB alongside SKILL.md, 1 of them executable
references/
- endpoints.md6.3 KB
- portable-text.md2.1 KB
scripts/
- weaverse_content_api.mjsruns4.5 KB