---
title: "List translation units for a target locale"
method: GET
path: "/projects/{projectId}/translation-units"
tags: ["Translations"]
---

# List translation units for a target locale

`GET /projects/{projectId}/translation-units`

## Request

- Base URL: `https://studio.weaverse.io/api/v1/content`
- URL: `https://studio.weaverse.io/api/v1/content/projects/{projectId}/translation-units`
- Auth: HTTP bearer

Project-wide translation inventory for one target locale: every unit an agent may translate, with opaque ids, source and target generations, context, storefront usages and a status summary. This is the first step of the translation-unit workflow:

1. `GET /translation-units?targetLocale=…` (optionally `status=missing,stale`) and page with `after=<nextCursor>` while `hasMore` is `true`.
2. `POST /translations/validate` with the units you translated: every check runs, nothing is written, and each unit reports `apply` or `unchanged`.
3. `POST /translations/apply` with the same body: the checks re-run under the project lock and the batch is written atomically (compare-and-set on both generations).
4. Use the `readback` in the apply response, or list again, to confirm.

What is listed:
- Units of the pages the target locale actually renders, resolved with the storefront cascade. Items shared by several pages (global sections) appear once, with every route in `usages`.
- Only fields the stored project schema approves: text, richtext and textarea inputs and their defaults. Components without a stored schema, and fields of other input types, are never listed or writable.
- `kind=text` (default) lists text units; `kind=image` lists per-locale image overrides at declared image inputs, on the same protocol with an image object as the value.
- `summary` counts `current`, `missing` and `stale` across all units of the requested kind (before the `status` filter), plus `excluded`: pages the locale renders that this project cannot write (inherited from a parent project or shared with another project).
- A target is `missing` when no row exists or it was cleared, and `stale` when the stored translation answers a source that has since changed.
- `usages` lists only concrete storefront paths and may be empty for templates, articles and system pages. Paths use the default route prefixes; a custom page prefix configured in Studio is not reflected.

Behaviour:
- Ordering is deterministic (by unit id). `limit` is 1-100 (default 100); `after` is a strict lower bound, so a cursor naming a unit that has since disappeared still resumes correctly.
- `status` accepts a comma-separated list or repeated parameters.
- `targetLocale` must be a configured, non-default language (400 otherwise).
- Uncached by design: it carries the generations a write compare-and-sets against.

Authentication: accepts shop API keys, scoped API keys and delegated MCP OAuth tokens that hold the scope, and project-bound translation agent tokens (`wv_agent_…`, Authorization header only). Agent tokens are accepted only by this route and `POST /translations/{operation}`; a token bound to another project gets 403.

Required scope: `translations:read`

## Response `200`

Deterministic, cursor-paged units with summary

- object

## Other responses

- `400`: Unconfigured locale
- `401`: Missing or invalid credentials
- `403`: Foreign project or missing scope (INSUFFICIENT_SCOPE)
- `404`: Not found (never discloses other tenants)

---

[API](https://skmtc.dev/weaverse/apis/weaverse-content-api.md) - [All operations](https://skmtc.dev/weaverse/apis/weaverse-content-api/llms.txt) - [OpenAPI document](https://skmtc.dev/weaverse/apis/weaverse-content-api/revisions/d189794169bb?raw)
