Read the archive, programmatically
Three corpora — 322 books, 19,245 speeches, and a growing testimony collection — exposed over a small, uniform JSON API. Same filter contract everywhere (title, author, date, word-count, tags, format), open CORS, rate-limited per IP. Free, no auth. See the legacy /api/v1 landing for an older summary; this page is the current reference.
Rate limits + CORS
Per-IP, fixed window — values come from lib/rate-limit.ts:
contentbucket — 60 req per 60s. Covers /api/v1/books*, /api/v1/speeches*, /api/v1/testimonies*, /api/v1/everything.searchbucket — 10 req per 60s. Covers /api/v1/search (the body-indexed corpus search).
Every response carries X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. On overrun you get a 429 with Retry-After. CORS is open (Access-Control-Allow-Origin: *) so you can call from a browser too.
Several list endpoints accept ?format=jsonl (one JSON object per line, no trailing newline — easy to stream-parse) or ?format=csv (RFC 4180, quotes doubled). The CSV/JSONL responses are the row slice only — no pagination envelope, since CSV consumers expect rows.
Books
The 322-volume Unification source library. Title/author filters, word-count ranges, sortable, CSV/JSONL export.
/api/v1/booksbucket: content · cache: 300sPaginated list of every book with the shared common-filter contract. Word counts are only computed when filtered or sorted by length (see q below); the field is null otherwise.
Query params
- q
- stringSubstring across title + author. Case-insensitive.e.g.
q=peace - q_title
- stringTitle-only substring.e.g.
q_title=divine - q_author
- stringAuthor-only substring.e.g.
q_author=moon - author
- stringExact (case-insensitive) author match.e.g.
author=Sun%20Myung%20Moon - min_words
- integerMinimum word count.e.g.
min_words=10000 - max_words
- integerMaximum word count.e.g.
max_words=50000 - has_book
- booleantrue → only books with at least one chapter parsed out.e.g.
has_book=true - sort
- enum— alphabetical | length_asc | length_descSort order. Date sorts do not apply to books (no per-book date in the corpus).e.g.
sort=length_desc - limit
- integer1..200, default 50.e.g.
limit=10 - offset
- integer>= 0, default 0.e.g.
offset=10 - format
- enum— json | jsonl | csvResponse format. Default json (envelope). jsonl/csv ship just the row slice.e.g.
format=csv
Example
curl 'https://wiki.lineage-of-legends.com/api/v1/books?author=Sun%20Myung%20Moon&sort=length_desc&limit=2'{
"count": 2,
"total": 47,
"offset": 0,
"limit": 2,
"hasMore": true,
"nextOffset": 2,
"filters": { "author": "sun myung moon", "sort": "length_desc", ... },
"books": [
{ "slug": "cheon-seong-gyeong", "title": "Cheon Seong Gyeong", "author": "Sun Myung Moon", "source": "CSG", "pageCount": 2542, "coverUrl": "/covers/cheon-seong-gyeong.jpg", "hasCover": true, "wordCount": 1024812 },
...
]
}/api/v1/books/{slug}bucket: content · cache: 300sSingle book meta + chapter list. The chapter rows carry the paragraph id of the first paragraph in each chapter — pass them to /api/v1/books/{slug}/text to stream chapter contents.
Query params
- slug*
- stringThe book slug (see list endpoint).e.g.
divine-principle
Example
curl https://wiki.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,
"coverUrl": "/covers/divine-principle.jpg",
"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: content · cache: 300sStream paragraphs from a book. Pass `from` and/or `to` paragraph ids to slice; otherwise you get the first 200 paragraphs.
Query params
- from
- stringInclusive start paragraph id.e.g.
from=p-30-1 - to
- stringInclusive end paragraph id.e.g.
to=p-45-2
Example
curl 'https://wiki.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" },
...
]
}Speeches
19,245-speech corpus mirrored from tparents.org. Author + year/decade filters, word-count ranges, sortable, JSONL/CSV export. Each speech also exposes the polished paragraph body via its detail endpoint.
/api/v1/speechesbucket: content · cache: 300sPaginated speech listing with the full shared filter contract. Body text is not searched here — use /api/v1/search for that.
Query params
- q
- stringSubstring across title + canonical author.e.g.
q=blessing - q_title
- stringTitle-only substring.e.g.
q_title=heart - q_author
- stringAuthor-only substring.e.g.
q_author=Hak - author
- stringExact (case-insensitive) canonical display_author.e.g.
author=Sun%20Myung%20Moon - route_author
- stringOn-disk folder slug.e.g.
route_author=sunmyungmoon77 - year
- stringYYYY — date_guess starts with year.e.g.
year=1977 - decade
- stringYYY0s — speech falls in decade.e.g.
decade=1970s - date_from
- stringYYYY[-MM[-DD]] lower bound.e.g.
date_from=1977-01 - date_to
- stringYYYY[-MM[-DD]] upper bound.e.g.
date_to=1977-12-31 - source_kind
- enum— htm | pdfOrigin file kind.e.g.
source_kind=htm - min_words
- integerMinimum word count.
- max_words
- integerMaximum word count.
- tag
- string (repeatable)Tag must be present. Pass multiple times to AND-combine.
- exclude_tag
- string (repeatable)Tag must NOT be present.
- sort
- enum— date_asc | date_desc | alphabetical | length_asc | length_descSort order.
- limit
- integer1..200, default 50.
- offset
- integer>= 0, default 0.
- format
- enum— json | jsonl | csvResponse format.
Example
curl 'https://wiki.lineage-of-legends.com/api/v1/speeches?author=Sun%20Myung%20Moon&decade=1970s&sort=date_asc&limit=2'{
"count": 2,
"total": 1284,
"offset": 0,
"limit": 2,
"hasMore": true,
"nextOffset": 2,
"filters": { ... },
"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/{author}/{slug}bucket: content · cache: 300sFull transcript — metadata plus the polished paragraph array. `author` is the on-disk folder slug (`routeAuthor` in the list response).
Query params
- author*
- stringOn-disk folder slug.e.g.
sunmyungmoon77 - slug*
- stringSpeech slug.e.g.
the-way-our-family-must-go
Example
curl https://wiki.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-"
}Testimonies
Living-member faith-journey stories — podcast guests, written memoirs, YouTube videos, Substack pieces. Date filters use `episodeRef` (best-effort year extraction) so they are most useful on written memoirs.
/api/v1/testimoniesbucket: content · cache: 300sPaginated testimony listing. q searches over name + tagline + summary + content body — testimony bodies are small enough that body search is cheap here (unlike speeches/books).
Query params
- q
- stringSubstring across name + tagline + summary + body content.
- q_title
- stringSubstring on name + tagline (closest analogue to title).
- q_author
- stringSubstring on speaker name.
- author
- stringExact (case-insensitive) speaker name.
- language
- stringBCP-47 lang code (en, ja, ko, de, …).
- country
- stringISO 3166-1 alpha-2.
- status
- enum— full | preview-only | needs-audioContent / curation status.
- source_kind
- enum— podcast | youtube | written-book | substack | otherTestimony source category.
- tag
- string (repeatable)Tag must be present. Pass multiple times to AND-combine.
- exclude_tag
- string (repeatable)Tag must NOT be present.
- has_audio
- booleantrue → only rows with audioUrl set.
- has_image
- booleantrue → only rows with imageUrl set.
- has_book
- booleantrue → only rows where the person has authored books.
- year
- stringYYYY — matches episodeRef contains year.
- decade
- stringYYY0s — matches episodeRef contains year in decade.
- date_from
- stringYYYY[-MM[-DD]] lower bound (vs episodeRef year).
- date_to
- stringYYYY[-MM[-DD]] upper bound.
- min_words
- integerMinimum content word count.
- max_words
- integerMaximum content word count.
- sort
- enum— date_asc | date_desc | alphabetical | length_asc | length_descSort order. Missing-date rows sink to the end on date sorts.
- limit
- integer1..200, default 50.
- offset
- integer>= 0, default 0.
- format
- enum— json | jsonl | csvResponse format. jsonl/csv ship the row slice without the envelope.
Example
curl 'https://wiki.lineage-of-legends.com/api/v1/testimonies?source_kind=podcast&country=US&limit=2'{
"count": 2,
"total": 41,
"offset": 0,
"limit": 2,
"hasMore": true,
"nextOffset": 2,
"filters": { ... },
"testimonies": [
{
"slug": "hon-mark-anderson-wij",
"name": "Hon. Mark Anderson",
"tagline": "Politics and Religion",
"summary": "...",
"source": "podcast",
"sourceName": "Why I Joined",
"status": "full",
"language": "en",
"country": "US",
"hasAudio": true,
"hasImage": true,
"hasBooks": false,
"wordCount": 7421,
"audioUrl": "...",
"imageUrl": "...",
"url": "https://...",
"textUrl": "/api/v1/testimonies/hon-mark-anderson-wij",
"relatedLegendSlug": null
},
...
]
}/api/v1/testimonies/{slug}bucket: content · cache: 300sFull testimony record by slug — including all content paragraphs, books, papers, and tags. 404 with `testimony_not_found` on miss.
Query params
- slug*
- stringTestimony slug.
Example
curl https://wiki.lineage-of-legends.com/api/v1/testimonies/hon-mark-anderson-wij{
"slug": "hon-mark-anderson-wij",
"name": "Hon. Mark Anderson",
"tagline": "Politics and Religion",
"summary": "...",
"content": [ "Hosts: ...", "Mark: ...", ... ],
"source": "podcast",
"sourceName": "Why I Joined",
"status": "full",
"tags": ["first-gen", "politician"],
"language": "en",
"country": "US",
"wordCount": 7421,
...
}/api/v1/testimonies/sourcesbucket: content · cache: 300sSource-bucket index: one row per testimony.source value with a count. Sorted by count desc.
Example
curl https://wiki.lineage-of-legends.com/api/v1/testimonies/sources{
"count": 4,
"sources": [
{ "source": "podcast", "count": 51 },
{ "source": "youtube", "count": 28 },
{ "source": "written-book", "count": 14 },
{ "source": "substack", "count": 4 }
]
}Cross-corpus search
Two distinct endpoints. `/api/v1/everything` does fast title+author search across all three resources and is meant for "find anything called X". `/api/v1/search` is the heavier book-text indexer with passage-level hits and snippets.
/api/v1/everythingbucket: content · cache: 60sCross-corpus search across books + speeches + testimonies, returning a discriminated hit list. ONLY searches titles + author names — body search is intentionally skipped to keep latency low (use /api/v1/search for book-text passages). Score: 1.0 for title match, 0.5 for author-only match.
Query params
- q*
- stringQuery. Case-insensitive substring.
- types
- stringComma-separated subset of `books,speeches,testimonies`. Default: all three.e.g.
types=books,testimonies - limit
- integer1..100, default 30.
- offset
- integer>= 0, default 0.
Example
curl 'https://wiki.lineage-of-legends.com/api/v1/everything?q=blessing&types=books,speeches&limit=3'{
"q": "blessing",
"types": ["books", "speeches"],
"count": 3,
"total": 1842,
"offset": 0,
"limit": 3,
"hasMore": true,
"nextOffset": 3,
"hits": [
{
"kind": "book",
"slug": "blessing-and-ideal-family",
"title": "Blessing and Ideal Family",
"author": "Sun Myung Moon",
"url": "/books/blessing-and-ideal-family",
"textUrl": "/api/v1/books/blessing-and-ideal-family",
"excerpt": "Blessing and Ideal Family",
"score": 1
},
...
]
}/api/v1/searchbucket: search · cache: 60sBook-text search with passage-level hits. `results` are book-level (title/chapter); `passages` are body-text matches with a highlighted snippet and a 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 and return book-level matches only.
Query params
- q*
- string1–100 chars, up to 6 terms.
- body
- boolean0 to skip body-text passage search. Default 1.
Example
curl 'https://wiki.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 inside /api/v1/* — new fields may appear but existing ones won't be renamed or removed. Bigger changes ship under /api/v2.