A draft, then a publish
account.theme.get returns three things: what is published, what is drafted, and the defaults, along with the full list of token and copy keys — so a form can be built from the response rather than from a list copied into your own code.
account.theme.set saves a draft and may be called with a test key. account.theme.publish is what changes anything anybody sees, and account.theme.reset puts it back; both are refused from a test key with live_only, because both change what live users receive.
Send only what you are changing. A key you leave out keeps its value, and a key set to null drops your override so Lath’s default shows through again — which is how you undo one colour without restating the other nineteen.
One theme for the project, both environments
A theme belongs to the project, not to an environment: live and test share it. That is deliberate — a brand is not a per-environment setting — but it means a draft saved with a test key and then published is published for live users too. The hosted pages read the published theme from a public endpoint keyed by environment id, which needs no key because a sign-in page is read by people who have not signed in yet. It answers with defaults filled in and is cached for a minute, so a publish takes up to that long to appear.What the tokens are
Twenty, all strings: backgrounds and surfaces, two border weights, three text tones, the primary action and its foreground, a focus ring, two danger colours, a UI font and a mono font, three radii, and a logo URL. Colours are six-digit hex and nothing else — no three-digit form, norgb(), no colour names, no alpha. Radii are whole pixels. An unknown key is refused rather than ignored, so a typo in a token name fails loudly instead of silently doing nothing.
The logo is a URL. There is no upload, and no size is enforced on write — but the email frame caps it at 28 pixels tall and 180 wide, so supply something that survives that.
The contrast check is a refusal, not a warning
Seven pairs have to reach WCAG AA — 4.5:1 — before a theme saves: both text tones on the canvas and on a surface, the faint tone on the canvas, the action’s foreground on the action, and the danger tone on a surface. Below that the write is refused withcontrast_too_low.
The refusal names every failing pair with its measured ratio and a nearby colour that would pass, found by mixing toward black or white until it does. It is the one validation here that does your next step for you rather than leaving you to guess.
Borders are deliberately not checked: a hairline that is hard to see is a choice, and text that is hard to read is not.
Dark mode, and the moment you lose it
Lath ships a dark palette, and a project still on the default colours gets it: the hosted page emits no colour variables at all, so the visitor’s own light or dark setting decides. Change any one colour and that stops. From then on your palette is what every visitor sees, on every device, and the page pins its colour scheme to match your canvas. There is no second palette to fill in — so a brand colour chosen against a white page is the page a dark-mode visitor gets too.The words, and where they do not reach
A few hundred copy keys cover the hosted pages end to end — sign-in, sign-up, codes and links, passkeys, two-step, recovery, profile, organizations, preferences — each capped at 500 characters, each interpolating{name}-style placeholders where it takes one. account.theme.get returns every key and its default, so the list never has to be kept in two places.
Email wears the same theme, but only the published one and only where a template asks for the frame; a template that does not opt in is sent exactly as written. The page-language key applies to the hosted pages alone — the email frame is English, stated in its markup.
Text messages are not themed at all. The single theme value an SMS touches is the unsubscribe word appended to marketing text.
One copy key blocks sending rather than decorating it: the legal postal address is empty by default, and marketing email will not go out until it is set and published.
