curl --request DELETE \
--url https://studio.weaverse.io/api/v1/content/projects/{projectId}/pages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"type": "CUSTOM",
"handles": [
"pages/old-campaign",
"pages/expired-offer"
]
}
'const options = {
method: 'DELETE',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({type: 'CUSTOM', handles: ['pages/old-campaign', 'pages/expired-offer']})
};
fetch('https://studio.weaverse.io/api/v1/content/projects/{projectId}/pages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://studio.weaverse.io/api/v1/content/projects/{projectId}/pages"
payload = {
"type": "CUSTOM",
"handles": ["pages/old-campaign", "pages/expired-offer"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.delete(url, json=payload, headers=headers)
print(response.text){
"object": "page_delete",
"requested": 2,
"deleted": 1,
"notFound": 1,
"failed": 0,
"deletedHandles": [
"pages/old-campaign"
],
"notFoundHandles": [
"pages/expired-offer"
],
"failedHandles": []
}{
"object": "error",
"code": "UNAUTHORIZED",
"message": "<string>",
"status": 123,
"details": "<unknown>"
}{
"object": "error",
"code": "UNAUTHORIZED",
"message": "<string>",
"status": 123,
"details": "<unknown>"
}{
"object": "error",
"code": "UNAUTHORIZED",
"message": "<string>",
"status": 123,
"details": "<unknown>"
}{
"object": "error",
"code": "UNAUTHORIZED",
"message": "<string>",
"status": 123,
"details": "<unknown>"
}{
"object": "error",
"code": "UNAUTHORIZED",
"message": "<string>",
"status": 123,
"details": "<unknown>"
}Bulk delete pages
Deletes page assignments in a project and soft-deletes each underlying page once it has no remaining live assignments; assignments for other locales or resources keep a shared page live. Only assignments in the project named in the URL are touched.
Identify up to 500 targets with one selector per request:
pageIds: page ids, scoped to this project.handles+type: handles of one page type, with an optionallocale. Whenlocaleis omitted the legacyen-uslocale is used; an empty string is rejected. For custom pages, pass the exact handle from the pages list, including any/.
If both pageIds and handles are present and pageIds is an array, pageIds wins and handles is ignored.
A handles request naming an internal template-marker handle (isTemplateMarker: true on the pages list) is rejected with 400 and deletes nothing, so a bulk delete can never half-apply and strip a custom template’s wiring. Delete such a template by its pageIds instead.
Deletion is consequential: resolve targets with the pages list first and, when acting through an agent, confirm them with the user. Use the response counts and handle lists to find misses (notFound) or per-page failures (failed).
Clients or CDNs that strip DELETE bodies may send POST to the same URL with the same body.
Required scope: content:write and content:delete. A credential with a stored scope list (any delegated grant or a shop API key minted with scopes) without content:delete gets 403 INSUFFICIENT_SCOPE and nothing is deleted. Only shop API keys minted before scopes existed keep this endpoint’s historical delete access.
curl --request DELETE \
--url https://studio.weaverse.io/api/v1/content/projects/{projectId}/pages \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"type": "CUSTOM",
"handles": [
"pages/old-campaign",
"pages/expired-offer"
]
}
'const options = {
method: 'DELETE',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({type: 'CUSTOM', handles: ['pages/old-campaign', 'pages/expired-offer']})
};
fetch('https://studio.weaverse.io/api/v1/content/projects/{projectId}/pages', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));import requests
url = "https://studio.weaverse.io/api/v1/content/projects/{projectId}/pages"
payload = {
"type": "CUSTOM",
"handles": ["pages/old-campaign", "pages/expired-offer"]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.delete(url, json=payload, headers=headers)
print(response.text){
"object": "page_delete",
"requested": 2,
"deleted": 1,
"notFound": 1,
"failed": 0,
"deletedHandles": [
"pages/old-campaign"
],
"notFoundHandles": [
"pages/expired-offer"
],
"failedHandles": []
}{
"object": "error",
"code": "UNAUTHORIZED",
"message": "<string>",
"status": 123,
"details": "<unknown>"
}{
"object": "error",
"code": "UNAUTHORIZED",
"message": "<string>",
"status": 123,
"details": "<unknown>"
}{
"object": "error",
"code": "UNAUTHORIZED",
"message": "<string>",
"status": 123,
"details": "<unknown>"
}{
"object": "error",
"code": "UNAUTHORIZED",
"message": "<string>",
"status": 123,
"details": "<unknown>"
}{
"object": "error",
"code": "UNAUTHORIZED",
"message": "<string>",
"status": 123,
"details": "<unknown>"
}Authorizations
Bearer authentication: a shop API key (WEAVERSE_API_KEY), a scoped API key, a delegated MCP OAuth token, or (translation-unit routes only) a project-bound translation agent token. Scopes: content:read — Read projects, pages, theme settings, versions, drafts and translation units. content:write — Save drafts and make non-destructive edits (page items, metadata, SEO, assignments, languages, glossary). Never publishes or deletes. content:publish — Publish drafts, schedule/reschedule/cancel publications, restore versions, publish global sections. content:delete — Delete pages, global sections, languages, static keys, override reverts; required with project:manage for project deletion. project:manage — Create/copy/delete projects, settings, variants, hierarchy, backups, restore-as-new, previews, hostname policy. translations:read — Read translation units only (no general content access). translations:write — Apply translation units only; never mutates page content. A legacy unscoped API key keeps read/write/translation baseline access and every pre-scope endpoint, but never gains publish/delete/project-manage implicitly.
Path Parameters
Body
- Option 1
- Option 2
500Was this page helpful?