API

The JSON API

Every page here has a JSON counterpart. No key and no sign-up. Start at the root and follow the links, or read the OpenAPI description and generate a client.

What it serves

The API mirrors the content tree. The twelve traditions, the principles distilled from each, their source books, the cross-tradition comparison layer, the union compass, and the corpus's own review status are all addressable as JSON. Where a document is long-form prose, the response carries it as markdown rather than splitting it into fields the corpus does not actually have.

It is read-only. Only GET is served, every response is public, and the content is licensed CC BY-SA 4.0.

No endpoint takes a request body, a header or a query parameter — the path is the whole request. The same URL always returns the same bytes, which is also why the language lives in the URL rather than in a header.

The envelope

Every response has the same three top-level keys, so a client can treat any endpoint the same way and can reach the whole tree knowing only the root URL.

data
The payload, and the only part whose shape changes between endpoints. An object on most of them; an array on the two collections, which list the traditions and one tradition's source books.
_links

Named links to related endpoints. Each has a href, and usually a rel describing the relationship.

  • self — this endpoint's own address, on every response
  • parent — one step back up the tree
  • html — the human-readable page carrying the same content, in the same language as the response
  • alternate — on the root, one per language: the same API in each of the nine locales, so the whole tree is reachable by following links rather than by guessing a URL
  • _links — each entry in a collection carries its own block of these, so a list is also a set of addresses
_meta

The same three fields on every response.

  • lang — the language of this document — the locale of the tree it came from, not a language negotiated per request
  • license — the content license, CC BY-SA 4.0
  • apiVersion — the API version, currently 1.0

The OpenAPI description also lists two optional fields on this object, for an entity tag and a last-modified date. Nothing sets either one today, so treat both as absent rather than as sometimes-missing.

A whole response, verbatim. This one is small enough to show entire; the endpoints that carry corpus documents run to tens of thousands of characters. /api/map.json
{
  "data": {
    "name": "Cross-Tradition Map",
    "description": "29 convergence themes, 13 held tensions, 41 preserved jewels across 12 traditions.",
    "themeCount": 27,
    "tensionCount": 13,
    "jewelCount": 41
  },
  "_links": {
    "self": {
      "href": "/api/map.json",
      "rel": "self"
    },
    "parent": {
      "href": "/api.json",
      "rel": "parent"
    },
    "convergence": {
      "href": "/api/map/convergence.json",
      "rel": "collection"
    },
    "divergence": {
      "href": "/api/map/divergence.json",
      "rel": "collection"
    },
    "jewels": {
      "href": "/api/map/jewels.json",
      "rel": "collection"
    },
    "html": {
      "href": "/en/map",
      "rel": "alternate",
      "type": "text/html"
    }
  },
  "_meta": {
    "lang": "en",
    "license": "CC BY-SA 4.0",
    "apiVersion": "1.0"
  }
}

Endpoints

Thirteen shapes. Three of them take a tradition slug, and one of those also takes a book identifier, so there are many more distinct URLs than rows.

Eleven of the thirteen also exist under a language prefix. The last column says which, and the section on languages below says what that does and does not get you.

EndpointReturnsPer language
/api.jsonThe root index. Every other endpoint is reachable from its links, including the root of each of the nine languages.yes
/api/traditions.jsonAll twelve traditions with scripture, principle count and links onward.yes
/api/traditions/{slug}.json example /api/traditions/taoism.jsonOne tradition — its scripture, how many principles were distilled from it, how many source books it has. Twelve of these.yes
/api/traditions/{slug}/principles.json example /api/traditions/taoism/principles.jsonThat tradition's distilled principles, as markdown. Twelve of these.yes
/api/traditions/{slug}/books.json example /api/traditions/taoism/books.jsonThe tradition's source books, each with a one-line summary and its own address. Twelve of these.yes
/api/traditions/{slug}/books/{id}.json example /api/traditions/taoism/books/ttc-ch01-10.jsonOne source book, with the statements read out of it verse by verse. One per book in the corpus; ask the collection above rather than assuming a count. English in every language, for the reason given below.no
/api/map.jsonThe comparison layer's index, with the counts of themes, tensions and preserved terms.yes
/api/map/convergence.jsonThe convergence matrix, plus the analysis separating a shared claim from the differing reasons traditions give for it.yes
/api/map/divergence.jsonThe held tensions — the points where traditions genuinely contradict one another and the contradiction is left standing.yes
/api/map/jewels.jsonThe terms kept in their own language, with the union compass and the structural analysis they sit in.yes
/api/compass.jsonThe full union compass as markdown, which is the form to paste into an AI assistant.yes
/api/review-status.jsonWhere verification stands, per tradition: whether quotes have been checked, and whether a reviewer from inside that tradition has been secured. Read this before describing the corpus as authoritative.yes
/api/openapi.jsonThe description of everything above, covering both trees. There is one of these, not one per language.no

Nothing else is served under this path. If an endpoint is not listed here it does not exist, and the root index is the authority — it links only to endpoints that resolve.

Trying it

The root index is the place to start — it is small, and every other endpoint hangs off it, including the root of each language.

curl -s https://distill.family/api.json

OpenAPI description

An OpenAPI 3.1 document describes every endpoint above, together with the envelope and link schemas. Point a generator at it, or just read it.

/api/openapi.json

The language-prefixed endpoints are written out one locale at a time rather than left as a template. A generated client cannot substitute into a template it has no list for, and the build check that asserts every documented path really resolves cannot follow one either — so enumerating them keeps the whole localized tree under that assertion.

It is deliberately not rendered here in an interactive explorer. This site sends a content security policy that permits scripts, styles and network connections only from its own origin, and the explorers all load from somewhere else — so embedding one would either silently fail or mean weakening that policy for every visitor. Fetch the document and open it in a tool you already trust.

Languages

There are two trees serving the same endpoints. The canonical one is English. The other carries a language prefix and is built once for each of the nine languages the site supports.

/api/es.json

The language is a path segment, not a negotiation. A query parameter is not read and the Accept-Language header is not read — and that is a design decision rather than an omission. Every endpoint is prerendered: the handler runs once at build time, with no request to negotiate against, and the resulting file is then served to everyone. A response that cannot vary by header has to carry its language in the URL, where it is addressable, linkable and cacheable.

A language segment that is not one of the nine returns 404. It would be worse to serve English under another language's URL and let a caching layer keep it there — the whole point of putting the language in the path is that the address tells the truth about what came back.

There is a second reason to validate it. Whatever the language resolver returns is used to build a filesystem path when the corpus is read, so a value taken straight from a request would be a way to ask for files outside the content tree. The resolver checks against the closed list of supported languages before returning anything, so it cannot emit a segment that is not one of them however it is called. The 404 above is about honesty; this is the part that is about safety.

One layer is not translated at all. The individual source books are English everywhere, because no translation of them exists — so those endpoints are served only from the English tree, and a language-prefixed book collection links each entry back to the English document, which reports as much about itself.

Elsewhere, translation is per document rather than per tree. Every response carries a flag saying whether the document it holds was translated, and a document with no translation in that language falls back to English rather than returning nothing. So read the flag rather than the URL.

And read the flag narrowly. It records that a translation exists and that nothing load-bearing was lost from it — headings, quotations, citations, preserved terms are all checked for presence. It does not record that the translation is accurate. No native speaker has reviewed any of this corpus. A translated document is best treated as a serviceable rendering, not as verified text, and the root endpoint says so in its own response rather than leaving a client to find out.

Headers and caching

Cross-origin requests are allowed from any host, so a page served from anywhere can fetch these directly. Only GET and OPTIONS are advertised.

Responses are cacheable for five minutes in a browser and an hour in a shared cache. They are static files behind a static file server, which sends a weak entity tag with each one, so conditional requests work.

Using it

The distilled content is licensed Creative Commons Attribution-ShareAlike 4.0 (opens in a new tab). Use it, quote it, build on it — attribute Distill.family, and license what you build the same way. Scripture quotations come from public-domain editions, attributed inline where a specific translation was relied on.

Two things to carry along with the data. Quotations are verified character by character against those editions, but no scholar from inside any of the twelve traditions has signed off on these readings; the review-status endpoint reports exactly where that stands, tradition by tradition.

And the standpoint is owned, not neutral. The traditions are treated here as potentially complementary partial views, which most of them reject. Anything built on this data inherits that choice, so it is better restated than passed on silently.