{
"object": "error",
"code": "STALE_PAGE",
"message": "The live page or project changed since it was read; nothing was saved — re-read and retry",
"status": 409
}
Drafts and publishing
Save a page draft
Saves a new draft head for the page from a full item list. Live content is never changed and no cache is invalidated. Publishing is a separate call that needs content:publish.
Workflow. Drafts and publishing work together like this:
GET /projects/{projectId}/page-drafts/{pageId} reads the editable content and its revision tokens.
PUT on the same path saves a new draft head (versionId). Live content is not touched.
Publish the draft with POST /publish-versions/{versionId}, or schedule it with POST /versions/{versionId}/schedule.
Manage history and the schedule with GET /projects/{projectId}/versions, /versions/{versionId} (read, reschedule, replace content, cancel), publish-now and restore.
Body
items: the complete item graph, 1 to 200 items. Each item needs id and type; children are { "id": ... } references and data is an object. Every child must reference an item in the list, ids must be unique, and every item must be reachable from the root. A malformed body is 400; a broken graph (duplicate ids, dangling child, orphaned items) is 404 PAGE_NOT_FOUND. Nothing is saved in either case.
The root is the item whose id matches the page’s current rootId; otherwise the first item.
name (optional): renames the draft. Defaults to the live page name.
Revision fence. All three tokens are required and must be copied exactly from the GET response:
expectedHeadVersionId: GET’s headVersionId (null means “no draft yet”).
expectedPageUpdatedAt: GET’s pageUpdatedAt, the exact ISO string or null.
expectedProjectUpdatedAt: GET’s projectUpdatedAt, the exact ISO string or null.
null is a real baseline for a legacy row and only matches a row that is still null. If the draft head, the live page or the project moved since your GET, the save is refused with 409 STALE_PAGE and nothing is written. Re-read with GET, reapply your edit and save again.
Retries. Retrying a save that already committed returns the same head instead of a conflict.
Response.versionId is the new draft head. Pass it to POST /publish-versions/{versionId} or POST /versions/{versionId}/schedule, and send it as expectedHeadVersionId on your next save or discard.
{
"object": "error",
"code": "STALE_PAGE",
"message": "The live page or project changed since it was read; nothing was saved — re-read and retry",
"status": 409
}
Bearer token: a shop API key (WEAVERSE_API_KEY), a scoped API key or a delegated MCP OAuth token; translation-unit routes also accept a project-bound translation agent token. Each operation lists the scope it requires; the scope table is in the API description.
GET pageUpdatedAt exactly as GET returned it (null = a legacy row with no revision). The save is refused with 409 STALE_PAGE when it no longer matches live.
GET projectUpdatedAt exactly as GET returned it (null = a legacy row with no revision). The save is refused with 409 STALE_PAGE when it no longer matches live.
{"docsConfig":{"theme":"mint","$schema":"https://mintlify.com/docs.json","name":"Weaverse","colors":{"primary":"#246aff","light":"#599aff","dark":"#1e40af"},"logo":{"light":"https://mintcdn.com/weaverse/UqDg35noNYU1xQJr/logo/light.svg?fit=max\u0026auto=format\u0026n=UqDg35noNYU1xQJr\u0026q=85\u0026s=03570de959edb471a7177f81be24d246","dark":"https://mintcdn.com/weaverse/UqDg35noNYU1xQJr/logo/dark.svg?fit=max\u0026auto=format\u0026n=UqDg35noNYU1xQJr\u0026q=85\u0026s=37c6ba54acdc2f2fec124b27d05ac379","href":"https://weaverse.io"},"favicon":"https://mintcdn.com/weaverse/EOrmVdYBR-QCAvXJ/favicon.ico?fit=max\u0026auto=format\u0026n=EOrmVdYBR-QCAvXJ\u0026q=85\u0026s=fee3d7a85f68c8b9e62d849017c3c087","api":{"playground":{"display":"interactive"},"examples":{"defaults":"required","languages":["curl","javascript","python"]}},"navbar":{"links":[{"href":"https://weaverse.io","label":"Weaverse.io"},{"href":"https://github.com/weaverse","label":"GitHub"},{"href":"https://wvse.cc/weaverse-slack","label":"Community"}],"primary":{"type":"button","label":"Studio","href":"https://studio.weaverse.io/dashboard"}},"footer":{"socials":{"x":"https://x.com/WeaverseIO","github":"https://github.com/weaverse","slack":"https://wvse.cc/weaverse-slack"}},"seo":{"metatags":{"og:site_name":"Weaverse Docs","twitter:site":"@WeaverseIO","keywords":"Weaverse, Shopify Hydrogen, headless commerce, visual page builder, React Router, Next.js"},"organization":{"name":"Weaverse","url":"https://weaverse.io","logo":"https://docs.weaverse.io/logo/light.svg","sameAs":["https://github.com/weaverse","https://x.com/WeaverseIO","https://wvse.cc/weaverse-slack"]}},"integrations":{"posthog":{"apiKey":"phc_BnZAhY8ELZCZukEErb6ab9T7txSsMolcgGIIhMj5oSP","apiHost":"https://posthog.weaverse.io"}},"contextual":{"options":["copy","view","chatgpt","claude","perplexity","mcp","add-mcp","download-spec","cursor","vscode"],"display":"header"},"thumbnails":{"preset":"headline","appearance":"dark"},"metadata":{"timestamp":true},"markdown":{"instructions":["Weaverse component configuration uses `settings`. `inspector` is deprecated; never generate it.","Weaverse Hydrogen themes use React Router v7: import from `react-router`, never `react-router-dom` or `@remix-run/*`.","The current SDK is `@weaverse/hydrogen` 6 for Shopify Hydrogen 2026.10 and later. React Router themes import from `@weaverse/hydrogen/react-router`; the root `@weaverse/hydrogen` entry only exports `createSchema()`, data helpers and types.","Some examples still show 5.x imports and type names. In 6.x, `HydrogenComponentProps` is `WeaverseComponentProps` and `HydrogenComponentSchema` is `WeaverseComponentSchema`; run `npx @weaverse/cli@latest migrate v6` to convert code. Projects on Hydrogen 2026.4 or earlier stay on 5.x. Do not mix major versions.","Next.js themes use `@weaverse/next` 1.x.","For live project data (pages, theme settings, translations), use the Weaverse MCP server: https://weaverse.io/docs/developer-tools/weaverse-mcp"]},"styling":{"latex":false},"navigation":{"pages":[]}},"deployment":{"deploymentMetadataValue":{"subdomain":"weaverse","hasAudioNarration":false,"actualSubdomain":"weaverse","customDomains":["weaverse.io"],"gitSource":{"type":"github","owner":"weaverse","repo":"docs","deployBranch":"main","contentDirectory":"","isPrivate":true,"mountPath":"","label":""},"feedback":{"thumbs":true},"entitlements":{},"buildId":"6af195982da007b7b71ce667","clientVersion":"0.0.4088","searchFilterCounts":[{"language":"default","tag":"Content API","count":54},{"language":"default","tag":"React Router","count":43},{"language":"default","tag":"Guides","count":42},{"language":"default","tag":"Ecosystem","count":22},{"language":"default","tag":"Next.js","count":21},{"language":"default","tag":"SDKs","count":18},{"language":"default","tag":"Drafts and publishing","count":12},{"language":"default","tag":"Hooks","count":10},{"language":"default","tag":"Help \u0026 Community","count":10},{"language":"default","tag":"Building Components","count":7}]},"assistantConfig":{},"basePath":"/docs","hasChatPermissions":false,"hasWebMcpPermissions":false,"toggles":[{"name":"kill-isr","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-mintlify-slack","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"agent-integrations-settings","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"rbac-expansion","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-pr-grouping","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"custom-prefix","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"analytics-v7","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"user-flows-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"no-publish-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-onboarding","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"llms-txt-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving-live","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"stripTemperatureMiddleware","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"support-platform-pylon-zendesk","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"snapshot-serving","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"instant-rollback","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications-server","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"granular-notifications","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automations-fable","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fixed-ai-action-pricing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"automation-resolve-merge-conflict","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"scoped-publishing","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"mintql","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"page-level-analytics","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-version-history-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"billing-page-v2","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"full-page-search","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workspace-projects","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"assistant-v5","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"fork-pr-previews","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"revalidation-jwt","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-sso-scim","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"hobby-abuse-scan","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"dashboard-inbox","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-signup","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-dual-write","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"workos-enabled","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"approve-review-flow","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"editor-metadata","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"sso-setup-deadline-banner","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"turbopuffer-serve","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"live-agents","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false},{"name":"comment-mode","enabled":true,"variant":{"name":"disabled","enabled":false,"feature_enabled":true},"impressionData":false}],"googleFontsInlined":false},"customCss":[],"page":{"pagePath":"content-api/drafts-and-publishing/save-a-page-draft","slug":"/content-api/drafts-and-publishing/save-a-page-draft","pageMetadata":{"title":"Save a page draft","description":"Saves a new draft head for the page from a full item list. Live content is never changed and no cache is invalidated. Publishing is a separate call that needs `content:publish`.\n\n**Workflow.** Drafts and publishing work together like this:\n\n1. `GET /projects/{projectId}/page-drafts/{pageId}` reads the editable content and its revision tokens.\n2. `PUT` on the same path saves a new draft head (`versionId`). Live content is not touched.\n3. Publish the draft with `POST /publish-versions/{versionId}`, or schedule it with `POST /versions/{versionId}/schedule`.\n4. Manage history and the schedule with `GET /projects/{projectId}/versions`, `/versions/{versionId}` (read, reschedule, replace content, cancel), `publish-now` and `restore`.\n\n**Body**\n\n- `items`: the complete item graph, 1 to 200 items. Each item needs `id` and `type`; `children` are `{ \"id\": ... }` references and `data` is an object. Every child must reference an item in the list, ids must be unique, and every item must be reachable from the root. A malformed body is 400; a broken graph (duplicate ids, dangling child, orphaned items) is 404 `PAGE_NOT_FOUND`. Nothing is saved in either case.\n- The root is the item whose id matches the page's current `rootId`; otherwise the first item.\n- `name` (optional): renames the draft. Defaults to the live page name.\n\n**Revision fence.** All three tokens are required and must be copied exactly from the GET response:\n\n- `expectedHeadVersionId`: GET's `headVersionId` (`null` means \"no draft yet\").\n- `expectedPageUpdatedAt`: GET's `pageUpdatedAt`, the exact ISO string or `null`.\n- `expectedProjectUpdatedAt`: GET's `projectUpdatedAt`, the exact ISO string or `null`.\n\n`null` is a real baseline for a legacy row and only matches a row that is still `null`. If the draft head, the live page or the project moved since your GET, the save is refused with 409 `STALE_PAGE` and nothing is written. Re-read with GET, reapply your edit and save again.\n\n**Retries.** Retrying a save that already committed returns the same head instead of a conflict.\n\n**Response.** `versionId` is the new draft head. Pass it to `POST /publish-versions/{versionId}` or `POST /versions/{versionId}/schedule`, and send it as `expectedHeadVersionId` on your next save or discard.\n\nRequired scope: `content:write`","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json put /projects/{projectId}/page-drafts/{pageId}","href":"/content-api/drafts-and-publishing/save-a-page-draft","autogeneratedByOpenApi":true},"description":{"compiledSource":"\"use strict\";\nconst {Fragment: _Fragment, jsx: _jsx, jsxs: _jsxs} = arguments[0];\nconst {useMDXComponents: _provideComponents} = arguments[0];\nfunction _createMdxContent(props) {\n const _components = {\n code: \"code\",\n li: \"li\",\n ol: \"ol\",\n p: \"p\",\n strong: \"strong\",\n ul: \"ul\",\n ..._provideComponents(),\n ...props.components\n };\n return _jsxs(_Fragment, {\n children: [_jsxs(_components.p, {\n children: [\"Saves a new draft head for the page from a full item list. Live content is never changed and no cache is invalidated. Publishing is a separate call that needs \", _jsx(_components.code, {\n children: \"content:publish\"\n }), \".\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.strong, {\n children: \"Workflow.\"\n }), \" Drafts and publishing work together like this:\"]\n }), \"\\n\", _jsxs(_components.ol, {\n children: [\"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"GET /projects/{projectId}/page-drafts/{pageId}\"\n }), \" reads the editable content and its revision tokens.\"]\n }), \"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"PUT\"\n }), \" on the same path saves a new draft head (\", _jsx(_components.code, {\n children: \"versionId\"\n }), \"). Live content is not touched.\"]\n }), \"\\n\", _jsxs(_components.li, {\n children: [\"Publish the draft with \", _jsx(_components.code, {\n children: \"POST /publish-versions/{versionId}\"\n }), \", or schedule it with \", _jsx(_components.code, {\n children: \"POST /versions/{versionId}/schedule\"\n }), \".\"]\n }), \"\\n\", _jsxs(_components.li, {\n children: [\"Manage history and the schedule with \", _jsx(_components.code, {\n children: \"GET /projects/{projectId}/versions\"\n }), \", \", _jsx(_components.code, {\n children: \"/versions/{versionId}\"\n }), \" (read, reschedule, replace content, cancel), \", _jsx(_components.code, {\n children: \"publish-now\"\n }), \" and \", _jsx(_components.code, {\n children: \"restore\"\n }), \".\"]\n }), \"\\n\"]\n }), \"\\n\", _jsx(_components.p, {\n children: _jsx(_components.strong, {\n children: \"Body\"\n })\n }), \"\\n\", _jsxs(_components.ul, {\n children: [\"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"items\"\n }), \": the complete item graph, 1 to 200 items. Each item needs \", _jsx(_components.code, {\n children: \"id\"\n }), \" and \", _jsx(_components.code, {\n children: \"type\"\n }), \"; \", _jsx(_components.code, {\n children: \"children\"\n }), \" are \", _jsx(_components.code, {\n children: \"{ \\\"id\\\": ... }\"\n }), \" references and \", _jsx(_components.code, {\n children: \"data\"\n }), \" is an object. Every child must reference an item in the list, ids must be unique, and every item must be reachable from the root. A malformed body is 400; a broken graph (duplicate ids, dangling child, orphaned items) is 404 \", _jsx(_components.code, {\n children: \"PAGE_NOT_FOUND\"\n }), \". Nothing is saved in either case.\"]\n }), \"\\n\", _jsxs(_components.li, {\n children: [\"The root is the item whose id matches the page’s current \", _jsx(_components.code, {\n children: \"rootId\"\n }), \"; otherwise the first item.\"]\n }), \"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"name\"\n }), \" (optional): renames the draft. Defaults to the live page name.\"]\n }), \"\\n\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.strong, {\n children: \"Revision fence.\"\n }), \" All three tokens are required and must be copied exactly from the GET response:\"]\n }), \"\\n\", _jsxs(_components.ul, {\n children: [\"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"expectedHeadVersionId\"\n }), \": GET’s \", _jsx(_components.code, {\n children: \"headVersionId\"\n }), \" (\", _jsx(_components.code, {\n children: \"null\"\n }), \" means “no draft yet”).\"]\n }), \"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"expectedPageUpdatedAt\"\n }), \": GET’s \", _jsx(_components.code, {\n children: \"pageUpdatedAt\"\n }), \", the exact ISO string or \", _jsx(_components.code, {\n children: \"null\"\n }), \".\"]\n }), \"\\n\", _jsxs(_components.li, {\n children: [_jsx(_components.code, {\n children: \"expectedProjectUpdatedAt\"\n }), \": GET’s \", _jsx(_components.code, {\n children: \"projectUpdatedAt\"\n }), \", the exact ISO string or \", _jsx(_components.code, {\n children: \"null\"\n }), \".\"]\n }), \"\\n\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.code, {\n children: \"null\"\n }), \" is a real baseline for a legacy row and only matches a row that is still \", _jsx(_components.code, {\n children: \"null\"\n }), \". If the draft head, the live page or the project moved since your GET, the save is refused with 409 \", _jsx(_components.code, {\n children: \"STALE_PAGE\"\n }), \" and nothing is written. Re-read with GET, reapply your edit and save again.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.strong, {\n children: \"Retries.\"\n }), \" Retrying a save that already committed returns the same head instead of a conflict.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [_jsx(_components.strong, {\n children: \"Response.\"\n }), \" \", _jsx(_components.code, {\n children: \"versionId\"\n }), \" is the new draft head. Pass it to \", _jsx(_components.code, {\n children: \"POST /publish-versions/{versionId}\"\n }), \" or \", _jsx(_components.code, {\n children: \"POST /versions/{versionId}/schedule\"\n }), \", and send it as \", _jsx(_components.code, {\n children: \"expectedHeadVersionId\"\n }), \" on your next save or discard.\"]\n }), \"\\n\", _jsxs(_components.p, {\n children: [\"Required scope: \", _jsx(_components.code, {\n children: \"content:write\"\n })]\n })]\n });\n}\nfunction MDXContent(props = {}) {\n const {wrapper: MDXLayout} = {\n ..._provideComponents(),\n ...props.components\n };\n return MDXLayout ? _jsx(MDXLayout, {\n ...props,\n children: _jsx(_createMdxContent, {\n ...props\n })\n }) : _createMdxContent(props);\n}\nreturn {\n default: MDXContent\n};\n","frontmatter":{},"scope":{}},"pageType":"default","mdx":{"mdxSource":{"compiledSource":"\"use strict\";const{Fragment:_Fragment,jsx:_jsx}=arguments[0];const{useMDXComponents:_provideComponents}=arguments[0];function _createMdxContent(props){return _jsx(_Fragment,{})}function MDXContent(props={}){const{wrapper:MDXLayout}={..._provideComponents(),...props.components};return MDXLayout?_jsx(MDXLayout,{...props,children:_jsx(_createMdxContent,{...props})}):_createMdxContent(props)}return{default:MDXContent}","frontmatter":{},"scope":{"config":{},"pageMetadata":{"title":"Save a page draft","description":"Saves a new draft head for the page from a full item list. Live content is never changed and no cache is invalidated. Publishing is a separate call that needs `content:publish`.\n\n**Workflow.** Drafts and publishing work together like this:\n\n1. `GET /projects/{projectId}/page-drafts/{pageId}` reads the editable content and its revision tokens.\n2. `PUT` on the same path saves a new draft head (`versionId`). Live content is not touched.\n3. Publish the draft with `POST /publish-versions/{versionId}`, or schedule it with `POST /versions/{versionId}/schedule`.\n4. Manage history and the schedule with `GET /projects/{projectId}/versions`, `/versions/{versionId}` (read, reschedule, replace content, cancel), `publish-now` and `restore`.\n\n**Body**\n\n- `items`: the complete item graph, 1 to 200 items. Each item needs `id` and `type`; `children` are `{ \"id\": ... }` references and `data` is an object. Every child must reference an item in the list, ids must be unique, and every item must be reachable from the root. A malformed body is 400; a broken graph (duplicate ids, dangling child, orphaned items) is 404 `PAGE_NOT_FOUND`. Nothing is saved in either case.\n- The root is the item whose id matches the page's current `rootId`; otherwise the first item.\n- `name` (optional): renames the draft. Defaults to the live page name.\n\n**Revision fence.** All three tokens are required and must be copied exactly from the GET response:\n\n- `expectedHeadVersionId`: GET's `headVersionId` (`null` means \"no draft yet\").\n- `expectedPageUpdatedAt`: GET's `pageUpdatedAt`, the exact ISO string or `null`.\n- `expectedProjectUpdatedAt`: GET's `projectUpdatedAt`, the exact ISO string or `null`.\n\n`null` is a real baseline for a legacy row and only matches a row that is still `null`. If the draft head, the live page or the project moved since your GET, the save is refused with 409 `STALE_PAGE` and nothing is written. Re-read with GET, reapply your edit and save again.\n\n**Retries.** Retrying a save that already committed returns the same head instead of a conflict.\n\n**Response.** `versionId` is the new draft head. Pass it to `POST /publish-versions/{versionId}` or `POST /versions/{versionId}/schedule`, and send it as `expectedHeadVersionId` on your next save or discard.\n\nRequired scope: `content:write`","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json put /projects/{projectId}/page-drafts/{pageId}","href":"/content-api/drafts-and-publishing/save-a-page-draft","autogeneratedByOpenApi":true}}},"mdxSourceWithNoJs":null},"mdxExtracts":{"tableOfContents":[],"codeExamples":{}},"jsLinks":["/docs/_mintlify/custom/weaverse/0543a9a70b6f3643/snitcher.js","/docs/_mintlify/custom/weaverse/20987ec1c9b2ceb6/same-tab-nav.js"],"openApiReferenceData":{"operation":{"operationId":"savePageDraft","summary":"Save a page draft","requestBody":"d26ebb90-83d8-4cf4-b2c9-6eab8441f2b0","responses":{"200":"ba7d137e-91ae-4638-a8d9-823dd0403eef","401":"8e1b2972-e3bf-4e6f-99c7-04ebfa672823","403":"25f39021-9617-4eb0-b9fb-7a94d106efaa","404":"4f302fd7-f326-412e-82c9-35362bfd4e47","409":"9acebd1c-ca2e-4631-8704-125c445672a9"},"tags":["Drafts and publishing"],"description":"Saves a new draft head for the page from a full item list. Live content is never changed and no cache is invalidated. Publishing is a separate call that needs `content:publish`.\n\n**Workflow.** Drafts and publishing work together like this:\n\n1. `GET /projects/{projectId}/page-drafts/{pageId}` reads the editable content and its revision tokens.\n2. `PUT` on the same path saves a new draft head (`versionId`). Live content is not touched.\n3. Publish the draft with `POST /publish-versions/{versionId}`, or schedule it with `POST /versions/{versionId}/schedule`.\n4. Manage history and the schedule with `GET /projects/{projectId}/versions`, `/versions/{versionId}` (read, reschedule, replace content, cancel), `publish-now` and `restore`.\n\n**Body**\n\n- `items`: the complete item graph, 1 to 200 items. Each item needs `id` and `type`; `children` are `{ \"id\": ... }` references and `data` is an object. Every child must reference an item in the list, ids must be unique, and every item must be reachable from the root. A malformed body is 400; a broken graph (duplicate ids, dangling child, orphaned items) is 404 `PAGE_NOT_FOUND`. Nothing is saved in either case.\n- The root is the item whose id matches the page's current `rootId`; otherwise the first item.\n- `name` (optional): renames the draft. Defaults to the live page name.\n\n**Revision fence.** All three tokens are required and must be copied exactly from the GET response:\n\n- `expectedHeadVersionId`: GET's `headVersionId` (`null` means \"no draft yet\").\n- `expectedPageUpdatedAt`: GET's `pageUpdatedAt`, the exact ISO string or `null`.\n- `expectedProjectUpdatedAt`: GET's `projectUpdatedAt`, the exact ISO string or `null`.\n\n`null` is a real baseline for a legacy row and only matches a row that is still `null`. If the draft head, the live page or the project moved since your GET, the save is refused with 409 `STALE_PAGE` and nothing is written. Re-read with GET, reapply your edit and save again.\n\n**Retries.** Retrying a save that already committed returns the same head instead of a conflict.\n\n**Response.** `versionId` is the new draft head. Pass it to `POST /publish-versions/{versionId}` or `POST /versions/{versionId}/schedule`, and send it as `expectedHeadVersionId` on your next save or discard.\n\nRequired scope: `content:write`","x-mint":{"metadata":{"playground":"simple"}},"method":"put","type":"path","servers":["06e8abcf-d98e-4c65-a1d0-4fa031893726"],"security":["15700b4d-44b3-4c88-a94b-4706f3058ff6"],"path":"/projects/{projectId}/page-drafts/{pageId}","baseUrlOptions":["https://studio.weaverse.io/api/v1/content"],"title":"Save a page draft","codeSamples":[],"requestExampleLanguages":["bash","javascript","python"],"requiredOnlyExamples":true,"requestExampleType":"generated","responseExampleType":"generated"},"dependencies":{"parameters":{"87a7047e-39f1-4f72-b63e-7b863364d26c":{"name":"projectId","in":"path","required":true,"schema":{"type":"string","isRequired":true,"uniqueKey":"","typeLabel":"string"}},"931411df-90a8-4ca7-bb6e-225d8f97233d":{"name":"pageId","in":"path","required":true,"schema":{"type":"string","isRequired":true,"uniqueKey":"","typeLabel":"string"}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["items","expectedHeadVersionId","expectedPageUpdatedAt","expectedProjectUpdatedAt"],"properties":{"items":{"type":"array","maxItems":200,"items":{"type":"object","required":["id"],"properties":{"id":{"type":"string","isRequired":true,"uniqueKey":"\\items.items.[INDEX].id","typeLabel":"string"},"type":{"type":"string","uniqueKey":"\\items.items.[INDEX].type","typeLabel":"string"},"data":{"type":"object","additionalProperties":true,"uniqueKey":"\\items.items.[INDEX].data","typeLabel":"object"},"children":{"type":"array","items":{"type":"object","required":["id"],"properties":{"id":{"type":"string","isRequired":true,"uniqueKey":"\\items.items.[INDEX].children.items.[INDEX].id","typeLabel":"string"}},"uniqueKey":"\\items.items.[INDEX].children.items.[INDEX]","typeLabel":"object"},"uniqueKey":"\\items.items.[INDEX].children","typeLabel":"object[]"}},"uniqueKey":"\\items.items.[INDEX]","typeLabel":"object"},"isRequired":true,"uniqueKey":"\\items","typeLabel":"object[]"},"expectedHeadVersionId":{"oneOf":[{"type":"string","description":"The head this edit started from; null means \"no draft yet\"","isRequired":true,"uniqueKey":"expectedHeadVersionId.oneOf.0","typeLabel":"string"},{"type":"null","description":"The head this edit started from; null means \"no draft yet\"","isRequired":true,"uniqueKey":"expectedHeadVersionId.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"expectedHeadVersionId","typeLabel":"string | null"},"expectedPageUpdatedAt":{"oneOf":[{"type":"string","format":"date-time","description":"GET `pageUpdatedAt` exactly as GET returned it (null = a legacy row with no revision). The save is refused with 409 STALE_PAGE when it no longer matches live.","isRequired":true,"uniqueKey":"expectedPageUpdatedAt.oneOf.0","typeLabel":"string\u003cdate-time>"},{"type":"null","format":"date-time","description":"GET `pageUpdatedAt` exactly as GET returned it (null = a legacy row with no revision). The save is refused with 409 STALE_PAGE when it no longer matches live.","isRequired":true,"uniqueKey":"expectedPageUpdatedAt.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"expectedPageUpdatedAt","typeLabel":"string\u003cdate-time> | null"},"expectedProjectUpdatedAt":{"oneOf":[{"type":"string","format":"date-time","description":"GET `projectUpdatedAt` exactly as GET returned it (null = a legacy row with no revision). The save is refused with 409 STALE_PAGE when it no longer matches live.","isRequired":true,"uniqueKey":"expectedProjectUpdatedAt.oneOf.0","typeLabel":"string\u003cdate-time>"},{"type":"null","format":"date-time","description":"GET `projectUpdatedAt` exactly as GET returned it (null = a legacy row with no revision). The save is refused with 409 STALE_PAGE when it no longer matches live.","isRequired":true,"uniqueKey":"expectedProjectUpdatedAt.oneOf.1","typeLabel":"null"}],"isRequired":true,"uniqueKey":"expectedProjectUpdatedAt","typeLabel":"string\u003cdate-time> | null"},"name":{"type":"string","uniqueKey":"name","typeLabel":"string"}},"uniqueKey":"","typeLabel":"object"},"example":{"items":[{"id":"root-1","type":"main","children":[{"id":"hero-1"}],"data":{}},{"id":"hero-1","type":"hero-image","data":{"heading":"Summer collection","height":"large"}}],"name":"Home","expectedHeadVersionId":null,"expectedPageUpdatedAt":"2026-10-08T10:00:00.000Z","expectedProjectUpdatedAt":"2026-10-08T09:00:00.000Z"},"examples":{"Example":{"title":"Example","value":{"items":[{"id":"root-1","type":"main","children":[{"id":"hero-1"}],"data":{}},{"id":"hero-1","type":"hero-image","data":{"heading":"Summer collection","height":"large"}}],"name":"Home","expectedHeadVersionId":null,"expectedPageUpdatedAt":"2026-10-08T10:00:00.000Z","expectedProjectUpdatedAt":"2026-10-08T09:00:00.000Z"}}},"exampleType":"examples"}},"exampleType":"examples"},"responses":{"ba7d137e-91ae-4638-a8d9-823dd0403eef":{"description":"New head version id","content":{"application/json":{"schema":{"type":"object","uniqueKey":"","typeLabel":"object"},"example":{"object":"page_draft_saved","pageId":"clz7pg9k2m4n6p8r0t2v4x6z","projectId":"clz7prj0a1b2c3d4e5f6g7h8","versionId":"clz9drf2h4j6l8n0p2r4t6v8","updatedAt":"2026-10-08T10:12:00.000Z"},"examples":{"Example":{"title":"Example","value":{"object":"page_draft_saved","pageId":"clz7pg9k2m4n6p8r0t2v4x6z","projectId":"clz7prj0a1b2c3d4e5f6g7h8","versionId":"clz9drf2h4j6l8n0p2r4t6v8","updatedAt":"2026-10-08T10:12:00.000Z"}}},"exampleType":"examples"}},"exampleType":"examples"},"8e1b2972-e3bf-4e6f-99c7-04ebfa672823":{"description":"Missing or invalid credentials","content":{"application/json":{"schema":{"type":"object","required":["object","code","message","status"],"properties":{"object":{"type":"string","enum":["error"],"isRequired":true,"uniqueKey":"object","typeLabel":"enum\u003cstring>"},"code":{"type":"string","enum":["UNAUTHORIZED","FORBIDDEN","INSUFFICIENT_SCOPE","PROJECT_NOT_FOUND","PAGE_NOT_FOUND","STALE_PAGE","STALE_PROJECT","STALE_TRANSLATION","TRANSLATION_UNIT_NOT_FOUND","SERVICE_UNAVAILABLE","CONFLICT","PRECONDITION_REQUIRED","INVALID_PARAMS","INTERNAL_ERROR"],"isRequired":true,"uniqueKey":"code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"},"status":{"type":"integer","isRequired":true,"uniqueKey":"status","typeLabel":"integer"},"details":{"description":"Optional machine-readable context, for example the clashing handles of a 409 CONFLICT.","uniqueKey":"details","typeLabel":"any"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"object":"error","code":"UNAUTHORIZED","message":"\u003cstring>","status":123,"details":"\u003cunknown>"}}},"exampleType":"generated"}},"exampleType":"generated"},"25f39021-9617-4eb0-b9fb-7a94d106efaa":{"description":"Foreign project or missing scope (INSUFFICIENT_SCOPE)","content":{"application/json":{"schema":{"type":"object","required":["object","code","message","status"],"properties":{"object":{"type":"string","enum":["error"],"isRequired":true,"uniqueKey":"object","typeLabel":"enum\u003cstring>"},"code":{"type":"string","enum":["UNAUTHORIZED","FORBIDDEN","INSUFFICIENT_SCOPE","PROJECT_NOT_FOUND","PAGE_NOT_FOUND","STALE_PAGE","STALE_PROJECT","STALE_TRANSLATION","TRANSLATION_UNIT_NOT_FOUND","SERVICE_UNAVAILABLE","CONFLICT","PRECONDITION_REQUIRED","INVALID_PARAMS","INTERNAL_ERROR"],"isRequired":true,"uniqueKey":"code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"},"status":{"type":"integer","isRequired":true,"uniqueKey":"status","typeLabel":"integer"},"details":{"description":"Optional machine-readable context, for example the clashing handles of a 409 CONFLICT.","uniqueKey":"details","typeLabel":"any"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"object":"error","code":"UNAUTHORIZED","message":"\u003cstring>","status":123,"details":"\u003cunknown>"}}},"exampleType":"generated"}},"exampleType":"generated"},"4f302fd7-f326-412e-82c9-35362bfd4e47":{"description":"Not found (never discloses other tenants)","content":{"application/json":{"schema":{"type":"object","required":["object","code","message","status"],"properties":{"object":{"type":"string","enum":["error"],"isRequired":true,"uniqueKey":"object","typeLabel":"enum\u003cstring>"},"code":{"type":"string","enum":["UNAUTHORIZED","FORBIDDEN","INSUFFICIENT_SCOPE","PROJECT_NOT_FOUND","PAGE_NOT_FOUND","STALE_PAGE","STALE_PROJECT","STALE_TRANSLATION","TRANSLATION_UNIT_NOT_FOUND","SERVICE_UNAVAILABLE","CONFLICT","PRECONDITION_REQUIRED","INVALID_PARAMS","INTERNAL_ERROR"],"isRequired":true,"uniqueKey":"code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"},"status":{"type":"integer","isRequired":true,"uniqueKey":"status","typeLabel":"integer"},"details":{"description":"Optional machine-readable context, for example the clashing handles of a 409 CONFLICT.","uniqueKey":"details","typeLabel":"any"}},"uniqueKey":"","typeLabel":"object"},"examples":{"Example":{"title":"Example","value":{"object":"error","code":"UNAUTHORIZED","message":"\u003cstring>","status":123,"details":"\u003cunknown>"}}},"exampleType":"generated"}},"exampleType":"generated"},"9acebd1c-ca2e-4631-8704-125c445672a9":{"description":"STALE_PAGE — the draft head, live page or project moved since GET; nothing was saved, re-read","content":{"application/json":{"schema":{"type":"object","required":["object","code","message","status"],"properties":{"object":{"type":"string","enum":["error"],"isRequired":true,"uniqueKey":"object","typeLabel":"enum\u003cstring>"},"code":{"type":"string","enum":["UNAUTHORIZED","FORBIDDEN","INSUFFICIENT_SCOPE","PROJECT_NOT_FOUND","PAGE_NOT_FOUND","STALE_PAGE","STALE_PROJECT","STALE_TRANSLATION","TRANSLATION_UNIT_NOT_FOUND","SERVICE_UNAVAILABLE","CONFLICT","PRECONDITION_REQUIRED","INVALID_PARAMS","INTERNAL_ERROR"],"isRequired":true,"uniqueKey":"code","typeLabel":"enum\u003cstring>"},"message":{"type":"string","isRequired":true,"uniqueKey":"message","typeLabel":"string"},"status":{"type":"integer","isRequired":true,"uniqueKey":"status","typeLabel":"integer"},"details":{"description":"Optional machine-readable context, for example the clashing handles of a 409 CONFLICT.","uniqueKey":"details","typeLabel":"any"}},"uniqueKey":"","typeLabel":"object"},"example":{"object":"error","code":"STALE_PAGE","message":"The live page or project changed since it was read; nothing was saved — re-read and retry","status":409},"examples":{"Example":{"title":"Example","value":{"object":"error","code":"STALE_PAGE","message":"The live page or project changed since it was read; nothing was saved — re-read and retry","status":409}}},"exampleType":"examples"}},"exampleType":"examples"}},"security":{"15700b4d-44b3-4c88-a94b-4706f3058ff6":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"WEAVERSE_API_KEY","description":"Bearer token: a shop API key (`WEAVERSE_API_KEY`), a scoped API key or a delegated MCP OAuth token; translation-unit routes also accept a project-bound translation agent token. Each operation lists the scope it requires; the scope table is in the API description.","scopes":[],"schemeName":"bearerAuth"}}},"servers":{"06e8abcf-d98e-4c65-a1d0-4fa031893726":{"url":"https://studio.weaverse.io/api/v1/content","description":"Production"}},"processedSecurityOptions":[{"schemes":[{"scheme":{"type":"http","scheme":"bearer","bearerFormat":"WEAVERSE_API_KEY","description":"Bearer token: a shop API key (`WEAVERSE_API_KEY`), a scoped API key or a delegated MCP OAuth token; translation-unit routes also accept a project-bound translation agent token. Each operation lists the scope it requires; the scope table is in the API description.","scopes":[],"schemeName":"bearerAuth"},"schema":{"title":"Bearer Auth","type":"string","isRequired":true,"description":"Bearer token: a shop API key (`WEAVERSE_API_KEY`), a scoped API key or a delegated MCP OAuth token; translation-unit routes also accept a project-bound translation agent token. Each operation lists the scope it requires; the scope table is in the API description.","format":"bearer","typeLabel":"string\u003cbearer>","deprecated":false},"schemeName":"bearerAuth","name":"Authorization"}],"title":"bearerAuth"}]},"originalFileLocation":"https://studio.weaverse.io/api/v1/content/openapi.json"},"subdomain":"weaverse","siteName":"Weaverse","title":"Save a page draft - Weaverse","navMaps":{"firstHrefInVersion":{"v5.x":{"href":"/content-api/drafts-and-publishing/save-a-page-draft","matchLevel":0}},"firstHrefInLanguage":{}},"originalFileLocation":"content-api/drafts-and-publishing/save-a-page-draft.mdx"},"headHtml":"\u003cscript data-mint-head>(function(){var d=document.documentElement,p=null;if(!p){try{p=localStorage.getItem(\"isDarkMode\")}catch(e){}if(p==='true')p='dark';else if(p==='false')p='light';if(p!=='light'\u0026\u0026p!=='dark'\u0026\u0026p!=='system')p=\"system\"}var r=p==='system'?(matchMedia(\"(prefers-color-scheme: dark)\").matches?'dark':'light'):p;d.classList.remove(r==='dark'?'light':'dark');d.classList.add(r);d.setAttribute(\"data-theme-preference\",p)})();\u003c/script>\u003cmeta data-mint-head name=\"description\" content=\"Saves a new draft head for the page from a full item list. Live content is never changed and no cache is invalidated. Publishing is a separate call that needs content:publish. Workflow. Drafts and publishing work together like this: 1. GET /projects/{projectId}/page-drafts/{pageId} reads the editable content and its revision tokens. 2. PUT on the same path saves a new draft head (versionId). Live content is not touched. 3. Publish the draft with POST /publish-versions/{versionId}, or schedule it with POST /versions/{versionId}/schedule. 4. Manage history and the schedule with GET /projects/{projectId}/versions, /versions/{versionId} (read, reschedule, replace content, cancel), publish-now and restore. Body - items: the complete item graph, 1 to 200 items. Each item needs id and type; children are { \u0026quot;id\u0026quot;: ... } references and data is an object. Every child must reference an item in the list, ids must be unique, and every item must be reachable from the root. A malformed body is 400; a broken graph (duplicate ids, dangling child, orphaned items) is 404 PAGE_NOT_FOUND. Nothing is saved in either case. - The root is the item whose id matches the page\u0026#x27;s current rootId; otherwise the first item. - name (optional): renames the draft. Defaults to the live page name. Revision fence. All three tokens are required and must be copied exactly from the GET response: - expectedHeadVersionId: GET\u0026#x27;s headVersionId (null means \u0026quot;no draft yet\u0026quot;). - expectedPageUpdatedAt: GET\u0026#x27;s pageUpdatedAt, the exact ISO string or null. - expectedProjectUpdatedAt: GET\u0026#x27;s projectUpdatedAt, the exact ISO string or null. null is a real baseline for a legacy row and only matches a row that is still null. If the draft head, the live page or the project moved since your GET, the save is refused with 409 STALE_PAGE and nothing is written. Re-read with GET, reapply your edit and save again. Retries. Retrying a save that already committed returns the same head instead of a conflict. Response. versionId is the new draft head. Pass it to POST /publish-versions/{versionId} or POST /versions/{versionId}/schedule, and send it as expectedHeadVersionId on your next save or discard. Required scope: content:write\">\u003cmeta data-mint-head name=\"keywords\" content=\"Weaverse, Shopify Hydrogen, headless commerce, visual page builder, React Router, Next.js\">\u003cmeta data-mint-head name=\"application-name\" content=\"Weaverse\">\u003cmeta data-mint-head name=\"generator\" content=\"Mintlify\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/weaverse/BNjY59OJurJKyxIa/_generated/favicon/android-chrome-192x192.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"apple-touch-icon\" type=\"image/png\" sizes=\"180x180\" href=\"/docs/mintlify-assets/_mintlify/favicons/weaverse/BNjY59OJurJKyxIa/_generated/favicon/apple-touch-icon.png\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/weaverse/BNjY59OJurJKyxIa/_generated/favicon/favicon-16x16.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/weaverse/BNjY59OJurJKyxIa/_generated/favicon/favicon-32x32.png\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/weaverse/BNjY59OJurJKyxIa/_generated/favicon/favicon.ico\" media=\"(prefers-color-scheme: light)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"192x192\" href=\"/docs/mintlify-assets/_mintlify/favicons/weaverse/BNjY59OJurJKyxIa/_generated/favicon-dark/android-chrome-192x192.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"16x16\" href=\"/docs/mintlify-assets/_mintlify/favicons/weaverse/BNjY59OJurJKyxIa/_generated/favicon-dark/favicon-16x16.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"icon\" type=\"image/png\" sizes=\"32x32\" href=\"/docs/mintlify-assets/_mintlify/favicons/weaverse/BNjY59OJurJKyxIa/_generated/favicon-dark/favicon-32x32.png\" media=\"(prefers-color-scheme: dark)\">\u003clink data-mint-head rel=\"shortcut icon\" type=\"image/x-icon\" href=\"/docs/mintlify-assets/_mintlify/favicons/weaverse/BNjY59OJurJKyxIa/_generated/favicon-dark/favicon.ico\" media=\"(prefers-color-scheme: dark)\">\u003cmeta data-mint-head property=\"og:title\" content=\"Save a page draft - Weaverse\">\u003cmeta data-mint-head property=\"og:description\" content=\"Saves a new draft head for the page from a full item list. Live content is never changed and no cache is invalidated. Publishing is a separate call that needs content:publish. Workflow. Drafts and publishing work together like this: 1. GET /projects/{projectId}/page-drafts/{pageId} reads the editable content and its revision tokens. 2. PUT on the same path saves a new draft head (versionId). Live content is not touched. 3. Publish the draft with POST /publish-versions/{versionId}, or schedule it with POST /versions/{versionId}/schedule. 4. Manage history and the schedule with GET /projects/{projectId}/versions, /versions/{versionId} (read, reschedule, replace content, cancel), publish-now and restore. Body - items: the complete item graph, 1 to 200 items. Each item needs id and type; children are { \u0026quot;id\u0026quot;: ... } references and data is an object. Every child must reference an item in the list, ids must be unique, and every item must be reachable from the root. A malformed body is 400; a broken graph (duplicate ids, dangling child, orphaned items) is 404 PAGE_NOT_FOUND. Nothing is saved in either case. - The root is the item whose id matches the page\u0026#x27;s current rootId; otherwise the first item. - name (optional): renames the draft. Defaults to the live page name. Revision fence. All three tokens are required and must be copied exactly from the GET response: - expectedHeadVersionId: GET\u0026#x27;s headVersionId (null means \u0026quot;no draft yet\u0026quot;). - expectedPageUpdatedAt: GET\u0026#x27;s pageUpdatedAt, the exact ISO string or null. - expectedProjectUpdatedAt: GET\u0026#x27;s projectUpdatedAt, the exact ISO string or null. null is a real baseline for a legacy row and only matches a row that is still null. If the draft head, the live page or the project moved since your GET, the save is refused with 409 STALE_PAGE and nothing is written. Re-read with GET, reapply your edit and save again. Retries. Retrying a save that already committed returns the same head instead of a conflict. Response. versionId is the new draft head. Pass it to POST /publish-versions/{versionId} or POST /versions/{versionId}/schedule, and send it as expectedHeadVersionId on your next save or discard. Required scope: content:write\">\u003cmeta data-mint-head property=\"og:site_name\" content=\"Weaverse Docs\">\u003cmeta data-mint-head property=\"og:url\" content=\"https://weaverse.io/docs/content-api/drafts-and-publishing/save-a-page-draft\">\u003cmeta data-mint-head property=\"og:type\" content=\"website\">\u003cmeta data-mint-head property=\"og:image\" content=\"https://weaverse.mintlify.site/docs/_mintlify/api/og/v2?division=Drafts+and+publishing\u0026amp;title=Save+a+page+draft\u0026amp;description=Saves+a+new+draft+head+for+the+page+from+a+full+item+list.+Live+content+is+never+changed+and+no+cache+is+invalidated.+Publishing+is+a+separate+call+that+needs+%60\u0026amp;theme=0d100f7670b454d40a653506\u0026amp;signature=06d5038cb8d949ad0dcba396df567ec7379bd252b18c575da127ee3fb9da0818\">\u003cmeta data-mint-head property=\"og:image:width\" content=\"1200\">\u003cmeta data-mint-head property=\"og:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"twitter:card\" content=\"summary_large_image\">\u003cmeta data-mint-head name=\"twitter:title\" content=\"Save a page draft - Weaverse\">\u003cmeta data-mint-head name=\"twitter:description\" content=\"Saves a new draft head for the page from a full item list. Live content is never changed and no cache is invalidated. Publishing is a separate call that needs content:publish. Workflow. Drafts and publishing work together like this: 1. GET /projects/{projectId}/page-drafts/{pageId} reads the editable content and its revision tokens. 2. PUT on the same path saves a new draft head (versionId). Live content is not touched. 3. Publish the draft with POST /publish-versions/{versionId}, or schedule it with POST /versions/{versionId}/schedule. 4. Manage history and the schedule with GET /projects/{projectId}/versions, /versions/{versionId} (read, reschedule, replace content, cancel), publish-now and restore. Body - items: the complete item graph, 1 to 200 items. Each item needs id and type; children are { \u0026quot;id\u0026quot;: ... } references and data is an object. Every child must reference an item in the list, ids must be unique, and every item must be reachable from the root. A malformed body is 400; a broken graph (duplicate ids, dangling child, orphaned items) is 404 PAGE_NOT_FOUND. Nothing is saved in either case. - The root is the item whose id matches the page\u0026#x27;s current rootId; otherwise the first item. - name (optional): renames the draft. Defaults to the live page name. Revision fence. All three tokens are required and must be copied exactly from the GET response: - expectedHeadVersionId: GET\u0026#x27;s headVersionId (null means \u0026quot;no draft yet\u0026quot;). - expectedPageUpdatedAt: GET\u0026#x27;s pageUpdatedAt, the exact ISO string or null. - expectedProjectUpdatedAt: GET\u0026#x27;s projectUpdatedAt, the exact ISO string or null. null is a real baseline for a legacy row and only matches a row that is still null. If the draft head, the live page or the project moved since your GET, the save is refused with 409 STALE_PAGE and nothing is written. Re-read with GET, reapply your edit and save again. Retries. Retrying a save that already committed returns the same head instead of a conflict. Response. versionId is the new draft head. Pass it to POST /publish-versions/{versionId} or POST /versions/{versionId}/schedule, and send it as expectedHeadVersionId on your next save or discard. Required scope: content:write\">\u003cmeta data-mint-head name=\"twitter:image\" content=\"https://weaverse.mintlify.site/docs/_mintlify/api/og/v2?division=Drafts+and+publishing\u0026amp;title=Save+a+page+draft\u0026amp;description=Saves+a+new+draft+head+for+the+page+from+a+full+item+list.+Live+content+is+never+changed+and+no+cache+is+invalidated.+Publishing+is+a+separate+call+that+needs+%60\u0026amp;theme=0d100f7670b454d40a653506\u0026amp;signature=06d5038cb8d949ad0dcba396df567ec7379bd252b18c575da127ee3fb9da0818\">\u003cmeta data-mint-head name=\"twitter:image:width\" content=\"1200\">\u003cmeta data-mint-head name=\"twitter:image:height\" content=\"630\">\u003cmeta data-mint-head name=\"msapplication-config\" content=\"/docs/mintlify-assets/_mintlify/favicons/weaverse/BNjY59OJurJKyxIa/_generated/favicon/browserconfig.xml\">\u003cmeta data-mint-head name=\"apple-mobile-web-app-title\" content=\"Weaverse\">\u003cmeta data-mint-head name=\"msapplication-TileColor\" content=\"#246aff\">\u003clink data-mint-head rel=\"canonical\" href=\"https://weaverse.io/docs/content-api/drafts-and-publishing/save-a-page-draft\">\u003clink data-mint-head rel=\"alternate\" type=\"application/xml\" href=\"/docs/sitemap.xml\">\u003clink data-mint-head rel=\"alternate\" type=\"text/markdown\" href=\"/docs/content-api/drafts-and-publishing/save-a-page-draft.md\">\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@graph\":[{\"@type\":\"Organization\",\"@id\":\"https://weaverse.io/#organization\",\"name\":\"Weaverse\",\"url\":\"https://weaverse.io\",\"logo\":{\"@type\":\"ImageObject\",\"url\":\"https://docs.weaverse.io/logo/light.svg\"},\"sameAs\":[\"https://github.com/weaverse\",\"https://x.com/WeaverseIO\",\"https://wvse.cc/weaverse-slack\"]},{\"@type\":\"WebSite\",\"@id\":\"https://weaverse.io/docs#website\",\"name\":\"Weaverse\",\"url\":\"https://weaverse.io/docs\",\"publisher\":{\"@id\":\"https://weaverse.io/#organization\"}},{\"@type\":\"WebPage\",\"@id\":\"https://weaverse.io/docs/content-api/drafts-and-publishing/save-a-page-draft#webpage\",\"url\":\"https://weaverse.io/docs/content-api/drafts-and-publishing/save-a-page-draft\",\"name\":\"Save a page draft\",\"description\":\"Saves a new draft head for the page from a full item list. Live content is never changed and no cache is invalidated. Publishing is a separate call that needs content:publish. Workflow. Drafts and publishing work together like this: 1. GET /projects/{projectId}/page-drafts/{pageId} reads the editable content and its revision tokens. 2. PUT on the same path saves a new draft head (versionId). Live content is not touched. 3. Publish the draft with POST /publish-versions/{versionId}, or schedule it with POST /versions/{versionId}/schedule. 4. Manage history and the schedule with GET /projects/{projectId}/versions, /versions/{versionId} (read, reschedule, replace content, cancel), publish-now and restore. Body - items: the complete item graph, 1 to 200 items. Each item needs id and type; children are { \\\"id\\\": ... } references and data is an object. Every child must reference an item in the list, ids must be unique, and every item must be reachable from the root. A malformed body is 400; a broken graph (duplicate ids, dangling child, orphaned items) is 404 PAGE_NOT_FOUND. Nothing is saved in either case. - The root is the item whose id matches the page's current rootId; otherwise the first item. - name (optional): renames the draft. Defaults to the live page name. Revision fence. All three tokens are required and must be copied exactly from the GET response: - expectedHeadVersionId: GET's headVersionId (null means \\\"no draft yet\\\"). - expectedPageUpdatedAt: GET's pageUpdatedAt, the exact ISO string or null. - expectedProjectUpdatedAt: GET's projectUpdatedAt, the exact ISO string or null. null is a real baseline for a legacy row and only matches a row that is still null. If the draft head, the live page or the project moved since your GET, the save is refused with 409 STALE_PAGE and nothing is written. Re-read with GET, reapply your edit and save again. Retries. Retrying a save that already committed returns the same head instead of a conflict. Response. versionId is the new draft head. Pass it to POST /publish-versions/{versionId} or POST /versions/{versionId}/schedule, and send it as expectedHeadVersionId on your next save or discard. Required scope: content:write\",\"isPartOf\":{\"@id\":\"https://weaverse.io/docs#website\"},\"breadcrumb\":{\"@id\":\"https://weaverse.io/docs/content-api/drafts-and-publishing/save-a-page-draft#breadcrumb\"}},{\"@type\":\"BreadcrumbList\",\"@id\":\"https://weaverse.io/docs/content-api/drafts-and-publishing/save-a-page-draft#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Drafts and publishing\",\"item\":\"https://weaverse.io/docs/content-api/drafts-and-publishing/get-a-pages-editable-content-and-revision-tokens\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Save a page draft\",\"item\":\"https://weaverse.io/docs/content-api/drafts-and-publishing/save-a-page-draft\"}]},{\"@type\":[\"TechArticle\",\"APIReference\"],\"@id\":\"https://weaverse.io/docs/content-api/drafts-and-publishing/save-a-page-draft#apireference\",\"headline\":\"Save a page draft\",\"name\":\"Save a page draft\",\"description\":\"Saves a new draft head for the page from a full item list. Live content is never changed and no cache is invalidated. Publishing is a separate call that needs content:publish. Workflow. Drafts and publishing work together like this: 1. GET /projects/{projectId}/page-drafts/{pageId} reads the editable content and its revision tokens. 2. PUT on the same path saves a new draft head (versionId). Live content is not touched. 3. Publish the draft with POST /publish-versions/{versionId}, or schedule it with POST /versions/{versionId}/schedule. 4. Manage history and the schedule with GET /projects/{projectId}/versions, /versions/{versionId} (read, reschedule, replace content, cancel), publish-now and restore. Body - items: the complete item graph, 1 to 200 items. Each item needs id and type; children are { \\\"id\\\": ... } references and data is an object. Every child must reference an item in the list, ids must be unique, and every item must be reachable from the root. A malformed body is 400; a broken graph (duplicate ids, dangling child, orphaned items) is 404 PAGE_NOT_FOUND. Nothing is saved in either case. - The root is the item whose id matches the page's current rootId; otherwise the first item. - name (optional): renames the draft. Defaults to the live page name. Revision fence. All three tokens are required and must be copied exactly from the GET response: - expectedHeadVersionId: GET's headVersionId (null means \\\"no draft yet\\\"). - expectedPageUpdatedAt: GET's pageUpdatedAt, the exact ISO string or null. - expectedProjectUpdatedAt: GET's projectUpdatedAt, the exact ISO string or null. null is a real baseline for a legacy row and only matches a row that is still null. If the draft head, the live page or the project moved since your GET, the save is refused with 409 STALE_PAGE and nothing is written. Re-read with GET, reapply your edit and save again. Retries. Retrying a save that already committed returns the same head instead of a conflict. Response. versionId is the new draft head. Pass it to POST /publish-versions/{versionId} or POST /versions/{versionId}/schedule, and send it as expectedHeadVersionId on your next save or discard. Required scope: content:write\",\"url\":\"https://weaverse.io/docs/content-api/drafts-and-publishing/save-a-page-draft\",\"mainEntityOfPage\":{\"@id\":\"https://weaverse.io/docs/content-api/drafts-and-publishing/save-a-page-draft#webpage\"},\"publisher\":{\"@id\":\"https://weaverse.io/#organization\"},\"isPartOf\":{\"@id\":\"https://weaverse.io/docs#website\"}}]}\u003c/script>\u003cscript data-mint-head type=\"application/ld+json\">{\"@context\":\"https://schema.org\",\"@type\":\"WebSite\",\"name\":\"Weaverse\",\"creator\":{\"@type\":\"Organization\",\"name\":\"Mintlify\",\"url\":\"https://mintlify.com\"}}\u003c/script>","siteName":"Weaverse","nav":{"global":null,"versions":[{"version":"v5.x","default":true,"tag":"Latest","tabs":[{"tab":"Get Started","pages":[{"title":"Get Started","href":""}]},{"tab":"Guides","dropdowns":[{"dropdown":"React Router","icon":"https://mintlify.s3.us-west-1.amazonaws.com/weaverse/images/icons/react-router.svg","groups":[{"group":"Environment","pages":[{"title":"Environment Variables","href":"/development-guide/environment-setup"},{"title":"Studio vs. Live Environment","href":"/development-guide/design-mode"}]},{"group":"Building Components","pages":[{"title":"Creating Components","href":"/development-guide/creating-components"},{"title":"Component Schema","href":"/development-guide/component-schema"},{"title":"Input Settings","href":"/development-guide/input-settings"},{"title":"Weaverse Hydrogen Component","href":"/development-guide/weaverse-component"},{"title":"Styling \u0026 Theming","href":"/development-guide/styling-theming"},{"title":"Section Data Fetching","href":"/development-guide/data-fetching"},{"title":"Data Connectors","href":"/development-guide/data-connectors"}]},{"group":"Content Management","pages":[{"title":"Global Sections","href":"/features/global-sections"},{"title":"Scheduled Publishing","href":"/features/schedule-publish"},{"title":"Navigation Configuration","href":"/features/navigation-menus"},{"title":"Third-party Integration","href":"/features/third-party-integrations"},{"title":"Installable Mobile App (PWA)","href":"/features/mobile-app-pwa"}]},{"group":"Internationalization","pages":[{"title":"Markets and Localization","href":"/features/markets-localization"},{"title":"Translation Feature Guide","href":"/features/translation-feature-guide"},{"title":"i18next Integration","href":"/features/i18next-integration"}]},{"group":"Security \u0026 Privacy","pages":[{"title":"Content Security Policy","href":"/features/content-security"},{"title":"Cookie Consent Banner","href":"/features/cookie-consent-banner"},{"title":"Analytics \u0026 Conversion Tracking","href":"/features/analytics-tracking"},{"title":"Security \u0026 Deployment Practices","href":"/features/security-deployment-practices"}]},{"group":"Pages \u0026 Routing","pages":[{"title":"Custom Pages","href":"/features/custom-pages"},{"title":"Page SEO","href":"/features/page-seo"},{"title":"Custom Templates","href":"/features/custom-templates"},{"title":"Custom Routing","href":"/features/custom-routing"}]},{"group":"Advanced","pages":[{"title":"Rendering Weaverse Pages","href":"/guides/rendering-page"},{"title":"Advanced Localization Guide","href":"/guides/localization-advanced"},{"title":"Multi-Project Architecture","href":"/guides/multi-project-architecture"},{"title":"Customer Account API Local Development","href":"/development-guide/customer-account-local-dev"},{"title":"Multipass in Hydrogen","href":"/development-guide/multipass-in-hydrogen"}]},{"group":"Deployment","root":{"title":"Deployment","href":"/guides/deployment/index"},"directory":"card","pages":[{"title":"Deploy to Shopify Oxygen","href":"/guides/deployment/oxygen"},{"title":"Custom Domain \u0026 DNS Setup","href":"/guides/deployment/custom-domain-and-dns"},{"title":"Deploy with Docker","href":"/guides/deployment/docker"},{"title":"Deploy to Cloudflare Workers","href":"/guides/deployment/workers"}]}]},{"dropdown":"Next.js","icon":"https://mintlify.s3.us-west-1.amazonaws.com/weaverse/images/icons/nextjs.svg","groups":[{"group":"Getting started","pages":[{"title":"Weaverse for Next.js","href":"/nextjs/overview"},{"title":"Next.js Quickstart","href":"/nextjs/quickstart"}]},{"group":"Next.js","pages":[{"title":"Rendering Pages in Next.js","href":"/nextjs/rendering-pages"},{"title":"Data Fetching in Next.js","href":"/nextjs/data-fetching"},{"title":"Connect Weaverse Studio","href":"/nextjs/studio"},{"title":"Markets \u0026 Translations","href":"/nextjs/markets-translations"}]},{"group":"Content Management","pages":[{"title":"Global Sections","href":"/features/global-sections"},{"title":"Navigation Configuration","href":"/features/navigation-menus"},{"title":"Third-party Integrations in Next.js","href":"/nextjs/third-party-integrations"},{"title":"Installable Mobile App (PWA)","href":"/features/mobile-app-pwa"}]},{"group":"Deployment","pages":[{"title":"Deploy to Vercel","href":"/guides/deployment/vercel"}]}]}]},{"tab":"SDKs","dropdowns":[{"dropdown":"React Router","icon":"https://mintlify.s3.us-west-1.amazonaws.com/weaverse/images/icons/react-router.svg","groups":[{"group":"Overview","pages":[{"title":"Introduction","sidebarTitle":"Overview","href":"/api-reference/introduction"}]},{"group":"Hooks","pages":[{"title":"useWeaverse","href":"/api-reference/use-weaverse"},{"title":"useItemInstance","href":"/api-reference/use-item-instance"},{"title":"useParentInstance","href":"/api-reference/use-parent-instance"},{"title":"useChildInstances","href":"/api-reference/use-child-instances"},{"title":"useThemeSettings","href":"/api-reference/use-theme-settings"}]},{"group":"Components","pages":[{"title":"WeaverseHydrogenRoot","href":"/api-reference/weaverse-root"},{"title":"WeaverseClient","href":"/api-reference/weaverse-client"},{"title":"withWeaverse","href":"/api-reference/with-weaverse"}]},{"group":"Utilities \u0026 Types","pages":[{"title":"getSelectedProductOptions","href":"/api-reference/get-selected-product-options"},{"title":"IMAGES_PLACEHOLDERS","href":"/api-reference/images-placeholders"},{"title":"Types","href":"/api-reference/types"}]}]},{"dropdown":"Next.js","icon":"https://mintlify.s3.us-west-1.amazonaws.com/weaverse/images/icons/nextjs.svg","groups":[{"group":"Overview","pages":[{"title":"@weaverse/next API Reference","href":"/nextjs/api-reference"}]},{"group":"Hooks","pages":[{"title":"useWeaverse","href":"/nextjs/api/use-weaverse"},{"title":"useItemInstance","href":"/nextjs/api/use-item-instance"},{"title":"useParentInstance","href":"/nextjs/api/use-parent-instance"},{"title":"useChildInstances","href":"/nextjs/api/use-child-instances"},{"title":"useThemeSettings","href":"/nextjs/api/use-theme-settings"}]}]}]},{"tab":"Content API","groups":[{"group":"Get started","pages":[{"title":"Content API","sidebarTitle":"Overview","href":"/content-api/overview"},{"title":"Portable Text Format","href":"/content-api/portable-text"},{"title":"List Public Custom Pages","href":"/content-api/public-custom-pages"}]},{"group":"Projects","pages":[{"title":"List projects","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects","href":"/content-api/projects/list-projects"},{"title":"Run a project lifecycle operation","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects","href":"/content-api/projects/run-a-project-lifecycle-operation"},{"title":"Get project","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}","href":"/content-api/projects/get-project"},{"title":"Update project","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json patch /projects/{projectId}","href":"/content-api/projects/update-project"}]},{"group":"Pages","pages":[{"title":"List page assignments","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/pages","href":"/content-api/pages/list-page-assignments"},{"title":"Create a page","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/pages","href":"/content-api/pages/create-a-page"},{"title":"Bulk delete pages","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json delete /projects/{projectId}/pages","href":"/content-api/pages/bulk-delete-pages"},{"title":"Get page content","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/pages/{type}/{handle}","href":"/content-api/pages/get-page-content"},{"title":"Update page content","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json patch /projects/{projectId}/pages/{type}/{handle}","href":"/content-api/pages/update-page-content"}]},{"group":"Assignments","pages":[{"title":"Assign resources to a shared template page","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/template-assignments/{pageId}","href":"/content-api/assignments/assign-resources-to-a-shared-template-page"},{"title":"List page assignments","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/assignments","href":"/content-api/assignments/list-page-assignments"},{"title":"Update, localize or remove page assignments","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/assignments","href":"/content-api/assignments/update-localize-or-remove-page-assignments"}]},{"group":"Theme settings","pages":[{"title":"Get theme settings","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/theme-settings","href":"/content-api/theme-settings/get-theme-settings"},{"title":"Update theme settings","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json patch /projects/{projectId}/theme-settings","href":"/content-api/theme-settings/update-theme-settings"}]},{"group":"Languages and localization","pages":[{"title":"List project languages","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/languages","href":"/content-api/languages-and-localization/list-project-languages"},{"title":"Get languages, glossary or static text","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/localization","href":"/content-api/languages-and-localization/get-languages-glossary-or-static-text"},{"title":"Manage languages, glossary and static text","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/localization","href":"/content-api/languages-and-localization/manage-languages-glossary-and-static-text"}]},{"group":"Specification","pages":[{"title":"Get the OpenAPI specification","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /openapi.json","href":"/content-api/specification/get-the-openapi-specification"}]},{"group":"Translations","pages":[{"title":"Read a page's translations for one locale","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/page-translations/{pageId}","href":"/content-api/translations/read-a-pages-translations-for-one-locale"},{"title":"Apply translations for one page and locale","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/page-translations/{pageId}","href":"/content-api/translations/apply-translations-for-one-page-and-locale"},{"title":"List translation units for a target locale","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/translation-units","href":"/content-api/translations/list-translation-units-for-a-target-locale"},{"title":"Validate or apply a translation batch","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/translations/{operation}","href":"/content-api/translations/validate-or-apply-a-translation-batch"}]},{"group":"Drafts and publishing","pages":[{"title":"Get a page's editable content and revision tokens","description":"Returns the content you should edit for one page, plus the revision tokens that a later save must send back unchanged. This is step 1 of draft-first editing.\n\n**Workflow.** Drafts and publishing work together like this:\n\n1. `GET /projects/{projectId}/page-drafts/{pageId}` reads the editable content and its revision tokens.\n2. `PUT` on the same path saves a new draft head (`versionId`). Live content is not touched.\n3. Publish the draft with `POST /publish-versions/{versionId}`, or schedule it with `POST /versions/{versionId}/schedule`.\n4. Manage history and the schedule with `GET /projects/{projectId}/versions`, `/versions/{versionId}` (read, reschedule, replace content, cancel), `publish-now` and `restore`.\n\n**What is returned**\n\n- When the page has a draft head: the draft's items, with `headVersionId` set to that draft. `pageUpdatedAt` and `projectUpdatedAt` are the live revisions the draft was built on, not the current live revisions. If live content has changed since the draft was saved, a save from this read is refused with 409 `STALE_PAGE`, so a draft can never quietly publish over a newer live edit.\n- When there is no draft: the live items, with `headVersionId: null` and the current live `pageUpdatedAt` / `projectUpdatedAt`.\n- Items are a flat list. Each item has `id`, `type`, `data` and `children` (child id references). `rootId` names the root item.\n- `pageUpdatedAt` or `projectUpdatedAt` is `null` for a legacy row whose revision was never set. Send that `null` back as is. A read never repairs it.\n\n**Addressing.** The page is addressed by `pageId` only. There is no locale or handle fallback, so a draft can never be read from or saved onto another assignment. A page that is not a live page of this project, or a draft head whose snapshot cannot be read, returns 404.\n\nRequired scope: `content:read`","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/page-drafts/{pageId}","href":"/content-api/drafts-and-publishing/get-a-pages-editable-content-and-revision-tokens"},{"title":"Save a page draft","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json put /projects/{projectId}/page-drafts/{pageId}","href":"/content-api/drafts-and-publishing/save-a-page-draft"},{"title":"Discard a page draft","description":"Discards the page's current draft head. Live content stays as it is, and the draft's version row is kept in history; only the head pointer is removed. The next GET returns live content again.\n\n**Fence.** Send `expectedHeadVersionId` with the `headVersionId` from GET. The discard is an exact compare-and-set:\n\n- If another save replaced the head since your read, the response is 409 `STALE_PAGE` and nothing is discarded.\n- Only an active (unscheduled) draft can be discarded. A scheduled draft, an unknown version or a page without a draft returns 404 `PAGE_NOT_FOUND`. Cancel the schedule with `DELETE /versions/{versionId}` first.\n\nRequired scope: `content:write`","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json delete /projects/{projectId}/page-drafts/{pageId}","href":"/content-api/drafts-and-publishing/discard-a-page-draft"},{"title":"Publish a saved page draft","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /publish-versions/{versionId}","href":"/content-api/drafts-and-publishing/publish-a-saved-page-draft"},{"title":"List page versions, theme versions or the schedule","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/versions","href":"/content-api/drafts-and-publishing/list-page-versions-theme-versions-or-the-schedule"},{"title":"Get one page or theme version","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /versions/{versionId}","href":"/content-api/drafts-and-publishing/get-one-page-or-theme-version"},{"title":"Replace a version's pending content","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json put /versions/{versionId}","href":"/content-api/drafts-and-publishing/replace-a-versions-pending-content"},{"title":"Cancel a scheduled publication","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json delete /versions/{versionId}","href":"/content-api/drafts-and-publishing/cancel-a-scheduled-publication"},{"title":"Reschedule a scheduled version","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json patch /versions/{versionId}","href":"/content-api/drafts-and-publishing/reschedule-a-scheduled-version"},{"title":"Schedule a version for publication","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /versions/{versionId}/schedule","href":"/content-api/drafts-and-publishing/schedule-a-version-for-publication"},{"title":"Publish a scheduled version immediately","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /versions/{versionId}/publish-now","href":"/content-api/drafts-and-publishing/publish-a-scheduled-version-immediately"},{"title":"Restore a version to live","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /versions/{versionId}/restore","href":"/content-api/drafts-and-publishing/restore-a-version-to-live"}]},{"group":"Global sections","pages":[{"title":"List global sections","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/global-sections","href":"/content-api/global-sections/list-global-sections"},{"title":"Promote an item to a global section","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/global-sections","href":"/content-api/global-sections/promote-an-item-to-a-global-section"},{"title":"Get a global section's draft","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/global-sections/{sectionId}","href":"/content-api/global-sections/get-a-global-sections-draft"},{"title":"Rename, delete, or draft and publish a global section","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/global-sections/{sectionId}","href":"/content-api/global-sections/rename-delete-or-draft-and-publish-a-global-section"}]},{"group":"Page settings","pages":[{"title":"Get page settings","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/page-settings/{pageId}","href":"/content-api/page-settings/get-page-settings"},{"title":"Rename a page or update its SEO","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/page-settings/{pageId}","href":"/content-api/page-settings/rename-a-page-or-update-its-seo"}]},{"group":"Project structure","pages":[{"title":"Get project hierarchy","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/hierarchy","href":"/content-api/project-structure/get-project-hierarchy"},{"title":"Manage variants and page overrides","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/hierarchy","href":"/content-api/project-structure/manage-variants-and-page-overrides"}]},{"group":"Backups and portability","pages":[{"title":"List, download or diff project backups","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/backups","href":"/content-api/backups-and-portability/list-download-or-diff-project-backups"},{"title":"Create a backup or restore one as a new project","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/backups","href":"/content-api/backups-and-portability/create-a-backup-or-restore-one-as-a-new-project"},{"title":"Export the live project","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/export","href":"/content-api/backups-and-portability/export-the-live-project"},{"title":"Import an export file into this project","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/import","href":"/content-api/backups-and-portability/import-an-export-file-into-this-project"},{"title":"Restore an uploaded backup file as a new project","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /backup-restores","href":"/content-api/backups-and-portability/restore-an-uploaded-backup-file-as-a-new-project"}]},{"group":"Previews and hostnames","pages":[{"title":"List preview URLs","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/previews","href":"/content-api/previews-and-hostnames/list-preview-urls"},{"title":"Create, update or delete a preview URL","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/previews","href":"/content-api/previews-and-hostnames/create-update-or-delete-a-preview-url"},{"title":"List observed storefront hostnames","deprecated":null,"version":null,"openapi":"https://studio.weaverse.io/api/v1/content/openapi.json get /projects/{projectId}/hostnames","href":"/content-api/previews-and-hostnames/list-observed-storefront-hostnames"},{"title":"Block or unblock a storefront hostname","deprecated":null,"version":null,"playground":"simple","openapi":"https://studio.weaverse.io/api/v1/content/openapi.json post /projects/{projectId}/hostnames","href":"/content-api/previews-and-hostnames/block-or-unblock-a-storefront-hostname"}]}]},{"tab":"Ecosystem","pages":[{"title":"Ecosystem","href":"/ecosystem"}]},{"tab":"Help \u0026 Community","pages":[{"title":"Help \u0026 Community","href":"/resources"}]}]}]},"basePath":"","title":"Save a page draft - Weaverse","buildId":"dpl_6dVqRXFR2Go5vF5RLvAdHuv189oT","deploymentId":"dpl_6dVqRXFR2Go5vF5RLvAdHuv189oT","dynamics":["c2aa737661","2b790eda92","b0f84f53ff","a9bb46feb3"],"chunks":["OpenApiReferenceProvider-D_7my4bd.js","utils-Cq_itTNA.js","cloneDeep-izs3Hzxb.js","_Uint8Array-BVIqJ90l.js","isObjectLike-C8vmzPEN.js","isArray-Dcu1dQ5t.js","utils-B5KPEvGz.js","toString-BX-iyh8G.js","isSymbol-CSH9U2Gm.js","addUniqueKeysToSchema-DBX-JepP.js","snippetPresets-Bsspz-Ge.js","style-to-object-BY3JEAdk.js","v4-DIgz8zy6.js","conditional-requirements-CFM0id0Q.js","ApiExamples-jcs-2nGf.js","isEqual-BfaiBbcl.js","usePlaygroundInputsStore-Dp53in7F.js","shallow-Dv9eUdUd.js","getApiPlaygroundDisplay-D8cDwNhi.js","CodeSnippet-DkwXLQor.js","CodeSnippets-DcSgKqs5.js","Page-t8ynOKTD.js","getPastedJson-I2RjoApV.js","icon-BIj57rZC.js","MethodPill-CTwLPWXC.js","DuplicateIcon-BJpFwygY.js","createIcon-C7PorfAe.js","DynamicMarkdown-BBht_uEs.js","SectionHeading-YIBwxbzj.js","axios-vUo_bRtp.js","Markdown--YCeFtOs.js","clsx-CrPa459s.js","lib-DuNMoZ05.js","lib-B8HbPgcC.js","html-void-elements-mCSPHezU.js","dist-BWxsj3I0.js","katex-YMM-FMeD.js","marked.esm-CZWythHk.js","AssistantPageLink-fBzVvq7k.js"]}