Read the source library, programmatically
Every book in the Lineage of Legends shelf AND every speech in the mirrored Sun Myung Moon + FFWPU archive is exposed over a small JSON API — 322 books and 19,245 speeches in one read-only surface. Free, no auth, rate-limited per IP. CORS is open so you can call from a browser too.
Rate limits
Per IP, fixed window per minute:
contentbucket — 60 req/min. Covers/api/v1/books*and/api/v1/speeches*endpoints.searchbucket — 10 req/min. Covers/api/v1/search.
Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. When you exceed the bucket you get a 429 with a Retry-After header.
/api/v1/booksbucket: contentList every book in the library — slug, title, author, source code, page count, and cover image URL.
curl https://www.lineage-of-legends.com/api/v1/books
{
"count": 322,
"books": [
{
"slug": "divine-principle",
"title": "Exposition of the Divine Principle",
"author": "Hyo Won Eu (compiled), HSA-UWC",
"source": "DP96",
"pageCount": 295,
"coverUrl": "/covers/divine-principle.jpg"
},
…
]
}/api/v1/books/{slug}bucket: contentGet a single book's metadata plus its full chapter list. Each chapter carries the paragraph id of its first paragraph — pass that to the text endpoint to stream chapter contents.
- slug*
- The book slug, e.g. "divine-principle".
curl https://www.lineage-of-legends.com/api/v1/books/divine-principle
{
"slug": "divine-principle",
"title": "Exposition of the Divine Principle",
"author": "Hyo Won Eu (compiled), HSA-UWC",
"pageCount": 295,
"paragraphCount": 8423,
"chapters": [
{ "number": 1, "title": "The Principle of Creation", "page": 30, "firstParagraphId": "p-30-1" },
…
],
"textUrl": "/api/v1/books/divine-principle/text"
}/api/v1/books/{slug}/textbucket: contentStream paragraphs from a book. Pass `from` and/or `to` paragraph ids to slice; otherwise you get the first 200 paragraphs. Hard cap of 500 paragraphs per response when both bounds are set.
- from
- Inclusive start paragraph id (e.g. "p-30-1").
- to
- Inclusive end paragraph id. If omitted, returns 200 paragraphs from `from`.
curl 'https://www.lineage-of-legends.com/api/v1/books/divine-principle/text?from=p-30-1&to=p-45-2'
{
"slug": "divine-principle",
"from": "p-30-1",
"to": "p-45-2",
"count": 142,
"totalCount": 8423,
"truncated": false,
"nextFrom": null,
"paragraphs": [
{ "paraId": "p-30-1", "page": 30, "text": "Chapter 1" },
…
]
}/api/v1/speechesbucket: contentPaginated list across the 19,245-speech corpus. Filter by author (canonical display name), route_author (on-disk folder slug), year, decade, or free-text query. Meta only — fetch a single speech's text via the per-speech endpoint.
- author
- Canonical display_author, e.g. "Sun Myung Moon".
- route_author
- On-disk folder slug, e.g. "sunmyungmoon11".
- year
- Filter by date_guess starting with YYYY.
- decade
- Filter by decade, e.g. "1970s".
- q
- Case-insensitive substring on title + author.
- limit
- Per-page size, 1–200 (default 50).
- offset
- Pagination offset (default 0).
curl 'https://www.lineage-of-legends.com/api/v1/speeches?author=Sun%20Myung%20Moon&decade=1970s&limit=2'
{
"count": 2,
"total": 1284,
"offset": 0,
"limit": 2,
"hasMore": true,
"nextOffset": 2,
"filters": { "author": "Sun Myung Moon", "decade": "1970s", … },
"speeches": [
{
"slug": "the-way-our-family-must-go",
"routeAuthor": "sunmyungmoon77",
"author": "Sun Myung Moon",
"rawAuthor": "SunMyungMoon77",
"title": "The Way Our Family Must Go",
"dateGuess": "1977-10-23",
"sourceUrl": "https://tparents.org/…",
"sourceKind": "htm",
"wordCount": 4912,
"textUrl": "/api/v1/speeches/sunmyungmoon77/the-way-our-family-must-go"
},
…
]
}/api/v1/speeches/authorsbucket: contentSpeaker index — one row per canonical display_author with the count of speeches in the corpus. Use it to discover speakers without paginating the full /speeches list.
curl https://www.lineage-of-legends.com/api/v1/speeches/authors
{
"count": 412,
"totalSpeeches": 19245,
"authors": [
{ "author": "Sun Myung Moon", "routeAuthor": "sunmyungmoon", "count": 12871 },
{ "author": "Hak Ja Han", "routeAuthor": "hakjahan", "count": 1442 },
…
]
}/api/v1/speeches/{author}/{slug}bucket: contentFull transcript of one speech — metadata plus the polished paragraph array (logistics stripped, typography normalised). `author` is the on-disk folder slug (`routeAuthor` in the list response).
- author*
- On-disk folder slug, e.g. "sunmyungmoon77".
- slug*
- Speech slug.
curl https://www.lineage-of-legends.com/api/v1/speeches/sunmyungmoon77/the-way-our-family-must-go
{
"slug": "the-way-our-family-must-go",
"routeAuthor": "sunmyungmoon77",
"author": "Sun Myung Moon",
"rawAuthor": "SunMyungMoon77",
"title": "The Way Our Family Must Go",
"dateGuess": "1977-10-23",
"sourceUrl": "https://tparents.org/…",
"wordCount": 4912,
"paragraphCount": 87,
"paragraphs": [ "…", "…", … ],
"anchorPrefix": "p-"
}/api/v1/searchbucket: searchSearch across the whole corpus. `results` are book-level hits (title, author, chapter heading); `passages` are body-text hits with a highlighted snippet and deep-link paragraph id. Multi-term queries require every term to match. The body-text index builds lazily on first call (~5-10s cold start) and is cached for the process lifetime — pass ?body=0 to skip passage search.
- q*
- Query string. 1–100 chars, up to 6 terms.
- body
- 0 to skip body-text passage search and only return book-level matches. Default 1.
curl 'https://www.lineage-of-legends.com/api/v1/search?q=true+parents+heart'
{
"query": "true parents heart",
"count": 18,
"results": [ /* book-level hits */ ],
"passages": {
"count": 24,
"results": [
{
"slug": "cheon-seong-gyeong",
"bookTitle": "Cheon Seong Gyeong",
"paraId": "p-142-3",
"page": 142,
"snippet": "…the **heart** of **true parents** flows through every…",
"score": 2
},
…
]
}
}Stability + versioning
This is v1. We won't make breaking changes to response shapes inside /api/v1/* — new fields may be added but existing ones won't be renamed or removed. Bigger changes ship under /api/v2.
Found a bug or want a new endpoint? Open an issue at github.com/hexgeta/uc-timeline.