Public API
https://api.livry.dev/public/v1 — REST, JSON, OAuth 2.0 bearer tokens. Create Themes, edit tokens, publish versions. Called from your backend or your CI, never from a browser.Serving edge
https://cdn.livry.dev — the published files themselves. Called by your app at runtime, at high volume, over a CDN. No bearer token.Base URL
The resource model
Everything is addressed by
id, never by slug. A slug is renameable, and a machine client stores what it was handed. The slug is returned as an ordinary attribute, and ?slug= on a list endpoint is how you turn one into the other.Response shapes
Every response has one of two outermost shapes.Paging
Pages are numbered, not continuation-token. Scripts drain collections and dashboards render “page 3 of 40”; neither can do anything with an opaque cursor.totalCount and totalPages are 0 unless you asked for them, not null. Counting is a second query, and paging a collection needs the count once rather than on every page. A page that has items cannot legitimately have a total of zero, so the pair is unambiguous.
pageCount is always populated — it is the length of items, so you never have to length-check the array to know you have reached the last page.
Conventions
- Timestamps are ISO 8601, UTC —
2026-09-18T04:21:07Z. - Enums are camelCase names, never ordinals:
"react","chakraUI","signed","descending". - Responses are pretty-printed. They are small, and the reader is usually a person with a curl.
- Unknown query parameters are ignored; a parameter that will not convert is a
400naming it.
Concurrency
Token documents are edited through an optimistic-concurrency check. Read the token set, send itsetag back with the write, and a 409 means somebody else got there first — re-read and retry.
The ETag is the draft blob’s, not the entity’s. The token document lives on Blob Storage, so a Cosmos ETag stopped saying anything about whether the tokens had changed. A
null etag is legitimate and means “there is no draft yet” — which is what a first edit on a freshly created Theme sends.?etag=…, not an If-Match header. That is a known wart: the header is the correct idiom and is where it will end up. See Errors.
What this API deliberately does not do
Adding any of these is a decision, not an oversight.