Skip to main content
A Theme’s token set is a W3C DTCG document — nested groups, $value, $type, $description, $extensions, and {alias} references left unresolved. See Tokens. All paths are under /public/v1/environments/{environmentID}.

The draft-and-versions model

A Theme holds zero or one draft and N immutable versions.
1

An edit creates the draft

The first PATCH that changes something creates a draft. An edit that reverted itself leaves nothing behind, so hasUnpublishedChanges is exactly “is there a draft”.
2

Publishing freezes it

POST …/publish writes the draft as the next version and deletes the draft. Version numbers start at 1 and never skip.
3

Versions are never editable

Nothing in Livry can write an existing version. A pinned URL’s content cannot change.
DELETE …/tokens throws the draft away and leaves every version alone. It is a discard, not a deletion of the Theme’s tokens.

Read the tokens

integer
Read a specific published version instead of the current document. Omit for “what is current” — the draft if there is one, otherwise the newest version.
boolean
default:"false"
Also list every published version number, newest first. Listing costs a storage request of its own, which is why it is opt-in.
Response 200

Reading that response

string | null
The concurrency token for your next write, and it is the draft’s — not the Theme entity’s. null means there is no draft, which is what a first edit legitimately sends.
array
Every token, flattened onto a dotted path, depth-first in document order. Not sorted — the order is the document’s.
array
Only the groups that carry metadata of their own. A group implied purely by the paths beneath it tells you nothing the paths do not, and listing every one would roughly double the payload. A group with a $type is the case this exists for: that type is a statement about every token under it, and it is not recoverable from the paths.
type and resolvedType are two different questions, and you may only write the first.type is the token’s own $type, null when it inherits one from a group. resolvedType is what the token actually is after inheritance and inference.Writing resolvedType back — materialising an inherited type onto the token — stops its group ever retyping its children. The API will let you; the document will be wrong. Address /…/$type.
inferred tells you whether resolvedType was guessed from the value’s shape rather than declared anywhere.

Edit the tokens

Tokens are edited through operations, never by sending the document. A whole-document write makes a deletion mean omission, so a client holding a stale copy would silently delete everything added since it read. The batch is applied to what is current, and the stored patch is re-derived from the result — so your call is additive while the stored file stays the minimal distance from the version below it.
Returns the whole token set as it stands afterwards, including the new etag your next write needs.

The operations

These are RFC 6902’s five, addressed by RFC 6901 JSON Pointers. They are not our invention and we have not renamed them. A pointer addresses the document, so /color/brand/primary is the token and /color/brand/primary/$value is its value. Escape / as ~1 and ~ as ~0, as RFC 6901 requires.
Prefer move over remove-and-add for a rename. When a Theme publishes, every Variant beneath it is migrated onto the new structure — keys the Theme renamed are renamed, keys it removed are dropped. A move says plainly that a rename happened; a remove-and-add pair has to be inferred, and the inference can lose an override when the rename also changed the value.

Publish a version

No body. Returns the Theme — with latestVersion set to the version just written and hasUnpublishedChanges back to false. Publishing also:
  • writes the served files for every (Theme, Variant) pair at the new version, and moves latest;
  • migrates every Variant’s draft onto the new structure, renaming the keys the Theme renamed and dropping the ones it removed or retyped past fitting.
Migration corrects each Variant’s draft. It does not publish them. After a Theme publish, your Variants have unpublished changes they did not ask for — review and publish each one.

Discard the draft

Throws the draft away and returns the Theme. Published versions are untouched. Send the etag so you cannot discard a draft that changed under you.

Two DTCG features Livry does not apply

$extends (group inheritance) and $ref (JSON Pointer references, including into a value) are preserved verbatim so documents round-trip, but their semantics are never applied. A document that relies on either will import with tokens missing, and nothing will warn you.Aliases — {color.brand.primary} — are supported, and are resolved in the served tokens.json, tokens.css and tokens.flat.json. tokens.dtcg.json keeps them as written.