curl --request POST \
--url https://studio.weaverse.io/api/v1/content/projects/{projectId}/page-translations/{pageId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"locale": "fr-fr",
"translations": [
{
"itemId": "clz8k3d2e0008poiu7ytr6ewq",
"key": "data.buttonText",
"source": "Shop now",
"translation": "Acheter maintenant",
"targetGeneration": null
}
]
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
locale: 'fr-fr',
translations: [
{
itemId: 'clz8k3d2e0008poiu7ytr6ewq',
key: 'data.buttonText',
source: 'Shop now',
translation: 'Acheter maintenant',
targetGeneration: null
}
]
})
};
fetch('https://studio.weaverse.io/api/v1/content/projects/{projectId}/page-translations/{pageId}', 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}/page-translations/{pageId}"
payload = {
"locale": "fr-fr",
"translations": [
{
"itemId": "clz8k3d2e0008poiu7ytr6ewq",
"key": "data.buttonText",
"source": "Shop now",
"translation": "Acheter maintenant",
"targetGeneration": None
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"object": "page_translations_update",
"projectId": "clz8k2m4n0001qwer7tyu8iop",
"pageId": "clz8k3a1b0004asdf5ghj6klz",
"language": {
"id": "clz8k2x7y0003lkjh4gfd3sap",
"code": "fr-fr"
},
"requested": 1,
"applied": 1,
"stale": 0
}{
"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>"
}{
"object": "error",
"code": "UNAUTHORIZED",
"message": "<string>",
"status": 123,
"details": "<unknown>"
}Apply translations for one page and locale
Writes translation overrides for an owned page and one configured, non-default target locale. Send the entries read from GET with translation replaced; source and targetGeneration must be the values GET returned.
- Only
Translationrows change. Base page content, its items and every other locale are untouched. - The project default language is rejected (400): it is the source other locales translate from.
- Each entry is compare-and-set on both its
sourceand itstargetGeneration, so a delayed agent can never overwrite a source the merchant edited or a newer translation another writer stored. Refused entries are counted instaleand were not written; re-read and resubmit them.applied + stale = requested. translation: ""clears a key, keeping the tombstone row that distinguishes “cleared” from “never translated”.targetGenerationis required on every entry (nullwhenGETreturnednull); omitting it is a 400, not a blind write.- At most 250 entries per request; duplicate
itemId+keypairs are rejected. - A request that applies nothing advances no project revision and flushes no cache.
- If the write committed but cache invalidation failed, the response is a 500 whose message states how many entries were applied. Verify with
GET; retrying the same entries will not flush the cache, because they then lose the target compare-and-set as no-ops.
Required scope: content:write
curl --request POST \
--url https://studio.weaverse.io/api/v1/content/projects/{projectId}/page-translations/{pageId} \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"locale": "fr-fr",
"translations": [
{
"itemId": "clz8k3d2e0008poiu7ytr6ewq",
"key": "data.buttonText",
"source": "Shop now",
"translation": "Acheter maintenant",
"targetGeneration": null
}
]
}
'const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
locale: 'fr-fr',
translations: [
{
itemId: 'clz8k3d2e0008poiu7ytr6ewq',
key: 'data.buttonText',
source: 'Shop now',
translation: 'Acheter maintenant',
targetGeneration: null
}
]
})
};
fetch('https://studio.weaverse.io/api/v1/content/projects/{projectId}/page-translations/{pageId}', 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}/page-translations/{pageId}"
payload = {
"locale": "fr-fr",
"translations": [
{
"itemId": "clz8k3d2e0008poiu7ytr6ewq",
"key": "data.buttonText",
"source": "Shop now",
"translation": "Acheter maintenant",
"targetGeneration": None
}
]
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text){
"object": "page_translations_update",
"projectId": "clz8k2m4n0001qwer7tyu8iop",
"pageId": "clz8k3a1b0004asdf5ghj6klz",
"language": {
"id": "clz8k2x7y0003lkjh4gfd3sap",
"code": "fr-fr"
},
"requested": 1,
"applied": 1,
"stale": 0
}{
"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>"
}{
"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.
Body
Target locale, resolved through the same language identity the storefront uses. Must be a configured, non-default language.
Entries echoed from GET with translation replaced. source and targetGeneration must be the values GET returned.
250Show child attributes
Show child attributes
Response
Decision for the whole batch. applied + stale = requested; a non-zero stale means those keys must be re-read and resubmitted.
page_translations_update Show child attributes
Show child attributes
Entries that passed both the source and target compare-and-set and were written.
Entries refused because the source or the target moved since the read. Re-run GET and resubmit those keys; they were NOT written.
Was this page helpful?