API reference

Four jobs, four endpoints. Start with which call — open fields and examples only when you need them.

Which endpoint do I call?

These are not four ways to search. Each exists because one product moment kept failing when everything went into a single lookup.

You haveYou needCall
A remembered line, paraphrase, or story description The closest verse or story unit, ranked with proof POST /v1/search
A sermon, transcript, caption, or long chat Every verse that was said, pointed back at the source POST /v1/extract
A quote and a chapter:verse already attached A yes / no / not sure before that claim ships POST /v1/verify
A reference you already trust Related passages, people, or themes GET /v1/graph/…
A reference you already trust The held verse text to display GET /v1/passage
An app boot or session check What this deployment holds GET /v1/corpus

Authentication

This website is free. Lookup, Graph, and the playground on this origin do not need a key.

GETAuthorization

Calling /v1/* from curl, another site, or your own product needs an API key:

Authorization: Bearer YOUR_TOKEN

Without a key those requests return 401. These pages set a short HttpOnly session cookie; their fetch calls send that cookie from this origin (rate-limited). Spoofing Origin is not enough. A Sardius service key or Control Panel token works as the Bearer value.

POST/v1/search

Reverse lookup: you have words, not a citation. The API returns ranked scripture — a verse if they quoted, a story unit if they described a scene.

Use it when
  • A search box or “what verse is this?” field
  • A paraphrase (“green pastures, still waters”)
  • A scene (“wedding where water becomes wine”)
  • One thought in, one ranked hit list out
Do not use it when
  • The input is a whole sermon — use extract
  • A chapter:verse is already claimed — use verify
  • You only want related links — use graph
  • You already have the ref and just need text — use passage

POST quote. Read candidates[0].reference. Show sharedPhrases as the proof. Scene description? Use mode: "story".

Why this call exists What it does under the hood

People almost never type a citation. They remember a phrase, or they describe a wedding at Cana. Keyword-only search misses the meaning; a chat model guesses a reference with no proof. This is the moment that lands them on the passage and tells you why it ranked there.

In quote mode it pulls distinctive words, finds candidate verses, then scores token overlap plus shared phrases. In story mode it matches a scene to a story unit (Cana, the prodigal) instead of a single verse. auto picks from the wording so a mixed search box does not have to.

Request fields quote · mode · limit
FieldTypeRequiredWhat it is / how to use it
quote string yes The remembered line, paraphrase, or story description. Aliases: q, text. Imperfect wording is expected. Max 4,000 characters.
mode string no quote (default) ranks verses. story ranks story units. auto chooses from the wording so a mixed search box does not have to.
limit number no How many candidates to return. Default 8, max 20. Use 1–3 for a “best hit” UI; more when you want a shortlist.
translations string[] no Optional corpus ids to search in quote mode. Omit to search everything this deployment holds.
Response fields candidates[] · sharedPhrases
Quote mode
FieldTypeWhat it is / how to use it
mode string Always quote in this shape. Check it if you sent auto.
corpusVersion string Which corpus this result was scored against. Cache or log it with the hit.
query string The text that was actually searched (trimmed).
keywords string[] Tokens used to prefilter the corpus. Useful for debugging a miss, not for display.
candidates[] object[] Ranked hits, best first. Empty if nothing scored well.
candidates[].reference string Display reference (e.g. John 3:16). This is the product answer.
candidates[].score number 0–1 token-overlap confidence. Treat ≥ ~0.7 as a strong hit in a search box.
candidates[].phraseScore number How well multi-word phrases lined up. High phrase score is better proof than a high token score alone.
candidates[].sharedPhrases string[] The overlapping phrases. Show these under the hit (“matched: so loved the world”).
candidates[].matchedTranslation string | null Corpus id that scored best for this candidate.
candidates[].text string | null Held verse text when available. Always show publisher attribution if you display it.
note string? Human-readable miss reason when the list is empty.
Story-mode extras
FieldTypeWhat it is / how to use it
unitId string Stable story-unit id. Use this as the key for a story card, not a single verse.
title · summary string | null Card copy for the scene. Prefer these over raw verse text in story UIs.
reference string Span of the story (often a range, not one verse).
people · themes · places string[] Tags from the story unit. Good chips on a result card; also a hop into graph explore.
scale string Always coarse today — this is a story, not a single verse.
Example curl
// Paraphrase → verse
curl -X POST ${ORIGIN}/v1/search \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"quote":"God so loved the world that he gave his only son","limit":6}'

// Scene → story unit
curl -X POST ${ORIGIN}/v1/search \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"mode":"story","quote":"wedding where Jesus turns water into wine"}'

Pull verses out of a transcript

POST/v1/extract

Find the scripture that was quoted or alluded to inside longer talk — even when only part of a verse is spoken — and point back to the words in your source text.

Use it when
  • Auto-tagging a sermon with verses that were said
  • Highlighting quotes in a caption or notes feed
  • Recovering several verses from one recap
  • The input is long — paragraphs, not a search box
Do not use it when
  • The user typed one clean line — use search
  • You already have quote + reference — use verify
  • You only want neighbors of a known ref — use graph

POST text. Highlight excerptStartexcerptEnd in the source and tag it with reference. Several hits can come back from one clip.

Why this call exists How it windows the talk

Sermons, captions, and chat bury half-quotes mid-sentence. Sending that whole transcript to /v1/search ranks noise. Extract recovers several verses from one clip and tells you where in the talk each one appeared.

It does not search the whole blob as one query. It splits the input into spans (quoted clauses, sentences, sliding windows, and explicit “John 3:16” mentions), drops speech filler, reverse-searches each span, then merges hits by reference.

Request fields text · limit · minScore
FieldTypeRequiredWhat it is / how to use it
text string yes The sermon clip, transcript, caption, or notes. Aliases: quote, q. Max ~20,000 characters.
limit number no Max distinct references to return. Default 8, max 20.
minScore number no Confidence floor for a span to become a hit. Default 0.32. Raise it if you only want obvious quotes; lower it if you are mining allusions.
maxSpans number no How many windows to search (budget). Default grows with text length, max 40. Leave it alone unless you are tuning cost vs. recall.
translations string[] no Optional corpus ids, same as search.
Response fields hits[] · excerpt + offsets
FieldTypeWhat it is / how to use it
corpusVersion string Corpus this extract was scored against.
query string The text that was processed (trimmed).
spansConsidered number How many windows were searched. Useful when debugging a miss on a long clip.
hits[] object[] Merged, ranked scripture found in the talk. Empty if nothing was confident.
hits[].reference string The verse (or range) this span most likely quoted.
hits[].score · phraseScore number Same meaning as search. Phrase score is what keeps partial spoken quotes.
hits[].sharedPhrases string[] Overlapping phrases — show these as the highlight reason.
hits[].excerpt string The substring of your text that produced the hit — not the corpus verse.
hits[].excerptStart · excerptEnd number Character offsets into the request text. Use these to paint a highlight.
hits[].kind string quoted · sentence · window · reference. Tells you whether it came from quotes, a sentence, a sliding window, or an explicit “John 3:16” mention.
hits[].claimedRef string? Present when the speaker also said a reference. Still verify it before you trust it.
hits[].text string? Held corpus wording for the matched verse, when available.
note string? Short summary (“Found 3 likely quotes…”) or a miss hint.
Example curl
curl -X POST ${ORIGIN}/v1/extract \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"text":"He was talking about how God so loved the world that he gave his only son…","limit":6}'

Check a claim before it publishes

POST/v1/verify

You send a quote and the reference you were given. You get a verdict — not a silent rewrite. If the claim is wrong, better matches come back so the UI can suggest a correction.

Use it when
  • A human or model already attached a verse number
  • You need a yes/no before publish
  • You want “this looks like Psalm 23, not that ref”
  • You are reviewing a batch of extracted claims
Do not use it when
  • There is no claimed reference — use search
  • You need every quote in a transcript — use extract first
  • You only want neighbors of a trusted ref — use graph

POST items with quote + reference. Branch on verdict: confirmed can ship. contradicted offer candidates[0]. uncertain / unverified do not auto-publish.

Why this call exists Guard rail, not a rewrite

Wrong chapter:verse slips into slides, emails, and captions. Verify is the guard rail: confirm, contradict, or admit uncertainty — and never overwrite the caller’s reference. Your product chooses whether to block, warn, or suggest.

For each item it scores the quote against the claimed passage, then nearby verses. A deterministic scorer decides; embeddings do not vote. An item with no usable reference falls back to ranked search in the same response shape.

Request fields items[].quote + reference
FieldTypeRequiredWhat it is / how to use it
items object[] yes Batch of claims, 1–200. One item is fine. Use a batch for a review queue.
items[].quote string yes The wording you were given. Too short to judge returns unverified.
items[].reference string or object no The claimed citation, e.g. "John 3:16" or {"raw":"John 3:16"}. Omit it and this item becomes a reverse-search (still in verify shape).
items[].id string no Your id, echoed on the result so you can join a batch back to rows.
items[].hintVersion string no Optional corpus id / abbreviation to try first when scoring the claim.
items[].source string no Opaque caller metadata (where the claim came from). Not used in scoring.
translations string[] no Optional corpus filter for the whole batch.
Verdicts confirmed · contradicted · uncertain · unverified
VerdictWhat it meansWhat you should do
confirmed The quote matches the claimed passage well enough to trust. Safe to publish the claim as given.
contradicted A nearby passage fits far better than the claimed one. Do not ship the claimed ref. Offer candidates[0] as the correction.
uncertain Partial match, or a rival that is not strong enough to contradict. Ask a human, or show the note. Do not auto-correct.
unverified Too short, not held in the corpus, or no usable reference. Do not treat as a yes. Use candidates as a search shortlist if present.
Response fields results[].verdict · candidates[]
FieldTypeWhat it is / how to use it
corpusVersion string Corpus this batch was judged against.
results[] object[] One result per item, same order is not guaranteed — join on id.
results[].id string? Echo of the item id you sent.
results[].verdict string The product switch: confirmed / contradicted / uncertain / unverified.
results[].score number How well the quote matched the claimed passage (not the rival).
results[].matchedTranslation string | null Corpus id used for the claimed (or best) match.
results[].candidates[] object[] Better or nearby matches (same shape as search candidates). Empty when confirmed. Suggestions only — never applied for you.
results[].note string? Why it judged this way. Good copy for a review UI.
results[].matchedText string | null Held text of the claimed passage when available, for side-by-side review.
Example intentionally wrong ref
curl -X POST ${ORIGIN}/v1/verify \
  -H 'Authorization: Bearer YOUR_TOKEN' \
  -H 'Content-Type: application/json' \
  -d '{"items":[{"id":"1","quote":"The Lord is my shepherd; I shall not want","reference":"John 3:16"}]}'

That example is intentionally wrong. Expect contradicted and a Psalm 23 candidate.

What this deployment holds

GET/v1/corpus

Inventory of the live corpus — version stamp plus the translations this Worker can search, verify, and display.

GET once at startup. Cache the list if you have a picker. Do not call it on every search.

Response fields corpusVersion · translations[]

Search and verify only work against what is actually ingested here. Apps call this on boot, and the demo UIs use it as a session check.

FieldTypeWhat it is / how to use it
corpusVersion string Stamp of the loaded corpus. Log it with searches if you need to reproduce a result later.
translations[] object[] What this deployment holds. Use id in translations filters on other calls.
translations[].id string Corpus id — the value you pass as a filter.
translations[].name · abbreviation string Display labels if you render a picker.
translations[].licensed boolean Whether this text is a licensed edition. Always attribute if you display it.
translations[].books · verses number How much of that edition is actually loaded.
curl "${ORIGIN}/v1/corpus" -H 'Authorization: Bearer YOUR_TOKEN'

Fetch held verse text

GET/v1/passage

Given a reference you already trust, return the held wording so a UI can display it.

After a search or verify hit, GET ?translation=…&ref=John+3:16. Always show attribution. This does not rank or guess.

Request & response ref · translation · text

Search, extract, and verify find and judge. Passage is for showing — license and attribution stay in one place.

Query parameters
FieldTypeRequiredWhat it is / how to use it
ref string yes* Human reference, e.g. John 3:16 or Psalm 23:1-3. *Or pass path parts instead: /v1/passage/{translation}/{book}/{chapter}/{verse}.
translation string yes* Corpus id from /v1/corpus. Required with ref unless you use the path form.
Response
FieldTypeWhat it is / how to use it
translation · name string Which edition you fetched.
bookUsfm · chapter · verseFrom · verseTo string / number Parsed location. Use these if you need structured keys, not just display text.
text string The held wording. This is what you put on screen.
attribution string Required publisher credit. Show it next to the verse.
licensed boolean Whether this edition is licensed. Still attribute either way.
curl "${ORIGIN}/v1/passage?translation=bsb&ref=John+3:16" \
  -H 'Authorization: Bearer YOUR_TOKEN'

Show what sits around the hit

Once you already have a reference, these GET routes return the neighborhood — linked passages, people, themes, concepts, and promise/fulfillment links. They do not reverse-search wording. Same Bearer (or demo cookie) as the rest of /v1.

GET/v1/graph/subgraph

Multi-hop cross-reference neighborhood around one verse. This is the “related scripture” panel and the 3D passage map.

GET with the winning ref. depth=1 for a related rail; depth=2 for a map. Read nodes and edges.

Query & response ref · depth · nodes[]

Finding the verse is half the product. Subgraph answers “what else connects?” without another reverse search.

Query parameters
FieldTypeDefaultWhat it is / how to use it
ref string required Center verse, e.g. John 3:16. Aliases: key, verse.
depth number 2 Hops from the center. Use 1 for a compact rail, 2 for a map.
limit number 22 Max neighbors off the center. Alias: limit_center.
limit_per_node number 8 Max neighbors expanded from each hop-1 node at depth 2.
translation string held default Which edition to hydrate text from. The graph itself is translation-independent.
text 0 | 1 1 Pass text=0 if you only need structure and will fetch wording via /v1/passage.
Response (what to read)
FieldWhat it is / how to use it
center The verse you asked about, plus optional held text.
nodes[] Each related verse: display, hop (1 or 2), via (parent), optional text, plus timeline labels for a map.
edges[] Why two nodes connect: ref_type, votes, strength, notes.
stats Counts by hop and type — useful for a footer (“12 links · 4 quotations”).
curl "${ORIGIN}/v1/graph/subgraph?ref=John+3:16&depth=2&limit=12" \
  -H 'Authorization: Bearer YOUR_TOKEN'
More graph routes neighbors · people · themes · concepts
GET/v1/graph/neighbors

One hop of related verses — the lighter cousin of subgraph when you only need a list, not a map.

Query: ref (required), optional types (comma-separated link types), limit (default 40), min_votes, text=0 to skip wording.

GET/v1/graph/explore/people

Everyone named in the story units — counts, first appearance, companions. This is the people map.

Use it after a search hit when you want “who else is in this story?” or a browse index of people. Drill in with /v1/graph/explore/person/David for that person’s thread of passages.

Query: limit (default 280), min_cooccur (default 2) to hide weak companion edges.

GET/v1/graph/explore/themes

Themes that run through the story units — the theme map and tag cloud.

Use it for a “kingdom / covenant / exile” browse, or to chip-tag a result. Drill in with /v1/graph/explore/theme/kingdom for the passages under that theme.

Query: limit, min_cooccur, optional testament=ot|nt or book=JHN.

GET/v1/graph/concepts

Curriculum + doctrine graph — Foundations topics and courses, plus the gospel thread. Not the same as theme chips.

/v1/graph/concepts lists them. /concepts/map is the overview. /concepts/{id} is the bundle of passages. /concepts/{id}/trajectory is how that concept moves through Scripture.

Kinds: topic (Nature of God, Soteriology, … — the mapping surface), course (F-101–A-304), practice (maturity markers), plus the original doctrine / theme / event seed. Edges are requires, builds_on, and covers.

GET/v1/graph/promises

Promise and fulfillment links for a verse: what this passage answers, and where this promise is answered.

Query: ref (required). Use next to a prophetic or gospel hit when the product question is “where is this kept?”

GET/v1/graph/meta

Graph inventory — how many verse links and concepts this deployment has. Good for a health/status line, not for a product panel.

Interactive UI: /graph · people /graph/people · passage /graph/passages

Live playground

Run the same routes against this alpha while you’re signed into the demo. Production integrations should send Authorization: Bearer YOUR_TOKEN.

Request body
Response
// Run a request
Ready