Reference data reference

Lookup type
| Field | Accepts | Default | Changeable | What it does |
|---|---|---|---|---|
name | 1–255 chars | — | No | Identifies the list wherever configuration refers to it. |
displayName | 1–255 chars | — | Yes | What people read in the console. |
description | Up to 2,000 chars | — | Yes | Free text. |
isHierarchical | true or false | false | Yes | Whether values may reference a parent value, forming a tree. |
lifecycleState | draft, active, retired | active | Yes | Where the list is in its life. A draft list can be built up before anything binds to it; a retired one stops being offered. |
versionLabel | 1–32 chars | v1 | No | Which published version of the list this is. |
metadata | An object | {} | Yes | Your own annotations, stored and returned uninterpreted. |
A new list is active unless you say otherwise. If you are assembling a
vocabulary and do not want it bound to attributes mid-build, create it as
draft and promote it when the values are in place.
Lookup value
| Field | Accepts | Default | Changeable | What it does |
|---|---|---|---|---|
lookupTypeId | A lookup type | — | No | Which list the value belongs to. A value cannot move between lists. |
code | 1–100 chars | — | No | What is stored on records. See the warning below. |
label | 1–500 chars | — | Yes | Display text. Freely changeable — the code is what records hold, so renaming a label rewrites nothing. |
parentValueId | Another value, or empty | — | Yes | The parent in a hierarchical list. Empty means a root, and clearing it moves the value back to the root. |
sortOrder | Integer, 0 or greater | 0 | Yes | Presentation order within its level. |
isActive | true or false | true | Yes | Whether the value is offered for new data. Retired values keep resolving on existing records. |
effectiveFrom | A timestamp | — | Yes | When the value becomes valid. |
effectiveTo | A timestamp | — | Yes | When it stops being valid. |
metadata | An object | {} | Yes | Your own annotations, stored and returned uninterpreted. |
Labels in other languages are not a field on the value — they are a separate child resource, so one value carries one label per language without the value itself changing.
code is what every record stores. It cannot be edited, and the restriction is
load-bearing rather than cautious: labels are resolved by looking up the stored
code in its list, so a changed code would leave every existing record pointing
at a value that no longer exists — rendering a bare code where a name should
be, on data that was correct when it was written.
If a code is genuinely wrong, add the correct value and migrate the records onto it. Get codes right at the start; treat them as permanent from the moment the first record uses one.
Label resolution deliberately ignores the active flag and the effective window. A retired code on a historical record must still display its label — the alternative is a record that silently loses meaning because a vocabulary moved on.
Transcoding
| Setting | Notes |
|---|---|
| Lookup type | Which list the mapping targets |
| Source system | Whose codes are being mapped |
| Source value | The incoming code |
| Canonical value | The value it becomes |
Mappings are per source system, so two systems can map different codes onto the same canonical value without ambiguity.
A mapping as the shipped banking pack authors it:
{ "lookupType": "account_types",
"sourceSystem": "core_banking",
"sourceValue": "CHK",
"canonicalCode": "checking" }
The core banking system calls it CHK. The canonical list calls it checking.
Neither system has to change, and nothing downstream — matching, search,
reporting — ever sees CHK.
The per-source-system scoping is what makes that safe. CHK from core banking
and CHECKING from a card processor both resolve to checking, while the same
literal string arriving from two systems can legitimately mean two different
things and still be mapped correctly.
The mapping is consulted when a record is created or patched individually and the caller identified its source system. A bulk load resolves codes strictly and directly, so translate values before submitting them at volume — an unmapped code there fails the load rather than being silently converted.
Hierarchies
| Concept | Notes |
|---|---|
| Hierarchy | A named levelled structure |
| Level | An ordered tier within it |
| Node | A position, referencing a lookup value |
| Rollup | Aggregation from a level upward |
Two distinct concepts share the word "hierarchy" and are worth keeping apart:
| What it is | Used for | |
|---|---|---|
| Value tree | A lookup value referencing a parent value | Constraining permitted values |
| Levelled hierarchy | A named structure with ordered levels | Classification and rollup |
Deletion guard
A lookup value in use cannot be deleted. The platform reports which records reference it rather than cascading, because cascading here would silently rewrite governed data.
Next
Last verified against commit a0765982 (2026-08-03)