Terminology Overrides
loc-2.v1 is the read side of localization. This is the write side.
The resolution stack ends with a terminology store that beats
every template file. These two endpoints are how entries get into that store — they are the
supported way to re-term Agility through the API, and what they write is what loc-2.v1
subsequently serves.
| Endpoint | Scope | Privilege |
|---|---|---|
api/localization | One key at a time | Authenticated |
api/localizations | Batch read and write | ManageConfig |
One Key at a Time — api/localization
A single route handling four verbs.
GET ~/api/localization?key=<tag>&language=<lang>
POST ~/api/localization?key=<tag>&value=<text>&language=<lang>
PUT ~/api/localization?key=<tag>&value=<text>&language=<lang>
DELETE ~/api/localization?key=<tag>&language=<lang>
language is optional and defaults to the two-letter language of the current UI culture.
POST and PUT do the same thing — both upsert. There is no create-versus-replace
distinction. DELETE removes the override, restoring whatever the template stack resolves to.
Both writes refresh the localizer immediately.
GET returns a bare string, and a missing override is not a 404The response body is the override text itself — not JSON, not an object. When no override exists, the endpoint returns 200 with an empty body, not a 404.
An empty response is therefore ambiguous: it means either "no override is set" or "an override is set to the empty string". If that distinction matters, use the batch endpoint, which returns a keyed object where an absent key is distinguishable from an empty value.
Batch — api/localizations
Note the plural. Different route, different privilege, different shape.
Requires the ManageConfig privilege, which is stricter than the singular route.
GET ~/api/localizations
POST ~/api/localizations
GETThis is unusual and easy to miss. GET here is a read that takes a JSON body describing which
keys to read, not a plain URL fetch. Some HTTP clients and proxies will not send a body on a
GET; if reads come back empty for no obvious reason, that is the first thing to check.
Request
{
"lang": "en",
"keys": ["Story", "Defect"],
"overrides": [
{ "key": "Story", "value": "Backlog Item", "act": "set" },
{ "key": "Defect", "act": "delete" }
]
}
| Field | Description |
|---|---|
lang | Language to operate on. Defaults to the current UI culture's two-letter language |
keys | Keys to read back |
overrides | Changes to apply. POST only |
overrides[].act | set or delete. Defaults to set when omitted |
Response
{
"lang": "en",
"deleted": ["Defect"],
"overridesByKey": { "Story": "Backlog Item" }
}
Unknown Keys Are Rejected
api/localizations validates the shape of the payload strictly. Any top-level key that is
not lang, overrides or keys is an error.
| Error message | Cause |
|---|---|
You must supply a payload. | Empty body |
Unknown payload at <name> | An unrecognised top-level key |
overrides must be an array | overrides is not an array |
Values must be strings | A non-string value |
act must be "set" or "delete" | A non-string act |
A value must be supplied when setting | act: "set" with no value |
All surface as 400, carrying { "errorMessage": … }. Any unexpected server-side exception
is converted to a 400 in the same shape, so a 400 here is not always a validation failure.
Two endpoints reject unknown keys — this one and api/webhook. Others,
including the Bulk API, tolerate them.
Do not carry an assumption either way between surfaces. A payload with a stray field that works against one endpoint can be a hard 400 against another.
Related
- Localization overview — the read side
- Template sets — where overrides sit in the resolution stack
- Hot reload — why a change may not be visible to clients immediately