$value, $type, $description, $extensions, and {alias} references.
Livry does not impose a vocabulary
There is no fixed list of names you must use. If your design system calls itsurface.raised.border, that is what you store. Nothing in Livry knows that color.brand means a brand colour.
Token taxonomies are opinionated and product-specific, and a theming service that forced its own onto you would mean writing a mapping layer on both sides — one to publish, one to consume.
What Livry does impose is the format, because the format is what makes typing, aliasing and import-from-anything possible.
$type is inherited, never copied
A group’s $type reaches every descendant that does not declare one.
color.brand resolves to type color without saying so itself.
A token with no declared or inherited type gets one inferred from the value’s shape. The API flags that with inferred: true, so you can tell a guess from a statement.
Aliases
A value of the form{path.to.token} is an alias. It is stored unresolved, so the relationship survives — override the target and everything pointing at it moves too.
color.brand moves all three. This is usually the single highest-leverage thing you can do when modelling a theme for white-labelling: alias aggressively, so a brand has few values to set.
Aliases are resolved when the files are rendered, not when they are stored:
Values by type
DTCG values are not all strings. The common ones:color
color
"#5B4DE4" is accepted on import and normalised into this shape.dimension
dimension
px and rem are the units DTCG defines.fontFamily
fontFamily
Composite types
Composite types
shadow, border, transition, typography, gradient and strokeStyle are objects whose members are themselves typed values — and each member may be an alias.Two DTCG features Livry does not apply
Groups
Only groups that carry something of their own — a$type or a $description — are meaningful. A group implied purely by the paths beneath it tells you nothing the paths do not, which is why the API returns only the former.
Editing
Tokens are edited through operations, never by sending the document. In the portal this is invisible — you edit a tree. Through the API it is explicit: RFC 6902 operations over JSON Pointers for a Theme, andset/unset over dotted paths for a Variant.
The reason is that a whole-document write makes a deletion mean omission, so a client holding a stale copy silently deletes everything added since it read. See Theme tokens.
Prefer
move over remove-and-add when renaming. When a Theme publishes, every Variant under it is migrated onto the new structure. A move says plainly that a rename happened; a remove-and-add pair has to be inferred, and the inference can lose an override. See Versioning.Naming, and what it costs you
Livry cannot validate token names — it has no vocabulary to check them against. A typo is stored faithfully and shows up as a missing custom property at render time. Two things worth doing early:- Settle your vocabulary before your second Variant. Retrofitting a naming convention across many brands is painful, and every rename is a migration.
- Always write a
var()fallback in your CSS, so a missing token degrades to your default rather than to nothing.
Variants
How a brand overrides this document, and what it is not allowed to change.