GET /api/v1The service index.
Every route with a one-line description, and every collection with the URL that pages through it. The cheapest possible first request.
/api/v1 ↗Everything on this site is available as JSON. No key, no sign-up, no rate limit worth mentioning. It is the same data the pages render from, so the two can never disagree.
GET /api/v1The service index.
Every route with a one-line description, and every collection with the URL that pages through it. The cheapest possible first request.
/api/v1 ↗GET /api/v1/statsWhat is in the knowledge base.
The catalogue: every collection with its document count, folder, example path and what it holds, plus graph totals and the commonest tags. Start here.
/api/v1/stats ↗GET /api/v1/listPage through any collection.
How you find out what exists rather than looking one thing up. Epochs and events default to chronological order, so one call answers "what happened, in sequence".
typetagfoldersortlimitoffsetGET /api/v1/searchConcept search across every collection.
Names and their variants — aliases, alternate spellings, Strong’s numbers, transliterations — plus descriptions, tags, type names and paths. All terms must match, so adding a word narrows the result. Filter by type: there are ~3,000 people and ~3,000 themes, so an unfiltered name query is a coin flip.
qtypetaglimitoffsetGET /api/v1/scriptureFull-text search over the text of Scripture.
For finding a passage you half-remember. Every word must appear in the verse; double quotes require them adjacent as a phrase. Covers all 31,102 verses less the handful the Berean edition omits on manuscript grounds — those carry no text, so nothing can match them.
qbooktestamentlimitoffsetGET /api/v1/passage/{osis}A verse, a range, or a whole chapter.
John.3.16 for a verse, John.3.16-18 for a range, John.3 for a chapter — the chapter returns a different shape. A verse comes with its context: speaker, the people and places it names, the themes it develops, and what points at it.
/api/v1/passage/John.3.16-18 ↗GET /api/v1/interlinear/{osis}The Hebrew, Aramaic or Greek behind the English, word by word.
John.3.16 for one verse or John.3 for a chapter — like /xrefs, no ranges. A reverse interlinear: entries are in English order and each carries the range of English words it produced, so a word in the translation traces back to the word it renders. Every entry has the original, its transliteration, its morphology spelled out and its Strong’s number; lexeme appears only where the bundle holds a document for that number, which is the words behind biblical names and their roots rather than all of Strong’s, and no Greek at all. Answers 503 until npm run build:interlinear has produced the artefact.
/api/v1/interlinear/John.3.16 ↗GET /api/v1/xrefs/{osis}Cross references, ordered by crowd support.
John.3.16 for one verse or John.3 for a whole chapter — unlike /passage this takes no ranges. The corpus records that two passages are connected but never why, so these carry no relationship type. Nothing below 20 votes is in the bundle at all, so a lower minVotes changes nothing.
minVoteslimitGET /api/v1/connectionsThe cross-reference corpus in aggregate.
The shape of the whole corpus rather than one passage: hub chapters, book-to-book flows, testament totals. Answers 503 until npm run build:connections has produced the artefact.
bookosislimitGET /api/v1/nearbyPlaces within a radius, nearest first.
Anchored on a place already here, or on a bare coordinate pair for a modern location that has no document. Distances are great-circle, in kilometres.
placelatlonradiuslimitGET /api/v1/changelogThe bundle log, and when the data was generated.
bundleGenerated is when the knowledge base was last ingested — the timestamp to cite or cache on. The generated field on /stats is this server’s index-build clock and changes on every restart.
/api/v1/changelog ↗GET /api/v1/entity/{path}Any document, with typed relations both ways.
Every collection, the relation vocabulary included. Relations are stored one-directional, so the inbound half is where a person’s parents live. Add body=true for the prose. A folder root — entity/themes, entity/sources — resolves too, and answers with the collection’s size and a sample instead of a document.
bodybacklinksGET /api/v1/family/{path}A person’s parents, children, siblings and spouses.
The corpus has no child-of edge anywhere — parentage is recorded only on the parent’s document — so a person’s own parent-of relations are their children. This inverts it for you.
generationsGET /api/v1/graph/{path}A node neighbourhood, with its edges.
Everything within N hops, and the edges between them. Typed edges carry a predicate; plain document links carry only kind, so about a third of the edge list has none. Any depth on a well-connected node runs past limit quickly — themes/faith truncates at depth 2 even at the 600 maximum — and the response sets truncated when it did.
depthtypepredicatelimitGET /api/v1/vocabularyThe relation predicates and the canon table.
What develops, narrated-in, involves and stated-in mean, their inverses, and how many edges use each — plus all 66 books with their OSIS ids and chapter counts.
/api/v1/vocabulary ↗GET /api/v1/tagsThe tag vocabulary, with counts.
Tags cut across collections. Any of them can be passed to /list or /search.
limitoffsetGET /api/v1/openapi.jsonOpenAPI 3.1 description of everything above.
For tools that build themselves from a schema. Also served at /openapi.json, and every operation is named to match its MCP tool.
/api/v1/openapi.json ↗Every success carries a licence object alongside its data. A failure is { "error": "…" }, sometimes with an available array naming the legal values — an unknown type or sort on /list tells you what it would have accepted.
400 means a parameter was wrong: a missing q, a testament that is not OT or NT, an unrecognised type. 404 covers everything a reference fails to resolve to, whether it was malformed or merely absent — /passage/NotABook.9.9 and /passage/John.999.1 answer alike, because the reference parser reports both the same way. A number that will not parse — a limit of abc — is treated as absent rather than as an error, so you get the default rather than an empty result.
Every /api/v1 route answers with Access-Control-Allow-Origin: *, so this can be called straight from client-side JavaScript without a proxy in between.
Four places the API gives you less than the whole truth. Most of them do say so — backlinksTruncated, truncated, hasMore, threshold — but you have to know to look for the field, and the last one says nothing at all.
backlinks stops at 100 by defaultbacklinkCount is the true total and backlinksTruncated says whether you are seeing all of it. On /entity you can raise the cap to 500 with ?backlinks=; the chapter shape is fixed at 100. Moses has 225, so the default shows fewer than half — they are ordered to put people, themes and events above the chapters that merely mention him, so the ones that survive the cut are the informative ones. links, the outbound side, is capped at 100 too, and that cap is fixed — no parameter raises it. linkCount is the true total, so compare the two rather than counting: Moses has 76 and returns all of them, while a hub like themes/god returns 100 of far more.votes is reconstructed, and saturateslimit is a cursor on some endpoints and a cap on the rest/list, /search, /scripture and /tags page properly: they take an offset and return total alongside the page, so you can walk a whole collection. /xrefs and /graph do not — there limit is still only a cap, raising it to the maximum is the only way to see more, and past that maximum the value is clamped without comment.The data is CC BY 4.0 and the scripture text is public domain, so you are free to use it — including commercially. What travels with it is the attribution: every response carries a licence field pointing at the full source list, because the obligation is inherited rather than discharged by us.
Documents under /sa/ are CC BY-SA 4.0 and are kept separate for exactly that reason. There are 451 of them: the 450 narrative events, plus the Theographic source record, which inherits the licence of the dataset it describes while living under /sources/. Filtering on the id prefix /sa/ therefore catches all but that one.
Two fields test it exactly, and which one you get depends on the shape of the response. A response about a single document — /passage, /entity, /xrefs, /family — carries licence.document, naming the licence that actually applies. A listing or a search covers many documents at once and cannot have one licence, so instead every share-alike entry in it is flagged shareAlike: true. Between them nothing viral reaches you unlabelled; the blanket data line is not a substitute for either.
There is also an MCP server if you want an AI assistant to read this directly, and an OpenAPI description if your tooling would rather build itself from a schema.