$npx -y skills add Weaverse/shopify-hydrogen-skills --skill weaverse-content-apiUse 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
| 1 | # Weaverse Content API |
| 2 | |
| 3 | 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. |
| 4 | |
| 5 | - **Base URL:** `https://studio.weaverse.io/api/v1/content` |
| 6 | - **Machine spec:** `GET https://studio.weaverse.io/api/v1/content/openapi.json` (OpenAPI 3.1, no auth) — the authoritative contract |
| 7 | - Full endpoint details: `references/endpoints.md`. Rich-text/Portable Text details: `references/portable-text.md`. |
| 8 | - Helper script: `scripts/weaverse_content_api.mjs` (zero-dependency, Node 18+). |
| 9 | |
| 10 | ## The one thing you must understand first |
| 11 | |
| 12 | **The Content API updates content — it does NOT create pages or projects.** |
| 13 | |
| 14 | `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. |
| 15 | |
| 16 | So the lifecycle is: |
| 17 | |
| 18 | ``` |
| 19 | Create initial structure → import a project JSON into Studio (use generating-weaverse-project-json) |
| 20 | Update content afterwards → Content API (this skill) |
| 21 | ``` |
| 22 | |
| 23 | 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. |
| 24 | |
| 25 | ## When to Use |
| 26 | |
| 27 | - Push AI-generated or translated copy into an existing live project |
| 28 | - Bulk-edit content across many pages/items |
| 29 | - Read current page content/items to diff or round-trip |
| 30 | - Delete pages in bulk |
| 31 | - Upload an image/video to Shopify and reference its CDN URL in a Weaverse item |
| 32 | |
| 33 | Do not use it to create pages, create projects, or add new sections/blocks to a page. |
| 34 | |
| 35 | ## Authentication |
| 36 | |
| 37 | Every endpoint except `openapi.json` needs a bearer token: |
| 38 | |
| 39 | ``` |
| 40 | Authorization: Bearer <WEAVERSE_API_KEY> |
| 41 | ``` |
| 42 | |
| 43 | - Get the key from **Weaverse Dashboard → Account → Content APIs**. |
| 44 | - A token is scoped to one shop. Requests for a project owned by another shop return `403 FORBIDDEN`. |
| 45 | - The same token also authorizes the Shopify proxy (see "Upload resources to Shopify"). |
| 46 | - 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. |
| 47 | |
| 48 | ## Core update workflow |
| 49 | |
| 50 | Updating content is always **read ids first, then patch by id**. You cannot patch blindly — you must target existing item ids. |
| 51 | |
| 52 | 1. **Find the project** — `GET /projects`, match by name, keep its `id`. |
| 53 | 2. **Pick a locale** — `GET /projects/:projectId/languages`. Keep the `isDefault: true` code (e.g. `en-us`). You need it for the next steps. |
| 54 | 3. **Read the page** — `GET /projects/:projectId/pages/:type/*handle?locale=<code>`. **Always pass `locale`.** With no `locale` the resolver only tries the empty locale and the legacy default `en-us`, so a market-first project or any project whose default locale isn't `en-us` returns `PAGE_NOT_FOUND` even though the page exists. The default `weaverse` format already returns **every item with its `id`** — that id is exactly what the patch needs, so **`?meta=true` is not required** (it only matters for `portable-text` reads). |
| 55 | 4. **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 **same `locale`** you read with: |
| 56 | ```json |
| 57 | { |
| 58 | "locale": "en-us", |
| 59 | "items": [ |
| 60 | { "id": "itm1", "data": { "heading": "New heading" } } |
| 61 | ] |
| 62 | } |
| 63 | ``` |
| 64 | 5. **Patch** — `PATCH /projects/:projectId/pages/:type/*handle` (use `POST` if your client/proxy can't send a `PATCH` body). The page is resolved with the **same locale rules as the read** — a missing/wrong `locale` can hit `PAGE_NOT_FOUND` or patch the wrong locale's page. Max **100 items per request** — chunk larger edits. |
| 65 | 6. **Check the response** — `{ object: "page_update", updated, notFound, updatedIds, notFoundIds }`. A non-empty `notFoundIds` means those ids aren't on the resolved page (wrong page, wrong locale, or stale ids) — re-read the page with the right `locale`, don't retry the same ids. |
| 66 | |
| 67 | A successful patch invalidates caches and goes live through `api.weaverse.io` — the same path a Studio save takes. |
| 68 | |
| 69 | ### Page addressing |
| 70 | |
| 71 | Pages are addressed by Prisma page type + handle: |
| 72 | |
| 73 | ``` |
| 74 | INDEX, PRODUCT, ALL_PRODUCTS, COLLECTION, COLLECTION_LIST, PAGE, BLOG, |
| 75 | ARTIC |