Skip to main content

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.

EndpointScopePrivilege
api/localizationOne key at a timeAuthenticated
api/localizationsBatch read and writeManageConfig

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.

warning
GET returns a bare string, and a missing override is not a 404

The 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
note
Both verbs take a request body, including GET

This 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" }
]
}
FieldDescription
langLanguage to operate on. Defaults to the current UI culture's two-letter language
keysKeys to read back
overridesChanges to apply. POST only
overrides[].actset 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 messageCause
You must supply a payload.Empty body
Unknown payload at <name>An unrecognised top-level key
overrides must be an arrayoverrides is not an array
Values must be stringsA non-string value
act must be "set" or "delete"A non-string act
A value must be supplied when settingact: "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.

Strictness is not consistent across Agility

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.