# Get Bible The Word. For the world. Built for developers. Bring the Bible into what you build. Open APIs, practical tools, and a shared mission to make Scripture accessible everywhere. ## Explore the ecosystem ### APIs - [Bible API](https://getbible.net/api/bible/): Translations, books, chapters and verses as predictable JSON. Choose v2 or the richer v3 format. - [Query API](https://getbible.net/api/query/): Resolve human-readable Bible references into structured passages, ranges and multiple selections. - [Search API](https://getbible.net/api/search/): Search Bible text with phrase matching, filters and pagination, while preserving the selected API format. - [Dictionaries API](https://getbible.net/api/dictionaries/): Explore Hebrew and Greek Strong’s entries and their translated definitions through a static JSON API. - [Commentaries API](https://getbible.net/api/commentaries/): Connect Bible verses with commentary entries, introductions and chapter-level study material. - [Bookmarks API](https://getbible.net/api/bookmarks/): Discover curated topics and scripture references, with multilingual topic information and reusable data. ### Tools - [Librarian](https://getbible.net/project/librarian/): Read, query and search Bible data from local files or HTTP using the getbible Python package. - [Get Bible for Joomla](https://getbible.net/project/joomla/): The component, package and scripture loader, together in one installation and integration guide. - [Scripture loader](https://getbible.net/project/loader/): Embed Scripture in an existing website with the JavaScript loader and its display options. - [GetBibleSword](https://getbible.net/project/getbiblesword/): An engineering preview for working with SWORD modules and bringing their data into applications. - [SWORD extension](https://getbible.net/project/sword/): The PHP extension for reading SWORD module data. Explore native requirements and usage. - [Scripture](https://getbible.net/project/scripture/): A PHP library for structured access to Scripture through the SWORD extension. ### Apps - [Get Bible app](https://getbible.net/project/app/): The Flutter app for mobile and desktop. Under development, using v2 today; help test the next chapter. - [Desktop](https://getbible.net/project/desktop/): Explore the existing desktop application, its setup and its relationship to the next Get Bible app. - [Telegram robot](https://getbible.net/project/robot/): A Telegram bot and Mini App with Bible reading, search, bookmarks and study topics. - [Web app](https://getbible.net/project/app-getbible-life/): The app.getbible.life web project: explore its source, setup and API integration. ### AI - [Get Bible MCP](https://getbible.net/mcp/): Connect ChatGPT and compatible MCP clients to Bible, search and study data. Remote or self-hosted. ### Builders - [API builders](https://getbible.net/project/builders/): Explore the GitHub-powered builders that produce Bible, study and bookmark API datasets. ## Your first request ```bash curl --fail-with-body \ 'https://api.getbible.net/v2/kjv/43/3.json' ``` ## The mission Get Bible is a project of [trueChristian.church](https://trueChristian.church). We build Scripture infrastructure that developers, churches and communities can use to bring the Bible to the world. The [Get Bible app](/project/app/) is under development and currently uses API v2. Advancing it to v3 and study APIs is a future priority. - [About Get Bible](/about/) - [Get involved](/contribute/) - [Donations](/donate/) - [Access and tokens](/tokens/) - [Public support](https://git.vdm.dev/getBible/support) - [Email](mailto:getBible@TrueChristian.church) - [Read the Bible](https://getbible.life) ## Connect AI tools The Get Bible MCP endpoint is `https://mcp.getbible.net/`. Connect using Streamable HTTP with anonymous access, or run the Python package locally. See [MCP setup](/mcp/) for ChatGPT developer mode and other clients. --- # The Word. For the world. Get Bible brings Scripture into the places people already read, learn, build and connect. At its core, it is a family of APIs that developers can use to put the Bible into applications of their own. ## Our purpose Our mission is to make the Bible accessible throughout the world, in a powerful and practical way. We provide the data and tools that let programmers, churches, ministries and communities build experiences around Scripture. An API can serve a verse in a website, a passage in a mobile app, a search result in a study tool, or source material for an AI assistant. Each integration is another opportunity to bring the Word to someone. ## A project of trueChristian.church Get Bible is a project of [trueChristian.church](https://trueChristian.church). This is the project’s affiliation and the home of its Christian mission. Our public code, documentation and developer tools make participation possible across languages, platforms and communities. For questions about the project, partnerships or its mission, email [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). ## How the project fits together | Layer | What it does | Start here | | --- | --- | --- | | Builders | Produce versioned Bible, dictionary, commentary and bookmark datasets through open source workflows | [API builders](/project/builders/) | | APIs | Deliver Scripture and study data, resolve references and search Bible text | [API documentation](/api/) | | Libraries and tools | Help developers consume APIs, embed Scripture or work with local modules | [Projects](/project/) | | Applications | Bring Scripture into websites, desktops, Telegram and the developing cross-platform app | [Get Bible app](/project/app/) | | MCP | Connect compatible AI clients with Get Bible resources and tools | [MCP guide](/mcp/) | ## Our next focus The [Get Bible app](/project/app/) is under development. It currently uses Bible API v2. Our intended direction is to advance it to v3 and integrate dictionaries, commentaries and the wider study ecosystem, then work toward app-store and desktop distribution. That is work to help shape and test, rather than a promise that those integrations or store releases are available today. Explore the source and contribute testing, accessibility feedback, platform expertise or implementation work. ## Read, build or contribute - **Read:** visit [getbible.life](https://getbible.life), the Bible reading site. - **Build:** start with the [Bible API](/api/bible/), then add [query](/api/query/), [search](/api/search/) or study resources. - **Contribute:** find practical ways to help on [Get involved](/contribute/). - **Support the mission:** [make a donation](/donate/) or contact the team. ## Open source and content rights Code and data are available through the [Get Bible GitHub organization](https://github.com/getbible). Check the license in each repository and the metadata for each translation or study work you use. An open API is a delivery mechanism; it does not remove the attribution or reuse requirements of the underlying material. All public questions go to the [central support desk](https://git.vdm.dev/getBible/support). --- # Build with the Get Bible APIs Six API families give you Scripture, reference lookup, search and study resources. Choose the API for the job, then select its version for the complete integration guide and contract reference. ## Choose an API | API | Use it to | Versions | | --- | --- | --- | | [Bible](/api/bible/) | Download translations, books, chapters and their checksums | [v2](/api/bible/v2/), [v3](/api/bible/v3/) | | [Query](/api/query/) | Resolve a verse, chapter, range or combined reference | [v2](/api/query/v2/), [v3](/api/query/v3/) | | [Search](/api/search/) | Find words and phrases with scopes and pagination | [v2](/api/search/v2/), [v3](/api/search/v3/) | | [Dictionaries](/api/dictionaries/) | Look up original-language entries and translated definitions | [v1](/api/dictionaries/v1/) | | [Commentaries](/api/commentaries/) | Read commentary on books, chapters and passages | [v1](/api/commentaries/v1/) | | [Bookmarks](/api/bookmarks/) | Discover curated Bible topics and references | [v1](/api/bookmarks/v1/) | ## Start with a chapter This retrieves John 3 in the King James Version: ```bash curl --fail-with-body --silent --show-error \ 'https://api.getbible.net/v2/kjv/43/3.json' ``` The static Bible API publishes chapter JSON. Use the Query API when you want a specific verse or a reference range: ```bash curl --fail-with-body --silent --show-error \ 'https://query.getbible.net/v3/kjv/John%203%3A16' ``` Look up the actual translation and book identifiers from the catalogs. For text matching and filtering, continue with the [Search API guide](/api/search/). ## Choose v2 or v3 The Bible, Query and Search APIs offer both versions. V3 preserves richer verse information where present, including lexical tokens and spans. Static v3 chapter data can also carry editorial layout metadata. Query and search return verse-based results rather than a complete chapter layout; do not assume chapter editorial data appears there. Not every translation contains every optional v3 field. Keep the data returned by your selected version and check optional fields before reading them. Translation catalogs remain the place for complete metadata; query and search results keep their translation headers compact. See [Bible v3](/api/bible/v3/), [Query v3](/api/query/v3/) and [Search v3](/api/search/v3/) for their exact response structures. ## Try the APIs in Postman Every version page includes a downloadable Postman collection generated from its OpenAPI document. Download the collection, open Postman, choose **Import**, and select the JSON file. Review the collection variables and choose the request you want to send. Optional query parameters start disabled; enable those you need. You can also copy the **live OpenAPI JSON** URL from a version page and paste it into Postman’s Import flow. Some source specifications use relative servers, so the generated collection resolves the actual service hostname for you. | Collection | Importable JSON | | --- | --- | | Bible v2 | [Download](/postman/bible-v2.json) | | Bible v3 | [Download](/postman/bible-v3.json) | | Query v2 | [Download](/postman/query-v2.json) | | Query v3 | [Download](/postman/query-v3.json) | | Search v2 | [Download](/postman/search-v2.json) | | Search v3 | [Download](/postman/search-v3.json) | | Dictionaries v1 | [Download](/postman/dictionaries-v1.json) | | Commentaries v1 | [Download](/postman/commentaries-v1.json) | | Bookmarks v1 | [Download](/postman/bookmarks-v1.json) | Postman is optional. Every guide includes cURL examples, and the source contracts can be used with other OpenAPI clients. ## Access, tokens and caching Start with public access. Query, search and MCP can have domain-specific tokens for managed access and rate-limit allowances; tokens are not interchangeable between hosts. The static Bible and study data do not require a consumer API key in their published contracts. Read [access and tokens](/tokens/) for the request process and client guidance. Cache reusable content, honor service response headers, and back off when rate-limited. Read the full translation or study-work metadata when you need rights and attribution information. Check the service-specific guides before depending on cache lifetimes, response sizes or optional data. ## Connect a library or AI client - [Librarian](/project/librarian/) provides Python access to local or remote Scripture datasets. - [The JavaScript loader](/project/loader/) embeds Scripture in existing websites. - [Get Bible MCP](/mcp/) connects compatible AI clients to the APIs. - [API builders](/project/builders/) explain how the published datasets are generated. ## Documentation and service addresses These guides live on `getbible.net/api///`. Requests still go to the original `api.`, `query.`, `search.`, `dictionaries.`, `commentaries.` and `bookmarks.getbible.net` service hosts. Moving documentation does not change the API endpoints. For all public support, use the [Get Bible support desk](https://git.vdm.dev/getBible/support). For private access enquiries, email [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). --- The Bible API is the foundation of GetBible. It publishes Scripture as a predictable tree of JSON files, so a reader, mobile app, website or offline tool can request one chapter, one book or an entire translation. The same data feeds the reference and full-text services. ## Choose a version | Version | Best fit | Documentation | Live base | | --- | --- | --- | --- | | v2 | Existing integrations and a compact chapter/verse text format | [Bible v2](/api/bible/v2/) | `https://api.getbible.net/v2/` | | v3 | New reading and study experiences that can use source lexical and layout metadata | [Bible v3](/api/bible/v3/) | `https://api.getbible.net/v3/` | Both versions publish translation, book and chapter documents. Version 3 retains the familiar `text`, `chapter`, `verse` and `name` fields and adds optional source metadata: paragraph starts, word tokens, annotation spans, introductions and chapter editorial layout. Availability depends on the translation and its source; metadata is not invented for translations that lack it. The API version selects a data tree. It is separate from the version of the Python librarian package, the MCP package or the server deployment software. Keep the chosen API version in application configuration and cache keys. The [live version index](https://api.getbible.net/versions.json) identifies published trees and their contracts. ## Make your first request ```bash curl --fail-with-body --compressed \ 'https://api.getbible.net/v3/kjv/43/3.json' ``` This returns John chapter 3 in the King James Version. `kjv` identifies the translation, `43` is the GetBible book number for John and `3` is the chapter. The response contains all verses in that chapter. For an individual verse or a selection of references, use the [Query API](/api/query/). For words and phrases, use the [Search API](/api/search/). The static Bible API does not accept `?verse=16`, `?q=faith` or other query parameters. ## Discover data instead of guessing ```bash # Translation catalogue, including language and distribution metadata curl --fail-with-body --compressed 'https://api.getbible.net/v3/translations.json' # Books actually published for the KJV curl --fail-with-body --compressed 'https://api.getbible.net/v3/kjv/books.json' # Chapters actually published for John curl --fail-with-body --compressed 'https://api.getbible.net/v3/kjv/43/chapters.json' ``` The JSON indexes are objects keyed by translation abbreviation, book number or chapter number. Their entries include a document `url` and its `sha` change checksum. JSON object keys representing numbers are strings; book and chapter fields inside the records are integers. Discover books independently for each translation. Translations may have different books, names or versification. In v3, additional source book identities can have stable numbers above the familiar 1–89 range. A translation's `books.json` is the authoritative inventory for that tree. ## Understand the three document sizes | Resource | Example | Contents | | --- | --- | --- | | Whole translation | `/v3/kjv.json` | Translation metadata and every book, chapter and verse | | Whole book | `/v3/kjv/43.json` | Shared translation metadata and every chapter in John | | One chapter | `/v3/kjv/43/3.json` | Shared translation metadata, chapter identity and its verses | | Translation catalogue | `/v3/translations.json` | Metadata for every published translation without the full Scripture hierarchy | Choose the smallest document that serves the task. A chapter request is suitable for a reader; a full translation download is useful for offline use and indexing. Store catalogue metadata separately and join on `abbreviation`, so repeated verse selections do not need to carry translation history or distribution descriptions. ## Access, caching and change detection Public calls work without registration. The live API advertises metered access by client address, with bearer tokens available to applications and partners. Request a token through [GetBible support](https://git.vdm.dev/getBible/support) or [email the team](mailto:getBible@TrueChristian.church). Tell us which API domains the application uses. Tokens are scoped to the domain that issued them and belong in the `Authorization` header, never in a URL. Use the returned `Cache-Control` and `ETag` headers. Revalidate a stored representation with `If-None-Match`; an unchanged representation can return `304` with no response body. `Last-Modified` and `If-Modified-Since` are also available on static documents. Read the actual headers instead of hardcoding a lifetime: deployed policy can differ from server defaults. Every JSON document has a sibling `.sha` file. For example, `/v3/kjv/43/3.sha` identifies the bytes of `/v3/kjv/43/3.json`. A checksum is a data change token; it is different from an HTTP validator and does not establish publisher identity. For persistent v2 Scripture caches, retain the relevant scope hashes and check at least weekly, as described in the [GetBible v2 cache policy](https://github.com/getbible/mcp/blob/main/site/v2/cache-policy.md). Replace changed text and its hash together. ## Browser applications The public APIs allow cross-origin reads. Browser clients can fetch JSON directly and respect the translation's `direction` when displaying it. Keep private partner tokens on your own backend rather than embedding them in publicly downloadable JavaScript. ```javascript const response = await fetch('https://api.getbible.net/v3/kjv/43/3.json'); if (!response.ok) { throw new Error(`GetBible returned HTTP ${response.status}`); } const chapter = await response.json(); for (const verse of chapter.verses) { console.log(verse.name, verse.text); } ``` Render Scripture text as text content. Preserve the returned verse objects if the application stores or forwards v3 metadata. ## Data provenance and distribution The [v2 builder](https://github.com/getbible/v2_builder) and [v3 builder](https://github.com/getbible/v3_builder) generate the published data from CrossWire SWORD modules. The v3 pipeline uses [GetBibleSWORD](/project/getbiblesword/) extraction and publishes compact reading data. Check the translation catalogue's `distribution_license`, `distribution_source` and related fields when choosing material for redistribution. A source-code licence and a translation's distribution terms describe different things. ## Contracts and upstream documentation | Resource | Link | | --- | --- | | API service overview | [api.getbible.net](https://api.getbible.net/) | | v2 live documentation | [api.getbible.net/v2/](https://api.getbible.net/v2/) | | v2 OpenAPI 3.1 | [openapi.json](https://api.getbible.net/v2/openapi.json) | | v3 live documentation | [api.getbible.net/v3/](https://api.getbible.net/v3/) | | v3 OpenAPI 3.1 | [openapi.json](https://api.getbible.net/v3/openapi.json) | | Server access and cache policy | [Access modes](https://github.com/getbible/api/blob/main/docs/ACCESS_MODES.md) | | v3 data semantics | [Generated static output](https://github.com/getbible/v3_builder/blob/master/docs/static-output.md) | For help with any API or project, use the shared [GetBible support desk](https://git.vdm.dev/getBible/support). Include the request URL, HTTP status and `X-Request-ID` response header when reporting an API problem; omit credentials. --- Bible v2 provides a compact, stable JSON hierarchy for applications that need Scripture text. Each translation, book and chapter is an independently addressable file. No database query, request body or URL query parameter is required. **Base URL:** `https://api.getbible.net/v2/` [Live documentation](https://api.getbible.net/v2/) · [OpenAPI JSON](https://api.getbible.net/v2/openapi.json) · [All Bible API versions](/api/bible/) · [Support](https://git.vdm.dev/getBible/support) ## Quick start ```bash # Read John chapter 3 curl --fail-with-body --compressed \ 'https://api.getbible.net/v2/kjv/43/3.json' # Read the whole book of John curl --fail-with-body --compressed \ 'https://api.getbible.net/v2/kjv/43.json' # Download the complete KJV for an offline application curl --fail-with-body --compressed \ 'https://api.getbible.net/v2/kjv.json' --output kjv-v2.json ``` These are different views of the same translation. The book and chapter files do not represent additional corpora to append to the whole-translation file. ## Path parameters | Name | Type | Requirement | | --- | --- | --- | | `abbreviation` | String | Required on translation-specific paths. Use a lowercase identifier from `translations.json`, such as `kjv`, `aov` or `vulgate`. The v2 schema uses `^[a-z0-9]+$`. | | `book` | Integer | Required on book/chapter paths. Use the translation's `books.json`; the v2 contract allows 1–89. | | `chapter` | Integer | Required for a chapter document. Positive integer listed by that book's `chapters.json`. | There is no default translation on a static file path. To obtain a single verse, use [Query v2](/api/query/v2/), for example `https://query.getbible.net/v2/kjv/John3:16`. ## Every resource All paths below are relative to the v2 base URL and use `GET`. `HEAD` retrieves headers; `OPTIONS` supports browser preflight. | Path | Result | | --- | --- | | `translations.json` | Object containing metadata for all translations, keyed by abbreviation | | `translations.txt` | Tab-separated translation index | | `translations.sha` | SHA-1 of `translations.json` | | `checksum.json` | Translation abbreviations mapped to translation-file hashes | | `checksum.txt` | Tab-separated translation checksum index | | `checksum.sha` | SHA-1 of root `checksum.json` | | `{abbreviation}.json` | Complete translation with all books and verses | | `{abbreviation}.sha` | SHA-1 of that complete translation | | `{abbreviation}/books.json` | Available books with metadata, URLs and hashes, keyed by book number | | `{abbreviation}/books.txt` | Tab-separated book index | | `{abbreviation}/books.sha` | SHA-1 of `books.json` | | `{abbreviation}/checksum.json` | Book numbers mapped to book-file hashes | | `{abbreviation}/checksum.txt` | Tab-separated book checksum index | | `{abbreviation}/checksum.sha` | SHA-1 of that book checksum index | | `{abbreviation}/{book}.json` | Complete book, including its chapters | | `{abbreviation}/{book}.sha` | SHA-1 of the book document | | `{abbreviation}/{book}/chapters.json` | Available chapters with metadata, URLs and hashes, keyed by chapter number | | `{abbreviation}/{book}/chapters.txt` | Tab-separated chapter index | | `{abbreviation}/{book}/chapters.sha` | SHA-1 of `chapters.json` | | `{abbreviation}/{book}/checksum.json` | Chapter numbers mapped to chapter-file hashes | | `{abbreviation}/{book}/checksum.txt` | Tab-separated chapter checksum index | | `{abbreviation}/{book}/checksum.sha` | SHA-1 of that chapter checksum index | | `{abbreviation}/{book}/{chapter}.json` | Complete chapter and its verses | | `{abbreviation}/{book}/{chapter}.sha` | SHA-1 of the chapter document | | `openapi.json` | The generated OpenAPI 3.1 contract | | `openapi.sha` | SHA-1 of the OpenAPI document | Index `.txt` files start with a header line beginning with `#`. Their records are separated by newlines and columns by tabs. Read the header instead of assuming every index level has identical columns. ## Discovery workflow ```bash # Find available translation identifiers and metadata curl --fail-with-body --compressed \ 'https://api.getbible.net/v2/translations.json' # Find the books of a selected translation curl --fail-with-body --compressed \ 'https://api.getbible.net/v2/kjv/books.json' # Find John's chapters curl --fail-with-body --compressed \ 'https://api.getbible.net/v2/kjv/43/chapters.json' ``` Translation, book and chapter index entries include `url` and `sha`. Follow those URLs and store the matching hash. Book numbers in JSON object keys are strings, while `nr`, `book_nr` and `chapter` inside records are integers. ## Response fields The six shared translation fields appear on standalone book and chapter documents: | Field | Type | Meaning | | --- | --- | --- | | `translation` | String | Display name, such as `King James Version` | | `abbreviation` | String | Translation identifier, such as `kjv` | | `lang` | String | Source language code, such as `en` | | `language` | String | Language label, such as `English` | | `direction` | String | `LTR` or `RTL` | | `encoding` | String | Source module encoding label | Do not replace an empty source language label with a guessed value. Use `direction` to choose the appropriate text flow. ### Chapter document | Field | Type | Meaning | | --- | --- | --- | | Shared translation fields | Strings | The six fields above | | `book_nr` | Integer | Stable GetBible book number | | `book_name` | String | Book name supplied for this translation | | `chapter` | Integer | Chapter number | | `name` | String | Chapter display name, for example `John 3` | | `verses` | Array of verse objects | Every verse in the chapter | Each v2 verse contains `chapter` (integer), `verse` (integer), `name` (string) and `text` (string). A selected verse record from the live John 3 chapter is: ```json { "chapter": 3, "verse": 16, "name": "John 3:16", "text": "For God so loved the world, that he gave his only begotten Son, that whosoever believeth in him should not perish, but have everlasting life." } ``` This is one record from `verses`; the chapter endpoint returns the complete chapter, not a one-verse response. ### Book document The top level contains the shared translation fields, `nr`, `name` and `chapters`. Here `nr` is the book number and `name` is the book name. Each nested chapter contains `chapter`, `name` and `verses`; the enclosing book supplies its translation and book context. ### Translation document and catalogue A whole translation has `books`, an array of book objects. Each book has `nr`, `name` and `chapters`. The document also includes these source metadata fields: | Field | Type | Meaning | | --- | --- | --- | | `description` | String | Source translation description | | `distribution_lcsh` | String | Source subject heading | | `distribution_version` | String | Source module version | | `distribution_version_date` | String | Source version date | | `distribution_abbreviation` | String | Original module abbreviation | | `distribution_about` | String | Source description of the text | | `distribution_license` | String | Distribution terms recorded by the source | | `distribution_sourcetype` | String | Source markup type | | `distribution_source` | String | Source provenance | | `distribution_versification` | String | Source versification system | | `distribution_history` | Object of strings | Source history entries | The translation catalogue contains this metadata without the `books` hierarchy, adding the document `url` and `sha`. Obtain it once and join by `abbreviation`. Query and search results intentionally carry only the six shared translation fields. ## Checksum-aware downloads A `.sha` response is a 40-character lowercase hexadecimal SHA-1 followed by a newline. It hashes the JSON file's bytes, not a parsed or reformatted object. ```bash # Download a chapter and its corresponding change token curl --fail-with-body --compressed \ 'https://api.getbible.net/v2/kjv/43/3.json' --output john-3-v2.json curl --fail-with-body \ 'https://api.getbible.net/v2/kjv/43/3.sha' --output john-3-v2.sha # Compare the advertised hash with the downloaded file on Linux expected_hash=$(tr -d '\r\n' < john-3-v2.sha) printf '%s %s\n' "$expected_hash" john-3-v2.json | sha1sum --check --status ``` A nonzero check means the pair should not be committed to the application cache. A publication may have changed between the two downloads; retrieve a matching pair again. Store replacement payloads and hashes atomically. These hashes detect a data change; they are not authentication credentials or signatures. For long-lived v2 Scripture caches, keep each payload's exact translation/book/chapter scope hash and the time of its last successful check. Recheck at least weekly; invalidate a changed scope and its descendants. If rechecking fails, retain the previous check time and describe the content as stale. See the [complete v2 cache policy](https://github.com/getbible/mcp/blob/main/site/v2/cache-policy.md). ## HTTP caching and browser use Respect `Cache-Control` on each response. Retain `ETag` for revalidation, and use `If-None-Match` to receive `304` when the representation is unchanged. The `.sha` resources generally have a shorter freshness lifetime than Scripture documents. Actual deployment headers are authoritative. ```bash # Save an ETag for the catalogue curl --fail-with-body --compressed \ --etag-save translations-v2.etag \ 'https://api.getbible.net/v2/translations.json' \ --output translations-v2.json # Inspect a subsequent conditional response; 304 has no JSON body curl --include --compressed \ --etag-compare translations-v2.etag \ 'https://api.getbible.net/v2/translations.json' ``` Open CORS permits browser reads. `GET`, `HEAD` and `OPTIONS` are accepted; preflights return `204`. Query strings are rejected, including cache-busting parameters. Use conditional headers instead. ## Access and tokens The live service is public and metered. Anonymous budgets are per client address; a valid token exempts its holder from those public rate budgets. Token privileges do not remove input validation or guarantee service availability. Ask through [support](https://git.vdm.dev/getBible/support) or [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church) for application or partner access. Specify `api.getbible.net`; a token for another domain is not interchangeable. Set the issued value in the `GETBIBLE_API_TOKEN` environment variable before running: ```bash curl --fail-with-body --compressed \ --header "Authorization: Bearer ${GETBIBLE_API_TOKEN:?Set GETBIBLE_API_TOKEN to your issued token}" \ 'https://api.getbible.net/v2/kjv/43/3.json' ``` ## Errors and troubleshooting Errors use `application/problem+json`, with `type`, `title`, `status`, `code`, `detail` and `instance`. Handle the status before parsing a successful Scripture response. | HTTP | Code | What to do | | --- | --- | --- | | 400 | `bad_request` | Remove query parameters or fix the malformed request | | 401 | `unauthorized` | Check token validity where token-only access is configured | | 404 | `not_found` | Check the version and discover the resource through the indexes | | 405 | `method_not_allowed` | Use GET, HEAD or OPTIONS | | 429 | `rate_limited` | Respect `Retry-After`; reduce request frequency and reuse cached data | | 503 | `unavailable` | Retry a temporary outage after a short delay | `GET https://api.getbible.net/healthz` is a liveness endpoint. When reporting a problem, include `X-Request-ID`, the exact resource URL and HTTP status at the [single support desk](https://git.vdm.dev/getBible/support). ## OpenAPI and API clients Import [the live v2 OpenAPI JSON](https://api.getbible.net/v2/openapi.json) into Postman's Import dialog to create requests from the contract. Its `servers` value already ends in `/v2`; its paths start below that base. Do not add the version twice. No API token is necessary to download the contract. For the generation pipeline, see [v2_builder](https://github.com/getbible/v2_builder). For the common deployment behavior, see [the service overview](https://api.getbible.net/) and [access and caching documentation](https://github.com/getbible/api/blob/main/docs/ACCESS_MODES.md). ## Complete contract reference Open the [complete endpoint and schema reference](/api/bible/v2/reference/) for every operation, parameter, response and component model in the published OpenAPI contract. --- # Bible API v2: endpoint and schema reference This reference is generated from the checked-in [OpenAPI contract](https://api.getbible.net/v2/openapi.json). Return to the [integration guide](/api/bible/v2/) for workflows and ready-to-run examples. Resolved request server: `https://api.getbible.net/v2`. ## GET /translations.json Index of the translations Every translation in the tree with its details and checksum, keyed by abbreviation. Operation ID: `listTranslations`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Index of the translations | application/json | #/components/schemas/TranslationIndex |
Complete operation contract ```json { "tags": [ "translations" ], "summary": "Index of the translations", "description": "Every translation in the tree with its details and checksum, keyed by abbreviation.", "operationId": "listTranslations", "responses": { "200": { "description": "Index of the translations", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TranslationIndex" } } } } }, "parameters": [] } ```
## GET /translations.txt Index of the translations as text Every translation in the tree, one per line, with the columns: #, language, translation, abbreviation, direction, filename, sha. Operation ID: `listTranslationsText`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Index of the translations as text | text/plain | #/components/schemas/TabSeparatedIndex |
Complete operation contract ```json { "tags": [ "translations" ], "summary": "Index of the translations as text", "description": "Every translation in the tree, one per line, with the columns: #, language, translation, abbreviation, direction, filename, sha.", "operationId": "listTranslationsText", "responses": { "200": { "description": "Index of the translations as text", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/TabSeparatedIndex" } } } } }, "parameters": [] } ```
## GET /translations.sha Checksum of the index of the translations The SHA-1 checksum of translations.json. Operation ID: `getTranslationIndexChecksum`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksum of the index of the translations | text/plain | #/components/schemas/Sha1File |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksum of the index of the translations", "description": "The SHA-1 checksum of translations.json.", "operationId": "getTranslationIndexChecksum", "responses": { "200": { "description": "Checksum of the index of the translations", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Sha1File" } } } } }, "parameters": [] } ```
## GET /checksum.json Checksums of the translations The SHA-1 checksum of every translation file, keyed by abbreviation. Operation ID: `listTranslationChecksums`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksums of the translations | application/json | #/components/schemas/ChecksumIndex |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksums of the translations", "description": "The SHA-1 checksum of every translation file, keyed by abbreviation.", "operationId": "listTranslationChecksums", "responses": { "200": { "description": "Checksums of the translations", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChecksumIndex" } } } } }, "parameters": [] } ```
## GET /checksum.txt Checksums of the translations as text The SHA-1 checksum of every translation file, one per line, with the columns: #, filename, sha. Operation ID: `listTranslationChecksumsText`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksums of the translations as text | text/plain | #/components/schemas/TabSeparatedIndex |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksums of the translations as text", "description": "The SHA-1 checksum of every translation file, one per line, with the columns: #, filename, sha.", "operationId": "listTranslationChecksumsText", "responses": { "200": { "description": "Checksums of the translations as text", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/TabSeparatedIndex" } } } } }, "parameters": [] } ```
## GET /checksum.sha Checksum of the checksums of the translations The SHA-1 checksum of checksum.json. Operation ID: `getTranslationChecksumIndexChecksum`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksum of the checksums of the translations | text/plain | #/components/schemas/Sha1File |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksum of the checksums of the translations", "description": "The SHA-1 checksum of checksum.json.", "operationId": "getTranslationChecksumIndexChecksum", "responses": { "200": { "description": "Checksum of the checksums of the translations", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Sha1File" } } } } }, "parameters": [] } ```
## GET /{abbreviation}.json A complete translation The whole translation: every book with every chapter and verse, and the details of the source module. Operation ID: `getTranslation`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | A complete translation | application/json | #/components/schemas/Translation | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "translations" ], "summary": "A complete translation", "description": "The whole translation: every book with every chapter and verse, and the details of the source module.", "operationId": "getTranslation", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" } ], "responses": { "200": { "description": "A complete translation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Translation" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}.sha Checksum of a translation The SHA-1 checksum of the translation file. Operation ID: `getTranslationChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksum of a translation | text/plain | #/components/schemas/Sha1File | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksum of a translation", "description": "The SHA-1 checksum of the translation file.", "operationId": "getTranslationChecksum", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" } ], "responses": { "200": { "description": "Checksum of a translation", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Sha1File" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/books.json Index of the books of a translation Every book of the translation with its details and checksum, keyed by book number. Operation ID: `listBooks`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Index of the books of a translation | application/json | #/components/schemas/BookIndex | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "books" ], "summary": "Index of the books of a translation", "description": "Every book of the translation with its details and checksum, keyed by book number.", "operationId": "listBooks", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" } ], "responses": { "200": { "description": "Index of the books of a translation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BookIndex" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/books.txt Index of the books of a translation as text Every book of the translation, one per line, with the columns: #, language, translation, abbreviation, direction, name, filename, sha. Operation ID: `listBooksText`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Index of the books of a translation as text | text/plain | #/components/schemas/TabSeparatedIndex | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "books" ], "summary": "Index of the books of a translation as text", "description": "Every book of the translation, one per line, with the columns: #, language, translation, abbreviation, direction, name, filename, sha.", "operationId": "listBooksText", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" } ], "responses": { "200": { "description": "Index of the books of a translation as text", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/TabSeparatedIndex" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/books.sha Checksum of the index of the books of a translation The SHA-1 checksum of the books.json of the translation. Operation ID: `getBookIndexChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksum of the index of the books of a translation | text/plain | #/components/schemas/Sha1File | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksum of the index of the books of a translation", "description": "The SHA-1 checksum of the books.json of the translation.", "operationId": "getBookIndexChecksum", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" } ], "responses": { "200": { "description": "Checksum of the index of the books of a translation", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Sha1File" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/checksum.json Checksums of the books of a translation The SHA-1 checksum of every book file of the translation, keyed by book number. Operation ID: `listBookChecksums`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksums of the books of a translation | application/json | #/components/schemas/ChecksumIndex | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksums of the books of a translation", "description": "The SHA-1 checksum of every book file of the translation, keyed by book number.", "operationId": "listBookChecksums", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" } ], "responses": { "200": { "description": "Checksums of the books of a translation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChecksumIndex" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/checksum.txt Checksums of the books of a translation as text The SHA-1 checksum of every book file of the translation, one per line, with the columns: #, filename, sha. Operation ID: `listBookChecksumsText`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksums of the books of a translation as text | text/plain | #/components/schemas/TabSeparatedIndex | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksums of the books of a translation as text", "description": "The SHA-1 checksum of every book file of the translation, one per line, with the columns: #, filename, sha.", "operationId": "listBookChecksumsText", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" } ], "responses": { "200": { "description": "Checksums of the books of a translation as text", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/TabSeparatedIndex" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/checksum.sha Checksum of the checksums of the books of a translation The SHA-1 checksum of the checksum.json of the translation. Operation ID: `getBookChecksumIndexChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksum of the checksums of the books of a translation | text/plain | #/components/schemas/Sha1File | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksum of the checksums of the books of a translation", "description": "The SHA-1 checksum of the checksum.json of the translation.", "operationId": "getBookChecksumIndexChecksum", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" } ], "responses": { "200": { "description": "Checksum of the checksums of the books of a translation", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Sha1File" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/{book}.json A complete book One book of the translation with every chapter and verse. Operation ID: `getBook`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | | `book` | path | Yes | integer | 1 | Book number, as listed in the books.json of the translation | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | A complete book | application/json | #/components/schemas/Book | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "books" ], "summary": "A complete book", "description": "One book of the translation with every chapter and verse.", "operationId": "getBook", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" }, { "name": "book", "in": "path", "required": true, "description": "Book number, as listed in the books.json of the translation", "schema": { "type": "integer", "minimum": 1, "maximum": 89 }, "example": 1 } ], "responses": { "200": { "description": "A complete book", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Book" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/{book}.sha Checksum of a book The SHA-1 checksum of the book file. Operation ID: `getBookChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | | `book` | path | Yes | integer | 1 | Book number, as listed in the books.json of the translation | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksum of a book | text/plain | #/components/schemas/Sha1File | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksum of a book", "description": "The SHA-1 checksum of the book file.", "operationId": "getBookChecksum", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" }, { "name": "book", "in": "path", "required": true, "description": "Book number, as listed in the books.json of the translation", "schema": { "type": "integer", "minimum": 1, "maximum": 89 }, "example": 1 } ], "responses": { "200": { "description": "Checksum of a book", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Sha1File" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/{book}/chapters.json Index of the chapters of a book Every chapter of the book with its details and checksum, keyed by chapter number. Operation ID: `listChapters`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | | `book` | path | Yes | integer | 1 | Book number, as listed in the books.json of the translation | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Index of the chapters of a book | application/json | #/components/schemas/ChapterIndex | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "chapters" ], "summary": "Index of the chapters of a book", "description": "Every chapter of the book with its details and checksum, keyed by chapter number.", "operationId": "listChapters", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" }, { "name": "book", "in": "path", "required": true, "description": "Book number, as listed in the books.json of the translation", "schema": { "type": "integer", "minimum": 1, "maximum": 89 }, "example": 1 } ], "responses": { "200": { "description": "Index of the chapters of a book", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChapterIndex" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/{book}/chapters.txt Index of the chapters of a book as text Every chapter of the book, one per line, with the columns: #, language, translation, abbreviation, textdirection, book_nr, book_name, filename, sha. Operation ID: `listChaptersText`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | | `book` | path | Yes | integer | 1 | Book number, as listed in the books.json of the translation | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Index of the chapters of a book as text | text/plain | #/components/schemas/TabSeparatedIndex | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "chapters" ], "summary": "Index of the chapters of a book as text", "description": "Every chapter of the book, one per line, with the columns: #, language, translation, abbreviation, textdirection, book_nr, book_name, filename, sha.", "operationId": "listChaptersText", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" }, { "name": "book", "in": "path", "required": true, "description": "Book number, as listed in the books.json of the translation", "schema": { "type": "integer", "minimum": 1, "maximum": 89 }, "example": 1 } ], "responses": { "200": { "description": "Index of the chapters of a book as text", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/TabSeparatedIndex" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/{book}/chapters.sha Checksum of the index of the chapters of a book The SHA-1 checksum of the chapters.json of the book. Operation ID: `getChapterIndexChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | | `book` | path | Yes | integer | 1 | Book number, as listed in the books.json of the translation | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksum of the index of the chapters of a book | text/plain | #/components/schemas/Sha1File | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksum of the index of the chapters of a book", "description": "The SHA-1 checksum of the chapters.json of the book.", "operationId": "getChapterIndexChecksum", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" }, { "name": "book", "in": "path", "required": true, "description": "Book number, as listed in the books.json of the translation", "schema": { "type": "integer", "minimum": 1, "maximum": 89 }, "example": 1 } ], "responses": { "200": { "description": "Checksum of the index of the chapters of a book", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Sha1File" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/{book}/checksum.json Checksums of the chapters of a book The SHA-1 checksum of every chapter file of the book, keyed by chapter number. Operation ID: `listChapterChecksums`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | | `book` | path | Yes | integer | 1 | Book number, as listed in the books.json of the translation | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksums of the chapters of a book | application/json | #/components/schemas/ChecksumIndex | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksums of the chapters of a book", "description": "The SHA-1 checksum of every chapter file of the book, keyed by chapter number.", "operationId": "listChapterChecksums", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" }, { "name": "book", "in": "path", "required": true, "description": "Book number, as listed in the books.json of the translation", "schema": { "type": "integer", "minimum": 1, "maximum": 89 }, "example": 1 } ], "responses": { "200": { "description": "Checksums of the chapters of a book", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChecksumIndex" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/{book}/checksum.txt Checksums of the chapters of a book as text The SHA-1 checksum of every chapter file of the book, one per line, with the columns: #, filename, sha. Operation ID: `listChapterChecksumsText`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | | `book` | path | Yes | integer | 1 | Book number, as listed in the books.json of the translation | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksums of the chapters of a book as text | text/plain | #/components/schemas/TabSeparatedIndex | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksums of the chapters of a book as text", "description": "The SHA-1 checksum of every chapter file of the book, one per line, with the columns: #, filename, sha.", "operationId": "listChapterChecksumsText", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" }, { "name": "book", "in": "path", "required": true, "description": "Book number, as listed in the books.json of the translation", "schema": { "type": "integer", "minimum": 1, "maximum": 89 }, "example": 1 } ], "responses": { "200": { "description": "Checksums of the chapters of a book as text", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/TabSeparatedIndex" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/{book}/checksum.sha Checksum of the checksums of the chapters of a book The SHA-1 checksum of the checksum.json of the book. Operation ID: `getChapterChecksumIndexChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | | `book` | path | Yes | integer | 1 | Book number, as listed in the books.json of the translation | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksum of the checksums of the chapters of a book | text/plain | #/components/schemas/Sha1File | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksum of the checksums of the chapters of a book", "description": "The SHA-1 checksum of the checksum.json of the book.", "operationId": "getChapterChecksumIndexChecksum", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" }, { "name": "book", "in": "path", "required": true, "description": "Book number, as listed in the books.json of the translation", "schema": { "type": "integer", "minimum": 1, "maximum": 89 }, "example": 1 } ], "responses": { "200": { "description": "Checksum of the checksums of the chapters of a book", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Sha1File" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/{book}/{chapter}.json A complete chapter One chapter of a book with every verse. Operation ID: `getChapter`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | | `book` | path | Yes | integer | 1 | Book number, as listed in the books.json of the translation | | `chapter` | path | Yes | integer | 1 | Chapter number, as listed in the chapters.json of the book | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | A complete chapter | application/json | #/components/schemas/Chapter | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "chapters" ], "summary": "A complete chapter", "description": "One chapter of a book with every verse.", "operationId": "getChapter", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" }, { "name": "book", "in": "path", "required": true, "description": "Book number, as listed in the books.json of the translation", "schema": { "type": "integer", "minimum": 1, "maximum": 89 }, "example": 1 }, { "name": "chapter", "in": "path", "required": true, "description": "Chapter number, as listed in the chapters.json of the book", "schema": { "type": "integer", "minimum": 1 }, "example": 1 } ], "responses": { "200": { "description": "A complete chapter", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Chapter" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /{abbreviation}/{book}/{chapter}.sha Checksum of a chapter The SHA-1 checksum of the chapter file. Operation ID: `getChapterChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `abbreviation` | path | Yes | string | kjv | Abbreviation of the translation, as listed in translations.json | | `book` | path | Yes | integer | 1 | Book number, as listed in the books.json of the translation | | `chapter` | path | Yes | integer | 1 | Chapter number, as listed in the chapters.json of the book | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksum of a chapter | text/plain | #/components/schemas/Sha1File | | 404 | No such file: the translation, book or chapter is not part of this tree | — | See contract |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksum of a chapter", "description": "The SHA-1 checksum of the chapter file.", "operationId": "getChapterChecksum", "parameters": [ { "name": "abbreviation", "in": "path", "required": true, "description": "Abbreviation of the translation, as listed in translations.json", "schema": { "type": "string", "pattern": "^[a-z0-9]+$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] }, "example": "kjv" }, { "name": "book", "in": "path", "required": true, "description": "Book number, as listed in the books.json of the translation", "schema": { "type": "integer", "minimum": 1, "maximum": 89 }, "example": 1 }, { "name": "chapter", "in": "path", "required": true, "description": "Chapter number, as listed in the chapters.json of the book", "schema": { "type": "integer", "minimum": 1 }, "example": 1 } ], "responses": { "200": { "description": "Checksum of a chapter", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Sha1File" } } } }, "404": { "$ref": "#/components/responses/NotFound" } } } ```
## GET /openapi.json This document The OpenAPI description of this tree, written at the end of the build that produced it. Operation ID: `getOpenApi`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | OpenAPI 3.1 document | application/json | object |
Complete operation contract ```json { "summary": "This document", "description": "The OpenAPI description of this tree, written at the end of the build that produced it.", "operationId": "getOpenApi", "responses": { "200": { "description": "OpenAPI 3.1 document", "content": { "application/json": { "schema": { "type": "object" } } } } }, "parameters": [] } ```
## GET /openapi.sha Checksum of this document The SHA-1 checksum of openapi.json. Operation ID: `getOpenApiChecksum`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Checksum of this document | text/plain | #/components/schemas/Sha1File |
Complete operation contract ```json { "tags": [ "checksums" ], "summary": "Checksum of this document", "description": "The SHA-1 checksum of openapi.json.", "operationId": "getOpenApiChecksum", "responses": { "200": { "description": "Checksum of this document", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/Sha1File" } } } } }, "parameters": [] } ```
## Component schemas Types, required properties, nested objects, constraints and examples below are copied directly from the contract. A property omitted from a schema’s `required` array is optional, even when examples include it. ### Direction Writing direction of the text
View full Direction schema ```json { "type": "string", "description": "Writing direction of the text", "enum": [ "LTR", "RTL" ] } ```
### Sha1 SHA-1 checksum of a JSON file, as 40 lowercase hexadecimal characters
View full Sha1 schema ```json { "type": "string", "description": "SHA-1 checksum of a JSON file, as 40 lowercase hexadecimal characters", "pattern": "^[0-9a-f]{40}$" } ```
### Sha1File The content of a .sha file: the SHA-1 checksum of the JSON file with the same name, as 40 lowercase hexadecimal characters followed by a newline
View full Sha1File schema ```json { "type": "string", "description": "The content of a .sha file: the SHA-1 checksum of the JSON file with the same name, as 40 lowercase hexadecimal characters followed by a newline", "pattern": "^[0-9a-f]{40}\\s*$" } ```
### TabSeparatedIndex The content of a .txt index file: a header line starting with # that names the columns, then one tab-separated line per file
View full TabSeparatedIndex schema ```json { "type": "string", "description": "The content of a .txt index file: a header line starting with # that names the columns, then one tab-separated line per file" } ```
### Verse One verse
View full Verse schema ```json { "type": "object", "description": "One verse", "properties": { "chapter": { "type": "integer", "description": "Chapter number", "minimum": 1 }, "verse": { "type": "integer", "description": "Verse number", "minimum": 1 }, "name": { "type": "string", "description": "Name of the verse, as book name, chapter and verse" }, "text": { "type": "string", "description": "Text of the verse" } }, "required": [ "chapter", "verse", "name", "text" ] } ```
### BookChapter One chapter with its verses
View full BookChapter schema ```json { "type": "object", "description": "One chapter with its verses", "properties": { "chapter": { "type": "integer", "description": "Chapter number", "minimum": 1 }, "name": { "type": "string", "description": "Name of the chapter, as book name and chapter" }, "verses": { "type": "array", "description": "Verses of the chapter", "items": { "$ref": "#/components/schemas/Verse" } } }, "required": [ "chapter", "name", "verses" ] } ```
### TranslationBook One book with its chapters
View full TranslationBook schema ```json { "type": "object", "description": "One book with its chapters", "properties": { "nr": { "type": "integer", "description": "Book number", "minimum": 1 }, "name": { "type": "string", "description": "Name of the book in the translation" }, "chapters": { "type": "array", "description": "Chapters of the book", "items": { "$ref": "#/components/schemas/BookChapter" } } }, "required": [ "nr", "name", "chapters" ] } ```
### Translation A complete translation file
View full Translation schema ```json { "type": "object", "description": "A complete translation file", "properties": { "translation": { "type": "string", "description": "Name of the translation" }, "abbreviation": { "type": "string", "description": "Abbreviation of the translation, used as its file and folder name", "pattern": "^[a-z0-9]+$" }, "description": { "type": "string", "description": "Description of the translation from the source module" }, "lang": { "type": "string", "description": "Language code of the translation" }, "language": { "type": "string", "description": "Name of the language in English" }, "direction": { "$ref": "#/components/schemas/Direction" }, "encoding": { "type": "string", "description": "Character encoding of the source module" }, "books": { "type": "array", "description": "Books of the translation", "items": { "$ref": "#/components/schemas/TranslationBook" } }, "distribution_lcsh": { "type": "string", "description": "Library of Congress subject heading of the source module" }, "distribution_version": { "type": "string", "description": "Version of the source module" }, "distribution_version_date": { "type": "string", "description": "Date of the source module version" }, "distribution_abbreviation": { "type": "string", "description": "Abbreviation of the source module" }, "distribution_about": { "type": "string", "description": "About text of the source module" }, "distribution_license": { "type": "string", "description": "Distribution license of the source module text" }, "distribution_sourcetype": { "type": "string", "description": "Markup type of the source module text" }, "distribution_source": { "type": "string", "description": "Origin of the source module text" }, "distribution_versification": { "type": "string", "description": "Versification of the source module" }, "distribution_history": { "type": "object", "description": "Change history of the source module, keyed by history entry", "additionalProperties": { "type": "string" } } }, "required": [ "translation", "abbreviation", "description", "lang", "language", "direction", "encoding", "books", "distribution_lcsh", "distribution_version", "distribution_version_date", "distribution_abbreviation", "distribution_about", "distribution_license", "distribution_sourcetype", "distribution_source", "distribution_versification", "distribution_history" ] } ```
### TranslationSummary A translation as listed in translations.json (the translation file without its books)
View full TranslationSummary schema ```json { "type": "object", "description": "A translation as listed in translations.json (the translation file without its books)", "properties": { "translation": { "type": "string", "description": "Name of the translation" }, "abbreviation": { "type": "string", "description": "Abbreviation of the translation, used as its file and folder name", "pattern": "^[a-z0-9]+$" }, "description": { "type": "string", "description": "Description of the translation from the source module" }, "lang": { "type": "string", "description": "Language code of the translation" }, "language": { "type": "string", "description": "Name of the language in English" }, "direction": { "$ref": "#/components/schemas/Direction" }, "encoding": { "type": "string", "description": "Character encoding of the source module" }, "distribution_lcsh": { "type": "string", "description": "Library of Congress subject heading of the source module" }, "distribution_version": { "type": "string", "description": "Version of the source module" }, "distribution_version_date": { "type": "string", "description": "Date of the source module version" }, "distribution_abbreviation": { "type": "string", "description": "Abbreviation of the source module" }, "distribution_about": { "type": "string", "description": "About text of the source module" }, "distribution_license": { "type": "string", "description": "Distribution license of the source module text" }, "distribution_sourcetype": { "type": "string", "description": "Markup type of the source module text" }, "distribution_source": { "type": "string", "description": "Origin of the source module text" }, "distribution_versification": { "type": "string", "description": "Versification of the source module" }, "distribution_history": { "type": "object", "description": "Change history of the source module, keyed by history entry", "additionalProperties": { "type": "string" } }, "url": { "type": "string", "description": "Address of the translation file", "format": "uri" }, "sha": { "$ref": "#/components/schemas/Sha1", "description": "SHA-1 checksum of the translation file" } }, "required": [ "translation", "abbreviation", "description", "lang", "language", "direction", "encoding", "distribution_lcsh", "distribution_version", "distribution_version_date", "distribution_abbreviation", "distribution_about", "distribution_license", "distribution_sourcetype", "distribution_source", "distribution_versification", "distribution_history", "url", "sha" ] } ```
### TranslationIndex Every translation in the tree, keyed by abbreviation
View full TranslationIndex schema ```json { "type": "object", "description": "Every translation in the tree, keyed by abbreviation", "propertyNames": { "pattern": "^[a-z0-9]+$" }, "additionalProperties": { "$ref": "#/components/schemas/TranslationSummary" } } ```
### Book A complete book file
View full Book schema ```json { "type": "object", "description": "A complete book file", "properties": { "translation": { "type": "string", "description": "Name of the translation" }, "abbreviation": { "type": "string", "description": "Abbreviation of the translation, used as its file and folder name", "pattern": "^[a-z0-9]+$" }, "lang": { "type": "string", "description": "Language code of the translation" }, "language": { "type": "string", "description": "Name of the language in English" }, "direction": { "$ref": "#/components/schemas/Direction" }, "encoding": { "type": "string", "description": "Character encoding of the source module" }, "nr": { "type": "integer", "description": "Book number", "minimum": 1 }, "name": { "type": "string", "description": "Name of the book in the translation" }, "chapters": { "type": "array", "description": "Chapters of the book", "items": { "$ref": "#/components/schemas/BookChapter" } } }, "required": [ "translation", "abbreviation", "lang", "language", "direction", "encoding", "nr", "name", "chapters" ] } ```
### BookSummary A book as listed in books.json (the book file without its chapters)
View full BookSummary schema ```json { "type": "object", "description": "A book as listed in books.json (the book file without its chapters)", "properties": { "translation": { "type": "string", "description": "Name of the translation" }, "abbreviation": { "type": "string", "description": "Abbreviation of the translation, used as its file and folder name", "pattern": "^[a-z0-9]+$" }, "lang": { "type": "string", "description": "Language code of the translation" }, "language": { "type": "string", "description": "Name of the language in English" }, "direction": { "$ref": "#/components/schemas/Direction" }, "encoding": { "type": "string", "description": "Character encoding of the source module" }, "nr": { "type": "integer", "description": "Book number", "minimum": 1 }, "name": { "type": "string", "description": "Name of the book in the translation" }, "url": { "type": "string", "description": "Address of the book file", "format": "uri" }, "sha": { "$ref": "#/components/schemas/Sha1", "description": "SHA-1 checksum of the book file" } }, "required": [ "translation", "abbreviation", "lang", "language", "direction", "encoding", "nr", "name", "url", "sha" ] } ```
### BookIndex Every book of a translation, keyed by book number
View full BookIndex schema ```json { "type": "object", "description": "Every book of a translation, keyed by book number", "propertyNames": { "pattern": "^[0-9]+$" }, "additionalProperties": { "$ref": "#/components/schemas/BookSummary" } } ```
### Chapter A complete chapter file
View full Chapter schema ```json { "type": "object", "description": "A complete chapter file", "properties": { "translation": { "type": "string", "description": "Name of the translation" }, "abbreviation": { "type": "string", "description": "Abbreviation of the translation, used as its file and folder name", "pattern": "^[a-z0-9]+$" }, "lang": { "type": "string", "description": "Language code of the translation" }, "language": { "type": "string", "description": "Name of the language in English" }, "direction": { "$ref": "#/components/schemas/Direction" }, "encoding": { "type": "string", "description": "Character encoding of the source module" }, "book_nr": { "type": "integer", "description": "Book number", "minimum": 1 }, "book_name": { "type": "string", "description": "Name of the book in the translation" }, "chapter": { "type": "integer", "description": "Chapter number", "minimum": 1 }, "name": { "type": "string", "description": "Name of the chapter, as book name and chapter" }, "verses": { "type": "array", "description": "Verses of the chapter", "items": { "$ref": "#/components/schemas/Verse" } } }, "required": [ "translation", "abbreviation", "lang", "language", "direction", "encoding", "book_nr", "book_name", "chapter", "name", "verses" ] } ```
### ChapterSummary A chapter as listed in chapters.json (the chapter file without its verses)
View full ChapterSummary schema ```json { "type": "object", "description": "A chapter as listed in chapters.json (the chapter file without its verses)", "properties": { "translation": { "type": "string", "description": "Name of the translation" }, "abbreviation": { "type": "string", "description": "Abbreviation of the translation, used as its file and folder name", "pattern": "^[a-z0-9]+$" }, "lang": { "type": "string", "description": "Language code of the translation" }, "language": { "type": "string", "description": "Name of the language in English" }, "direction": { "$ref": "#/components/schemas/Direction" }, "encoding": { "type": "string", "description": "Character encoding of the source module" }, "book_nr": { "type": "integer", "description": "Book number", "minimum": 1 }, "book_name": { "type": "string", "description": "Name of the book in the translation" }, "chapter": { "type": "integer", "description": "Chapter number", "minimum": 1 }, "name": { "type": "string", "description": "Name of the chapter, as book name and chapter" }, "url": { "type": "string", "description": "Address of the chapter file", "format": "uri" }, "sha": { "$ref": "#/components/schemas/Sha1", "description": "SHA-1 checksum of the chapter file" } }, "required": [ "translation", "abbreviation", "lang", "language", "direction", "encoding", "book_nr", "book_name", "chapter", "name", "url", "sha" ] } ```
### ChapterIndex Every chapter of a book, keyed by chapter number
View full ChapterIndex schema ```json { "type": "object", "description": "Every chapter of a book, keyed by chapter number", "propertyNames": { "pattern": "^[0-9]+$" }, "additionalProperties": { "$ref": "#/components/schemas/ChapterSummary" } } ```
### ChecksumIndex The SHA-1 checksum of every JSON file at this level, keyed by file name without extension
View full ChecksumIndex schema ```json { "type": "object", "description": "The SHA-1 checksum of every JSON file at this level, keyed by file name without extension", "propertyNames": { "pattern": "^[a-z0-9]+$" }, "additionalProperties": { "$ref": "#/components/schemas/Sha1" } } ```
## Authentication contract ```json { "security": [], "securitySchemes": {} } ``` See [access and tokens](/tokens/) for public usage and token requests. --- Bible v3 publishes Scripture text together with the source information needed for richer reading and study applications. The basic translation → book → chapter → verse structure is familiar from v2. Optional metadata adds word-level lexical attributes, annotations, paragraph starts, chapter layout and introductory material when the source supplies them. **Base URL:** `https://api.getbible.net/v3/` [Live documentation](https://api.getbible.net/v3/) · [OpenAPI JSON](https://api.getbible.net/v3/openapi.json) · [All Bible API versions](/api/bible/) · [Support](https://git.vdm.dev/getBible/support) ## Quick start ```bash # Read a chapter with its available v3 metadata curl --fail-with-body --compressed \ 'https://api.getbible.net/v3/kjv/43/3.json' # Read a complete book curl --fail-with-body --compressed \ 'https://api.getbible.net/v3/kjv/43.json' # Download an entire translation for offline reading curl --fail-with-body --compressed \ 'https://api.getbible.net/v3/kjv.json' --output kjv-v3.json ``` The static API returns published files and accepts no URL query parameters. To resolve `John3:16`, use [Query v3](/api/query/v3/). To find verses containing words, use [Search v3](/api/search/v3/). ## Inventory and addresses ```bash curl --fail-with-body --compressed 'https://api.getbible.net/v3/translations.json' curl --fail-with-body --compressed 'https://api.getbible.net/v3/kjv/books.json' curl --fail-with-body --compressed 'https://api.getbible.net/v3/kjv/43/chapters.json' ``` Indexes are JSON objects keyed by translation abbreviation, book number or chapter number. Follow each entry's `url` and retain its `sha`. They list the resources actually published for the selected translation. | Parameter | Type | Rules | | --- | --- | --- | | `translation` | String | Abbreviation from `translations.json`; pattern `^[a-z0-9][a-z0-9_-]{0,29}$` | | `book` | Integer | Actual number listed by `books.json`; minimum 1, maximum 281474977710655 | | `chapter` | Integer | Positive chapter number from the book's `chapters.json` | Established addresses remain stable: Genesis is 1, Matthew 40, John 43 and Revelation 66. Established additional books continue through 89. Previously unseen source book identities can receive deterministic numbers starting at 1000000. Those values remain exactly representable in JavaScript; avoid storing book identifiers in a database column restricted to a tiny integer or assuming every translation ends at book 66. Chapter and verse numbering follows the translation's own versification. A book containing only source titles or introductions can be present even if its `chapters` array is empty. A chapter with introductory material but no verse text remains inside its book/translation with an empty `verses` array; it has no standalone chapter file or chapter-index entry. These cases preserve supplied source content without inventing Scripture positions. ## Every described resource Each path below is relative to the v3 base. Every JSON file has the listed `.sha` companion. | JSON path | Contents | Hash path | | --- | --- | --- | | `translations.json` | Translation catalogue, keyed by abbreviation | `translations.sha` | | `checksum.json` | Whole-translation hashes | `checksum.sha` | | `openapi.json` | Generated standalone OpenAPI 3.1 contract | `openapi.sha` | | `{translation}.json` | Translation and all its books | `{translation}.sha` | | `{translation}/books.json` | Book catalogue for a translation | `{translation}/books.sha` | | `{translation}/checksum.json` | Book hashes for a translation | `{translation}/checksum.sha` | | `{translation}/{book}.json` | One book and its chapters | `{translation}/{book}.sha` | | `{translation}/{book}/chapters.json` | Published chapters for a book | `{translation}/{book}/chapters.sha` | | `{translation}/{book}/checksum.json` | Chapter hashes for a book | `{translation}/{book}/checksum.sha` | | `{translation}/{book}/{chapter}.json` | One chapter and its verses | `{translation}/{book}/{chapter}.sha` | The builder also produces extensionless tab-separated companion listings, but these are not described by the v3 OpenAPI contract. Use the documented JSON indexes on the public endpoint; do not assume that v2's `.txt` routes exist in v3. ## Core response structure Standalone chapter documents contain: | Field | Type | Meaning | | --- | --- | --- | | `translation` | String | Translation display name | | `abbreviation` | String | Translation identifier | | `lang` | String | Language code supplied by the source | | `language` | String | Language label; can be empty when no label is available | | `direction` | String | Reading direction, normally `LTR` or `RTL` | | `encoding` | String | Source module encoding label; generated JSON is UTF-8 | | `book_nr` | Integer | Stable GetBible book identity | | `book_name` | String | Translation's book name | | `chapter` | Integer | Chapter number | | `name` | String | Chapter display name | | `verses` | Array | Ordered verse objects | | `editorial` | Array, optional | Ordered chapter headings and paragraph ranges | | `introduction` | Array, optional | Source introduction entries, each with `text` | A book contains the shared translation fields, `nr`, `name` and `chapters`, plus any available `titles` and `introduction`. A full translation has `books` and source distribution metadata. Nested chapters carry the same chapter-level reading data as their standalone representation after shared translation/book context is removed. Use `translations.json` for translation descriptions, history, provenance, version and distribution terms. The catalogue includes source fields such as `description`, `distribution_about`, `distribution_license`, `distribution_source`, `distribution_versification` and `distribution_history`, alongside `url` and `sha`. These broad translation details do not need to accompany every selected verse in your application. ## Reading a verse Every verse includes the core fields `chapter`, `verse`, `name` and `text`. `text` is the display text. It does not begin with a line ending; line endings within the verse are preserved. Do not rebuild display text by joining token strings: source tokens and displayed words do not always map one-to-one. | Optional field | Meaning | | --- | --- | | `paragraph: true` | The source marks this verse as beginning a paragraph | | `tokens` | Word-level records in reading order, with source lexical attributes and display positions | | `spans` | Source annotations covering token and display-word ranges | The static v3 contract pairs `tokens` and `spans` when source word markup exists; an empty span array is valid. A source without the relevant markup does not receive fabricated tokens or annotations. ## Tokens: lexical information without losing display position A token's required fields are `token`, `word_start` and `word_end`. For example, the live John 3:16 data includes this token for “the world”: ```json { "token": "the world", "lemma": { "strong": ["G3588", "G2889"], "lemma.TR": ["τον", "κοσμον"] }, "morph": { "robinson": ["T-ASM", "N-ASM"] }, "src": [6, 7], "word_start": 5, "word_end": 6 } ``` | Token member | Type | Meaning | | --- | --- | --- | | `token` | String | Visible token text; may cover more than one display word | | `word_start`, `word_end` | Integers | Inclusive positions in whitespace-separated display words, starting at 1; 0 means unlocated | | `lemma` | Object of string arrays | Lexical identifiers grouped by scheme, such as `strong` or `lemma.TR` | | `morph` | Object of string arrays | Morphological attributes grouped by source scheme | | `xlit` | Object of string arrays | Transliterations grouped by source scheme | | `src` | Array of integers/strings | Source positions carried by the module | | `gloss` | String | Source gloss when present | | `n`, `type`, `subType`, `variantType` | Strings | Additional source token attributes | | `variant`, `morphSegmented` | Booleans | Additional source flags | Only the required token members can be assumed. Lexical schemes and attributes are source-dependent; preserve them rather than replacing their grouped structure with one flat string. The [Dictionaries API](/api/dictionaries/) supplies related lexical resources, with its own discovery and key conventions. ## Spans: two coordinate systems The `spans` array describes supported annotations such as `divineName`, `transChange` and `q`. The live 1 Corinthians 13:13 data includes a supplied-word annotation: ```json { "tag": "transChange", "span": "is", "token_start": 11, "token_end": 11, "attrs": {"type": "added"}, "word_start": 14, "word_end": 14 } ``` | Coordinate | Interpretation | | --- | --- | | `token_start` / `token_end` | Zero-based, inclusive indexes into this verse's `tokens` array | | `word_start` / `word_end` | One-based, inclusive positions in whitespace-separated `text`; 0 means not located | `tag` identifies the source annotation, `span` contains its text and optional `attrs` retains its string attributes. Highlighting can use display-word ranges; lexical inspection can use token ranges. Do not treat either range as a byte or character offset. One token can span several words, so the two coordinate systems are intentionally different. ## Chapter editorial layout The optional `editorial` array is the chapter's ordered reading layout. `order` runs contiguously from 0 across headings and paragraphs. It is present consistently in the standalone chapter and the same chapter nested in a book or whole translation. ### Headings A heading contains exactly `order`, `type: "heading"`, `anchor`, `text`, `heading_type` and `canonical`. `anchor.verse` is an emitted verse in this chapter; `anchor.edge` is `before`. ```json { "order": 0, "type": "heading", "anchor": {"verse": 1, "edge": "before"}, "text": "CHAPTER 3.", "heading_type": "chapter", "canonical": false } ``` `heading_type` reflects the source title type, or `unspecified` when absent. `canonical` is true only when explicitly marked by the source. It records source metadata and is not an independent theological judgment by the builder. ### Paragraphs A paragraph contains exactly `order`, `type: "paragraph"`, `start` and `end`. Its range is inclusive and uses emitted verse numbers in the current chapter: ```json { "order": 3, "type": "paragraph", "start": 16, "end": 17 } ``` When paragraph entries exist, their ranges cover the chapter's emitted verses contiguously. An implicit opening range can precede the first explicit paragraph start. If the source supplies no paragraph starts, no paragraph ranges are manufactured. Headings may still exist. The entire `editorial` field is absent when there are neither headings nor explicit paragraph markers. Chapters containing verses do not duplicate headings in a `titles` array, and verse objects do not contain `titles`. Use `editorial` for their headings. A chapter without published verses may retain title metadata only in its nested representation. ## Titles and introductions Titles belong to the translation or book that supplies them. A title has `text` and may also carry `type`, `canonical`, `subtype`, and title-local `tokens`/`spans` when available. Introduction prose is an array of objects with a `text` member, placed at the translation, book or chapter level. Optional data is absent when the source has nothing to provide. The published API deliberately excludes the extraction stream's raw byte projections, base64 fields and source-contract envelopes. The reading representation is documented by the [builder's checked-in schemas](https://github.com/getbible/v3_builder/tree/master/schema) and generated [OpenAPI contract](https://api.getbible.net/v3/openapi.json). ## Integrate with query and search [Query v3](/api/query/v3/) and [Search v3](/api/search/v3/) preserve the selected verses' full source objects, including nested `tokens` and `spans`. Their assembled chapter results carry compact translation metadata and intentionally omit static chapter-level `editorial`. Fetch the static chapter when the application needs full paragraph and heading layout. For an app moving from v2, keep its text renderer, add optional metadata handling and partition caches by API version. Validate the translations actually required by the app; do not assume that changing `/v2/` to `/v3/` supplies identical data, catalogue contents or hashes. ## Caching, hashes and access Every JSON resource has a `.sha` sibling containing its SHA-1 as 40 lowercase hexadecimal characters and a newline. Hashes identify the exact JSON bytes. Index entries also provide the `sha` of their target. Re-download and atomically replace changed documents with their matching hashes; do not hash a pretty-printed transformation and compare it with the original file hash. HTTP freshness is separate. Respect returned `Cache-Control`, use `ETag` with `If-None-Match`, and treat `304` as permission to reuse the saved body. Static files also provide `Last-Modified`. Open CORS allows browser access. The accepted methods are GET, HEAD and OPTIONS; query strings are rejected. Public access is metered by client address. Applications and partners can [request a bearer token](mailto:getBible@TrueChristian.church) or contact [support](https://git.vdm.dev/getBible/support). A token is scoped to its issuing domain and must be sent in an `Authorization: Bearer` header, never in a query parameter. Public rate exemption does not bypass structural or execution limits. ## Errors | HTTP | Code | Meaning | | --- | --- | --- | | 400 | `bad_request` | Malformed request or a query string on a static path | | 401 | `unauthorized` | Missing/invalid credential when token-only access is configured | | 404 | `not_found` | Resource not published at that path | | 405 | `method_not_allowed` | Use GET, HEAD or OPTIONS | | 429 | `rate_limited` | Respect the response's `Retry-After` value | | 503 | `unavailable` | Temporary service outage | Error bodies use `application/problem+json` and carry `type`, `title`, `status`, `code`, `detail` and `instance`. Include the `X-Request-ID` response header in a [support request](https://git.vdm.dev/getBible/support). ## OpenAPI import and sources The v3 specification intentionally has no host in `servers` and its paths already begin with `/v3`. When importing the raw contract into Postman, set the server/base host to `https://api.getbible.net` if the importer asks. The resulting chapter request must be `https://api.getbible.net/v3/kjv/43/3.json`, with the version appearing once. This guide follows the [live v3 contract](https://api.getbible.net/v3/openapi.json), [live service documentation](https://api.getbible.net/v3/), [generated-output documentation](https://github.com/getbible/v3_builder/blob/master/docs/static-output.md), and [runtime response contract](https://github.com/getbible/api/blob/main/docs/RUNTIME_ENDPOINTS.md). ## Complete contract reference Open the [complete endpoint and schema reference](/api/bible/v3/reference/) for every operation, parameter, response and component model in the published OpenAPI contract. --- # Bible API v3: endpoint and schema reference This reference is generated from the checked-in [OpenAPI contract](https://api.getbible.net/v3/openapi.json). Return to the [integration guide](/api/bible/v3/) for workflows and ready-to-run examples. Resolved request server: `https://api.getbible.net`. ## GET /v3/translations.json Every translation in the tree The translation index: every translation with its metadata, the URL its document was built for and the SHA-1 of that document. Operation ID: `getTranslations`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Every translation in the tree | application/json | #/components/schemas/translations-index | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "Every translation in the tree", "description": "The translation index: every translation with its metadata, the URL its document was built for and the SHA-1 of that document.", "operationId": "getTranslations", "responses": { "200": { "description": "Every translation in the tree", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/translations-index" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } }, "parameters": [] } ```
## GET /v3/translations.sha The SHA-1 of the translation index Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the translation index. Operation ID: `getTranslationsChecksum`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of the translation index | text/plain | #/components/schemas/checksum | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The SHA-1 of the translation index", "description": "Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the translation index.", "operationId": "getTranslationsChecksum", "responses": { "200": { "description": "The SHA-1 of the translation index", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/checksum" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } }, "parameters": [] } ```
## GET /v3/checksum.json The SHA-1 of every translation document Every translation's abbreviation mapped to the SHA-1 of its document. Operation ID: `getTranslationChecksums`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of every translation document | application/json | #/components/schemas/checksum-index | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The SHA-1 of every translation document", "description": "Every translation's abbreviation mapped to the SHA-1 of its document.", "operationId": "getTranslationChecksums", "responses": { "200": { "description": "The SHA-1 of every translation document", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/checksum-index" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } }, "parameters": [] } ```
## GET /v3/checksum.sha The SHA-1 of the translation checksum index Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the translation checksum index. Operation ID: `getTranslationChecksumsChecksum`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of the translation checksum index | text/plain | #/components/schemas/checksum | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The SHA-1 of the translation checksum index", "description": "Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the translation checksum index.", "operationId": "getTranslationChecksumsChecksum", "responses": { "200": { "description": "The SHA-1 of the translation checksum index", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/checksum" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } }, "parameters": [] } ```
## GET /v3/openapi.json This description The OpenAPI description of the tree, generated with it. Operation ID: `getOpenApi`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | This description | application/json | object | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "This description", "description": "The OpenAPI description of the tree, generated with it.", "operationId": "getOpenApi", "responses": { "200": { "description": "This description", "content": { "application/json": { "schema": { "type": "object" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } }, "parameters": [] } ```
## GET /v3/openapi.sha The SHA-1 of this description Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of this description. Operation ID: `getOpenApiChecksum`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of this description | text/plain | #/components/schemas/checksum | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The SHA-1 of this description", "description": "Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of this description.", "operationId": "getOpenApiChecksum", "responses": { "200": { "description": "The SHA-1 of this description", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/checksum" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } }, "parameters": [] } ```
## GET /v3/{translation}.json The whole translation Every book, chapter and verse of one translation with its metadata and the source module's distribution metadata. A bulk document: translations.json carries its digest. Operation ID: `getTranslation`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The whole translation | application/json | #/components/schemas/translation | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "translation" ], "summary": "The whole translation", "description": "Every book, chapter and verse of one translation with its metadata and the source module's distribution metadata. A bulk document: translations.json carries its digest.", "operationId": "getTranslation", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } } ], "responses": { "200": { "description": "The whole translation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/translation" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}.sha The SHA-1 of the translation document Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the translation document. Operation ID: `getTranslationChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of the translation document | text/plain | #/components/schemas/checksum | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "translation" ], "summary": "The SHA-1 of the translation document", "description": "Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the translation document.", "operationId": "getTranslationChecksum", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } } ], "responses": { "200": { "description": "The SHA-1 of the translation document", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/checksum" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/books.json Every book of one translation The book index of a translation: every book with its number, name and title metadata, the URL its document was built for and the SHA-1 of that document. Operation ID: `getBooks`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Every book of one translation | application/json | #/components/schemas/books-index | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "translation" ], "summary": "Every book of one translation", "description": "The book index of a translation: every book with its number, name and title metadata, the URL its document was built for and the SHA-1 of that document.", "operationId": "getBooks", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } } ], "responses": { "200": { "description": "Every book of one translation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/books-index" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/books.sha The SHA-1 of the book index Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the book index. Operation ID: `getBooksChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of the book index | text/plain | #/components/schemas/checksum | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "translation" ], "summary": "The SHA-1 of the book index", "description": "Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the book index.", "operationId": "getBooksChecksum", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } } ], "responses": { "200": { "description": "The SHA-1 of the book index", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/checksum" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/checksum.json The SHA-1 of every book document of one translation Every book number mapped to the SHA-1 of its document. Operation ID: `getBookChecksums`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of every book document of one translation | application/json | #/components/schemas/checksum-index | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "translation" ], "summary": "The SHA-1 of every book document of one translation", "description": "Every book number mapped to the SHA-1 of its document.", "operationId": "getBookChecksums", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } } ], "responses": { "200": { "description": "The SHA-1 of every book document of one translation", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/checksum-index" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/checksum.sha The SHA-1 of the book checksum index Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the book checksum index. Operation ID: `getBookChecksumsChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of the book checksum index | text/plain | #/components/schemas/checksum | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "translation" ], "summary": "The SHA-1 of the book checksum index", "description": "Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the book checksum index.", "operationId": "getBookChecksumsChecksum", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } } ], "responses": { "200": { "description": "The SHA-1 of the book checksum index", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/checksum" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/{book}.json One book Every chapter and verse of one book with the translation's metadata and the book's title metadata and introduction. Operation ID: `getBook`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | | `book` | path | Yes | integer | 1 | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | One book | application/json | #/components/schemas/book | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "book" ], "summary": "One book", "description": "Every chapter and verse of one book with the translation's metadata and the book's title metadata and introduction.", "operationId": "getBook", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } }, { "name": "book", "in": "path", "required": true, "description": "GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has.", "schema": { "type": "integer", "minimum": 1, "maximum": 281474977710655 } } ], "responses": { "200": { "description": "One book", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/book" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/{book}.sha The SHA-1 of the book document Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the book document. Operation ID: `getBookChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | | `book` | path | Yes | integer | 1 | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of the book document | text/plain | #/components/schemas/checksum | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "book" ], "summary": "The SHA-1 of the book document", "description": "Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the book document.", "operationId": "getBookChecksum", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } }, { "name": "book", "in": "path", "required": true, "description": "GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has.", "schema": { "type": "integer", "minimum": 1, "maximum": 281474977710655 } } ], "responses": { "200": { "description": "The SHA-1 of the book document", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/checksum" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/{book}/chapters.json Every chapter of one book The chapter index of a book: every chapter with its number, name and reading layout, the URL its document was built for and the SHA-1 of that document. Operation ID: `getChapters`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | | `book` | path | Yes | integer | 1 | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Every chapter of one book | application/json | #/components/schemas/chapters-index | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "book" ], "summary": "Every chapter of one book", "description": "The chapter index of a book: every chapter with its number, name and reading layout, the URL its document was built for and the SHA-1 of that document.", "operationId": "getChapters", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } }, { "name": "book", "in": "path", "required": true, "description": "GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has.", "schema": { "type": "integer", "minimum": 1, "maximum": 281474977710655 } } ], "responses": { "200": { "description": "Every chapter of one book", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/chapters-index" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/{book}/chapters.sha The SHA-1 of the chapter index Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the chapter index. Operation ID: `getChaptersChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | | `book` | path | Yes | integer | 1 | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of the chapter index | text/plain | #/components/schemas/checksum | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "book" ], "summary": "The SHA-1 of the chapter index", "description": "Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the chapter index.", "operationId": "getChaptersChecksum", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } }, { "name": "book", "in": "path", "required": true, "description": "GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has.", "schema": { "type": "integer", "minimum": 1, "maximum": 281474977710655 } } ], "responses": { "200": { "description": "The SHA-1 of the chapter index", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/checksum" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/{book}/checksum.json The SHA-1 of every chapter document of one book Every chapter number mapped to the SHA-1 of its document. Operation ID: `getChapterChecksums`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | | `book` | path | Yes | integer | 1 | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of every chapter document of one book | application/json | #/components/schemas/checksum-index | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "book" ], "summary": "The SHA-1 of every chapter document of one book", "description": "Every chapter number mapped to the SHA-1 of its document.", "operationId": "getChapterChecksums", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } }, { "name": "book", "in": "path", "required": true, "description": "GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has.", "schema": { "type": "integer", "minimum": 1, "maximum": 281474977710655 } } ], "responses": { "200": { "description": "The SHA-1 of every chapter document of one book", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/checksum-index" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/{book}/checksum.sha The SHA-1 of the chapter checksum index Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the chapter checksum index. Operation ID: `getChapterChecksumsChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | | `book` | path | Yes | integer | 1 | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of the chapter checksum index | text/plain | #/components/schemas/checksum | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "book" ], "summary": "The SHA-1 of the chapter checksum index", "description": "Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the chapter checksum index.", "operationId": "getChapterChecksumsChecksum", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } }, { "name": "book", "in": "path", "required": true, "description": "GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has.", "schema": { "type": "integer", "minimum": 1, "maximum": 281474977710655 } } ], "responses": { "200": { "description": "The SHA-1 of the chapter checksum index", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/checksum" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/{book}/{chapter}.json One chapter Every verse of one chapter with the translation's metadata, the book it belongs to, and its reading layout and introduction when the source supplies them. Operation ID: `getChapter`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | | `book` | path | Yes | integer | 1 | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has. | | `chapter` | path | Yes | integer | 1 | Chapter number; chapters.json lists the chapters the book has. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | One chapter | application/json | #/components/schemas/chapter | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "chapter" ], "summary": "One chapter", "description": "Every verse of one chapter with the translation's metadata, the book it belongs to, and its reading layout and introduction when the source supplies them.", "operationId": "getChapter", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } }, { "name": "book", "in": "path", "required": true, "description": "GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has.", "schema": { "type": "integer", "minimum": 1, "maximum": 281474977710655 } }, { "name": "chapter", "in": "path", "required": true, "description": "Chapter number; chapters.json lists the chapters the book has.", "schema": { "type": "integer", "minimum": 1 } } ], "responses": { "200": { "description": "One chapter", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/chapter" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## GET /v3/{translation}/{book}/{chapter}.sha The SHA-1 of the chapter document Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the chapter document. Operation ID: `getChapterChecksum`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | The translation's abbreviation, as translations.json lists it. | | `book` | path | Yes | integer | 1 | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has. | | `chapter` | path | Yes | integer | 1 | Chapter number; chapters.json lists the chapters the book has. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-1 of the chapter document | text/plain | #/components/schemas/checksum | | 404 | No such document. The tree is static: a document the index documents do not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "chapter" ], "summary": "The SHA-1 of the chapter document", "description": "Forty hexadecimal digits and a line feed: the SHA-1 of the bytes of the chapter document.", "operationId": "getChapterChecksum", "parameters": [ { "name": "translation", "in": "path", "required": true, "description": "The translation's abbreviation, as translations.json lists it.", "schema": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "enum": [ "akjv", "alb", "aleppo", "almeida", "aov", "arabicsv", "asv", "basicenglish", "basque", "bibelselskap", "bkr", "breton", "burcbcm", "calo", "canisius", "cep", "chamorro", "che1860", "chiunl", "cns", "cnt", "codex", "coptic", "cornilescu", "croatia", "csielizabeth", "cus", "cut", "danish", "danish1819", "danish1871", "darby", "dari", "douayrheims", "easternarmenian", "elberfelder", "elberfelder1905", "esperanto", "estonian", "finnish1776", "gaelic", "giovanni", "gothic", "japbungo", "japdenmo", "japkougo", "japraguet", "judson", "karoli", "kjv", "kjva", "klv", "korean", "koreankjv", "latvian", "lithuanian", "livre", "livretr", "ls1910", "luther1545", "lxx", "mal1910", "manxgaelic", "maori", "martin", "mg1865", "moderngreek", "modernhebrew", "monkjv", "ndebele", "norsmb", "peshitta", "pohnold", "pohnpeian", "polgdanska", "polugdanska", "potawatomi", "pyharaamattu1933", "pyharaamattu1992", "riveduta", "rv1858", "sahidic", "schlachter", "shona", "srkdekavski", "srkdijekav", "sse", "statenvertaling", "statenvertalinga", "swahili", "swedish", "swekarlxii", "swekarlxii1873", "synodal", "tagalog", "tausug", "textusreceptus", "thai", "tischendorf", "tpikjpb", "turhadi", "turkish", "tyndale", "ukranian", "ukrogienko", "uma", "valera", "vietnamese", "vulgate", "wb", "web", "westcotthort", "westernarmenian", "weymouth", "wycliffe", "ylt", "zhuromsky" ] } }, { "name": "book", "in": "path", "required": true, "description": "GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and established additional books continue to 89. Further source identities receive deterministic numbers from 1000000. books.json lists the numbers the translation has.", "schema": { "type": "integer", "minimum": 1, "maximum": 281474977710655 } }, { "name": "chapter", "in": "path", "required": true, "description": "Chapter number; chapters.json lists the chapters the book has.", "schema": { "type": "integer", "minimum": 1 } } ], "responses": { "200": { "description": "The SHA-1 of the chapter document", "content": { "text/plain": { "schema": { "$ref": "#/components/schemas/checksum" } } } }, "404": { "description": "No such document. The tree is static: a document the index documents do not list does not exist." } } } ```
## Component schemas Types, required properties, nested objects, constraints and examples below are copied directly from the contract. A property omitted from a schema’s `required` array is optional, even when examples include it. ### translation One whole translation: its metadata, the source module's description and distribution metadata, title metadata and introductions attached at the translation level, and every book with every chapter and verse. A bulk document; translations.json states its size through its url and sha.
View full translation schema ```json { "title": "Translation", "description": "One whole translation: its metadata, the source module's description and distribution metadata, title metadata and introductions attached at the translation level, and every book with every chapter and verse. A bulk document; translations.json states its size through its url and sha.", "type": "object", "properties": { "translation": { "type": "string", "description": "Display name of the translation." }, "abbreviation": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "description": "The translation's identifier and the first path segment of every one of its documents." }, "lang": { "type": "string", "description": "Language code of the translation." }, "language": { "type": "string", "description": "Language name; empty when the builder's tables have no name for the code." }, "direction": { "type": "string", "description": "Writing direction of the text, LTR or RTL." }, "encoding": { "type": "string", "description": "Character encoding declared by the source module. The generated documents are always UTF-8." }, "description": { "type": "string", "description": "The source module's description of the translation." }, "titles": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/title" }, "description": "Title metadata belonging to this level, in source order." }, "introduction": { "$ref": "#/components/schemas/introduction" }, "books": { "type": "array", "items": { "$ref": "#/components/schemas/book/$defs/entry" }, "description": "The source module's books with verses, titles, or introductions, in source order. Empty canon positions without content are omitted." }, "distribution_lcsh": { "type": "string", "description": "Library of Congress subject heading of the source module." }, "distribution_version": { "type": "string", "description": "Version of the source module." }, "distribution_version_date": { "type": "string", "description": "Release date of that version." }, "distribution_abbreviation": { "type": "string", "description": "Abbreviation the source module uses for itself." }, "distribution_about": { "type": "string", "description": "The source module's own description of the text." }, "distribution_license": { "type": "string", "description": "Distribution licence of the text." }, "distribution_sourcetype": { "type": "string", "description": "Markup of the source module, such as OSIS." }, "distribution_source": { "type": "string", "description": "Provenance of the text as the source module states it." }, "distribution_versification": { "type": "string", "description": "Versification system of the source module." }, "distribution_history": { "type": "object", "description": "Every history entry of the source module, keyed as the module keys it.", "additionalProperties": { "type": "string" } } }, "required": [ "translation", "abbreviation", "lang", "language", "direction", "encoding", "description", "books", "distribution_lcsh", "distribution_version", "distribution_version_date", "distribution_abbreviation", "distribution_about", "distribution_license", "distribution_sourcetype", "distribution_source", "distribution_versification", "distribution_history" ], "additionalProperties": false } ```
### book One book: the translation's metadata, the book's number and name, its title metadata and introduction when the source supplies them, and every chapter. Each nested chapter is what the standalone chapter document holds after the shared metadata. Books containing only title metadata or introduction text remain published with an empty chapters array.
View full book schema ```json { "title": "Book", "description": "One book: the translation's metadata, the book's number and name, its title metadata and introduction when the source supplies them, and every chapter. Each nested chapter is what the standalone chapter document holds after the shared metadata. Books containing only title metadata or introduction text remain published with an empty chapters array.", "type": "object", "properties": { "translation": { "type": "string", "description": "Display name of the translation." }, "abbreviation": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "description": "The translation's identifier and the first path segment of every one of its documents." }, "lang": { "type": "string", "description": "Language code of the translation." }, "language": { "type": "string", "description": "Language name; empty when the builder's tables have no name for the code." }, "direction": { "type": "string", "description": "Writing direction of the text, LTR or RTL." }, "encoding": { "type": "string", "description": "Character encoding declared by the source module. The generated documents are always UTF-8." }, "nr": { "type": "integer", "minimum": 1, "maximum": 281474977710655, "description": "Stable GetBible book number. Established books keep numbers 1 through 89; additional source book identities receive deterministic extension numbers. The translation's books.json lists its actual book numbers." }, "name": { "type": "string", "description": "Name of the book in the translation's language." }, "titles": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/title" }, "description": "Title metadata belonging to this level, in source order." }, "introduction": { "$ref": "#/components/schemas/introduction" }, "chapters": { "type": "array", "items": { "$ref": "#/components/schemas/chapter/$defs/entry" }, "description": "The content-bearing chapters of the book, in source order. Empty when the source supplies only book titles or introduction text." } }, "required": [ "translation", "abbreviation", "lang", "language", "direction", "encoding", "nr", "name", "chapters" ], "additionalProperties": false, "$defs": { "entry": { "title": "Book entry", "description": "A book as nested in the translation document: the same members as the standalone book document after the shared metadata.", "type": "object", "properties": { "nr": { "type": "integer", "minimum": 1, "maximum": 281474977710655, "description": "Stable GetBible book number. Established books keep numbers 1 through 89; additional source book identities receive deterministic extension numbers. The translation's books.json lists its actual book numbers." }, "name": { "type": "string", "description": "Name of the book in the translation's language." }, "titles": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/title" }, "description": "Title metadata belonging to this level, in source order." }, "introduction": { "$ref": "#/components/schemas/introduction" }, "chapters": { "type": "array", "items": { "$ref": "#/components/schemas/chapter/$defs/entry" }, "description": "The content-bearing chapters of the book, in source order. Empty when the source supplies only book titles or introduction text." } }, "required": [ "nr", "name", "chapters" ], "additionalProperties": false, "anyOf": [ { "properties": { "chapters": { "minItems": 1 } } }, { "required": [ "titles" ] }, { "required": [ "introduction" ] } ] } }, "anyOf": [ { "properties": { "chapters": { "minItems": 1 } } }, { "required": [ "titles" ] }, { "required": [ "introduction" ] } ] } ```
### chapter One chapter: the translation's metadata, the book it belongs to, and its verses, with the optional reading layout and introduction. The same chapter members appear in the chapter nested in the book and translation documents.
View full chapter schema ```json { "title": "Chapter", "description": "One chapter: the translation's metadata, the book it belongs to, and its verses, with the optional reading layout and introduction. The same chapter members appear in the chapter nested in the book and translation documents.", "type": "object", "properties": { "translation": { "type": "string", "description": "Display name of the translation." }, "abbreviation": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "description": "The translation's identifier and the first path segment of every one of its documents." }, "lang": { "type": "string", "description": "Language code of the translation." }, "language": { "type": "string", "description": "Language name; empty when the builder's tables have no name for the code." }, "direction": { "type": "string", "description": "Writing direction of the text, LTR or RTL." }, "encoding": { "type": "string", "description": "Character encoding declared by the source module. The generated documents are always UTF-8." }, "book_nr": { "type": "integer", "minimum": 1, "maximum": 281474977710655, "description": "Stable GetBible book number. Established books keep numbers 1 through 89; additional source book identities receive deterministic extension numbers. The translation's books.json lists its actual book numbers." }, "book_name": { "type": "string", "description": "Name of the book in the translation's language." }, "chapter": { "type": "integer", "minimum": 1, "description": "Chapter number in the translation's own versification." }, "name": { "type": "string", "description": "Book name and chapter, for example Genesis 1." }, "introduction": { "$ref": "#/components/schemas/introduction" }, "editorial": { "$ref": "#/components/schemas/editorial" }, "verses": { "type": "array", "items": { "$ref": "#/components/schemas/verse" }, "description": "The verses of the chapter that have text, in verse order.", "minItems": 1 } }, "required": [ "translation", "abbreviation", "lang", "language", "direction", "encoding", "book_nr", "book_name", "chapter", "name", "verses" ], "additionalProperties": false, "$defs": { "entry": { "title": "Chapter entry", "description": "A chapter as nested in a book or translation document: the same members as the standalone chapter document after the shared metadata. A chapter for which the source supplied an introduction or titles but no verse text is kept with an empty verses array and its titles, and has no standalone document; a chapter with verses carries its headings in editorial and never in titles.", "type": "object", "properties": { "chapter": { "type": "integer", "minimum": 1, "description": "Chapter number in the translation's own versification." }, "name": { "type": "string", "description": "Book name and chapter, for example Genesis 1." }, "introduction": { "$ref": "#/components/schemas/introduction" }, "editorial": { "$ref": "#/components/schemas/editorial" }, "verses": { "type": "array", "items": { "$ref": "#/components/schemas/verse" }, "description": "The verses of the chapter that have text, in verse order." }, "titles": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/title" }, "description": "Title metadata of a chapter without published verses; a chapter with verses carries its headings in editorial instead." } }, "required": [ "chapter", "name", "verses" ], "additionalProperties": false, "if": { "properties": { "verses": { "minItems": 1 } } }, "then": { "not": { "required": [ "titles" ] } }, "else": { "not": { "required": [ "editorial" ] } } } } } ```
### translations-index Every translation in the tree, keyed by abbreviation: the translation document's members except its books, with the URL the document was built for and the SHA-1 of its bytes.
View full translations-index schema ```json { "title": "Translations index", "description": "Every translation in the tree, keyed by abbreviation: the translation document's members except its books, with the URL the document was built for and the SHA-1 of its bytes.", "type": "object", "propertyNames": { "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$" }, "additionalProperties": { "type": "object", "properties": { "translation": { "type": "string", "description": "Display name of the translation." }, "abbreviation": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "description": "The translation's identifier and the first path segment of every one of its documents." }, "lang": { "type": "string", "description": "Language code of the translation." }, "language": { "type": "string", "description": "Language name; empty when the builder's tables have no name for the code." }, "direction": { "type": "string", "description": "Writing direction of the text, LTR or RTL." }, "encoding": { "type": "string", "description": "Character encoding declared by the source module. The generated documents are always UTF-8." }, "description": { "type": "string", "description": "The source module's description of the translation." }, "titles": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/title" }, "description": "Title metadata belonging to this level, in source order." }, "introduction": { "$ref": "#/components/schemas/introduction" }, "distribution_lcsh": { "type": "string", "description": "Library of Congress subject heading of the source module." }, "distribution_version": { "type": "string", "description": "Version of the source module." }, "distribution_version_date": { "type": "string", "description": "Release date of that version." }, "distribution_abbreviation": { "type": "string", "description": "Abbreviation the source module uses for itself." }, "distribution_about": { "type": "string", "description": "The source module's own description of the text." }, "distribution_license": { "type": "string", "description": "Distribution licence of the text." }, "distribution_sourcetype": { "type": "string", "description": "Markup of the source module, such as OSIS." }, "distribution_source": { "type": "string", "description": "Provenance of the text as the source module states it." }, "distribution_versification": { "type": "string", "description": "Versification system of the source module." }, "distribution_history": { "type": "object", "description": "Every history entry of the source module, keyed as the module keys it.", "additionalProperties": { "type": "string" } }, "url": { "type": "string", "format": "uri", "description": "The public URL the document was built for." }, "sha": { "type": "string", "pattern": "^[0-9a-f]{40}$", "description": "SHA-1 of the document's bytes, the same value its .sha file holds." } }, "required": [ "translation", "abbreviation", "lang", "language", "direction", "encoding", "description", "distribution_lcsh", "distribution_version", "distribution_version_date", "distribution_abbreviation", "distribution_about", "distribution_license", "distribution_sourcetype", "distribution_source", "distribution_versification", "distribution_history", "url", "sha" ], "additionalProperties": false } } ```
### books-index Every book of one translation, keyed by book number: the book document's members except its chapters, with the URL the document was built for and the SHA-1 of its bytes.
View full books-index schema ```json { "title": "Books index", "description": "Every book of one translation, keyed by book number: the book document's members except its chapters, with the URL the document was built for and the SHA-1 of its bytes.", "type": "object", "propertyNames": { "pattern": "^[1-9][0-9]*$" }, "additionalProperties": { "type": "object", "properties": { "translation": { "type": "string", "description": "Display name of the translation." }, "abbreviation": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "description": "The translation's identifier and the first path segment of every one of its documents." }, "lang": { "type": "string", "description": "Language code of the translation." }, "language": { "type": "string", "description": "Language name; empty when the builder's tables have no name for the code." }, "direction": { "type": "string", "description": "Writing direction of the text, LTR or RTL." }, "encoding": { "type": "string", "description": "Character encoding declared by the source module. The generated documents are always UTF-8." }, "nr": { "type": "integer", "minimum": 1, "maximum": 281474977710655, "description": "Stable GetBible book number. Established books keep numbers 1 through 89; additional source book identities receive deterministic extension numbers. The translation's books.json lists its actual book numbers." }, "name": { "type": "string", "description": "Name of the book in the translation's language." }, "titles": { "type": "array", "minItems": 1, "items": { "$ref": "#/components/schemas/title" }, "description": "Title metadata belonging to this level, in source order." }, "introduction": { "$ref": "#/components/schemas/introduction" }, "url": { "type": "string", "format": "uri", "description": "The public URL the document was built for." }, "sha": { "type": "string", "pattern": "^[0-9a-f]{40}$", "description": "SHA-1 of the document's bytes, the same value its .sha file holds." } }, "required": [ "translation", "abbreviation", "lang", "language", "direction", "encoding", "nr", "name", "url", "sha" ], "additionalProperties": false } } ```
### chapters-index Every chapter of one book, keyed by chapter number: the chapter document's members except its verses, with the URL the document was built for and the SHA-1 of its bytes.
View full chapters-index schema ```json { "title": "Chapters index", "description": "Every chapter of one book, keyed by chapter number: the chapter document's members except its verses, with the URL the document was built for and the SHA-1 of its bytes.", "type": "object", "propertyNames": { "pattern": "^[1-9][0-9]*$" }, "additionalProperties": { "type": "object", "properties": { "translation": { "type": "string", "description": "Display name of the translation." }, "abbreviation": { "type": "string", "pattern": "^[a-z0-9][a-z0-9_-]{0,29}$", "description": "The translation's identifier and the first path segment of every one of its documents." }, "lang": { "type": "string", "description": "Language code of the translation." }, "language": { "type": "string", "description": "Language name; empty when the builder's tables have no name for the code." }, "direction": { "type": "string", "description": "Writing direction of the text, LTR or RTL." }, "encoding": { "type": "string", "description": "Character encoding declared by the source module. The generated documents are always UTF-8." }, "book_nr": { "type": "integer", "minimum": 1, "maximum": 281474977710655, "description": "Stable GetBible book number. Established books keep numbers 1 through 89; additional source book identities receive deterministic extension numbers. The translation's books.json lists its actual book numbers." }, "book_name": { "type": "string", "description": "Name of the book in the translation's language." }, "chapter": { "type": "integer", "minimum": 1, "description": "Chapter number in the translation's own versification." }, "name": { "type": "string", "description": "Book name and chapter, for example Genesis 1." }, "introduction": { "$ref": "#/components/schemas/introduction" }, "editorial": { "$ref": "#/components/schemas/editorial" }, "url": { "type": "string", "format": "uri", "description": "The public URL the document was built for." }, "sha": { "type": "string", "pattern": "^[0-9a-f]{40}$", "description": "SHA-1 of the document's bytes, the same value its .sha file holds." } }, "required": [ "translation", "abbreviation", "lang", "language", "direction", "encoding", "book_nr", "book_name", "chapter", "name", "url", "sha" ], "additionalProperties": false } } ```
### checksum-index The SHA-1 of every translation, book or chapter document at one level of the tree, keyed as that level is addressed: by abbreviation at the root, by book number in a translation, by chapter number in a book. Index, checksum and description documents are not listed here; each has its own .sha sibling.
View full checksum-index schema ```json { "title": "Checksum index", "description": "The SHA-1 of every translation, book or chapter document at one level of the tree, keyed as that level is addressed: by abbreviation at the root, by book number in a translation, by chapter number in a book. Index, checksum and description documents are not listed here; each has its own .sha sibling.", "type": "object", "additionalProperties": { "type": "string", "pattern": "^[0-9a-f]{40}$", "description": "SHA-1 of the document's bytes." } } ```
### checksum The content of a .sha file: the SHA-1 of the bytes of the JSON document of the same name, as forty lowercase hexadecimal digits followed by a line feed.
View full checksum schema ```json { "title": "Checksum", "description": "The content of a .sha file: the SHA-1 of the bytes of the JSON document of the same name, as forty lowercase hexadecimal digits followed by a line feed.", "type": "string", "pattern": "^[0-9a-f]{40}\\n$" } ```
### verse One verse. `text` is the display text and never begins with a line ending. `paragraph` is present when the verse begins a paragraph. `tokens` and `spans` are present together when the source carries OSIS word markup.
View full verse schema ```json { "title": "Verse", "description": "One verse. `text` is the display text and never begins with a line ending. `paragraph` is present when the verse begins a paragraph. `tokens` and `spans` are present together when the source carries OSIS word markup.", "type": "object", "properties": { "chapter": { "type": "integer", "minimum": 1, "description": "Chapter number in the translation's own versification." }, "verse": { "type": "integer", "minimum": 1, "description": "Verse number in the translation's own versification." }, "name": { "type": "string", "description": "Book name, chapter and verse, for example Genesis 1:1." }, "text": { "type": "string", "minLength": 1, "pattern": "^[^\\r\\n]", "description": "The verse text. Line endings inside the verse are preserved; none begins it." }, "paragraph": { "const": true, "description": "Present when the verse begins a paragraph." }, "tokens": { "type": "array", "items": { "$ref": "#/components/schemas/token" }, "description": "Word-level tokens in reading order; present with spans when the source carries OSIS word markup." }, "spans": { "type": "array", "items": { "$ref": "#/components/schemas/span" }, "description": "Annotations over token and word ranges; present with tokens." } }, "required": [ "chapter", "verse", "name", "text" ], "dependentRequired": { "tokens": [ "spans" ], "spans": [ "tokens" ] }, "additionalProperties": false } ```
### token One word-level token of a verse or title. Tokens are listed in reading order. `word_start` and `word_end` locate the token in the whitespace-separated words of the display text (1-based, inclusive; 0 when the token could not be located). Every other member is an attribute of the source OSIS w element: multi-valued attributes are grouped by scheme and `src` is split into positions, any other attribute is kept as its string value.
View full token schema ```json { "title": "Token", "description": "One word-level token of a verse or title. Tokens are listed in reading order. `word_start` and `word_end` locate the token in the whitespace-separated words of the display text (1-based, inclusive; 0 when the token could not be located). Every other member is an attribute of the source OSIS w element: multi-valued attributes are grouped by scheme and `src` is split into positions, any other attribute is kept as its string value.", "type": "object", "properties": { "token": { "type": "string", "minLength": 1, "description": "The token text as it appears in the display text." }, "word_start": { "type": "integer", "minimum": 0, "description": "First whitespace-separated word of the display text the token covers, 1-based." }, "word_end": { "type": "integer", "minimum": 0, "description": "Last whitespace-separated word the token covers, inclusive." }, "lemma": { "type": "object", "description": "Lexical identifiers grouped by OSIS scheme, for example {\"strong\": [\"H07225\"]}.", "additionalProperties": { "type": "array", "minItems": 1, "items": { "type": "string" } } }, "morph": { "type": "object", "description": "Morphology codes grouped by OSIS scheme.", "additionalProperties": { "type": "array", "minItems": 1, "items": { "type": "string" } } }, "xlit": { "type": "object", "description": "Transliterations grouped by OSIS scheme.", "additionalProperties": { "type": "array", "minItems": 1, "items": { "type": "string" } } }, "src": { "type": "array", "items": { "type": [ "integer", "string" ] }, "description": "Source word positions of the token; strings only when the source value is not numeric." }, "gloss": { "type": "string", "description": "Gloss supplied by the source." }, "n": { "type": "string", "description": "The OSIS n attribute of the word." }, "type": { "type": "string", "description": "The OSIS type attribute of the word." }, "subType": { "type": "string", "description": "The OSIS subType attribute of the word." }, "morphSegmented": { "const": true, "description": "Present when the word carries a morphological segment." }, "variant": { "const": true, "description": "Present when the word is a textual variant." }, "variantType": { "type": "string", "description": "The variant's subType when the source supplies one." } }, "required": [ "token", "word_start", "word_end" ], "additionalProperties": { "type": "string", "description": "Any other attribute of the source w element, kept as its string value." } } ```
### span An annotation over a range of tokens: the OSIS context element that marks them (divineName, transChange, hi, q, foreign, inscription, name, speaker, number, unit or seg), the exact text it marks, and the range in both addressings. `token_start` and `token_end` index the verse's tokens array (0-based, inclusive); `word_start` and `word_end` count whitespace-separated words of the display text (1-based, inclusive; 0 when the text could not be located).
View full span schema ```json { "title": "Span", "description": "An annotation over a range of tokens: the OSIS context element that marks them (divineName, transChange, hi, q, foreign, inscription, name, speaker, number, unit or seg), the exact text it marks, and the range in both addressings. `token_start` and `token_end` index the verse's tokens array (0-based, inclusive); `word_start` and `word_end` count whitespace-separated words of the display text (1-based, inclusive; 0 when the text could not be located).", "type": "object", "properties": { "tag": { "type": "string", "minLength": 1, "description": "Name of the OSIS element." }, "span": { "type": "string", "description": "The exact text the element marks." }, "attrs": { "type": "object", "additionalProperties": { "type": "string" }, "description": "Retained attributes of the element; absent when there are none." }, "token_start": { "type": "integer", "minimum": 0, "description": "Index of the first token the span covers." }, "token_end": { "type": "integer", "minimum": 0, "description": "Index of the last token the span covers, inclusive." }, "word_start": { "type": "integer", "minimum": 0, "description": "First whitespace-separated word of the display text the span covers, 1-based." }, "word_end": { "type": "integer", "minimum": 0, "description": "Last whitespace-separated word the span covers, inclusive." } }, "required": [ "tag", "span", "token_start", "token_end", "word_start", "word_end" ], "additionalProperties": false } ```
### editorial The reading layout of one chapter, in reading order. A heading is anchored before a verse; a paragraph is an inclusive range of verse numbers. `order` is the contiguous zero-based position of the entry. When paragraph entries are present they cover every verse of the chapter contiguously, from its first verse to its last. The array is absent when the chapter has neither headings nor explicit paragraph markers.
View full editorial schema ```json { "title": "Editorial", "description": "The reading layout of one chapter, in reading order. A heading is anchored before a verse; a paragraph is an inclusive range of verse numbers. `order` is the contiguous zero-based position of the entry. When paragraph entries are present they cover every verse of the chapter contiguously, from its first verse to its last. The array is absent when the chapter has neither headings nor explicit paragraph markers.", "type": "array", "minItems": 1, "items": { "oneOf": [ { "$ref": "#/components/schemas/editorial/$defs/heading" }, { "$ref": "#/components/schemas/editorial/$defs/paragraph" } ] }, "$defs": { "heading": { "title": "Heading", "type": "object", "properties": { "order": { "type": "integer", "minimum": 0, "description": "Position of the entry in the array." }, "type": { "const": "heading" }, "anchor": { "type": "object", "properties": { "verse": { "type": "integer", "minimum": 1, "description": "The verse the heading precedes." }, "edge": { "const": "before" } }, "required": [ "verse", "edge" ], "additionalProperties": false }, "text": { "type": "string", "minLength": 1, "description": "The heading text." }, "heading_type": { "type": "string", "minLength": 1, "description": "The OSIS title type, or unspecified when the source supplies none." }, "canonical": { "type": "boolean", "description": "True only when the source explicitly marks the heading canonical." } }, "required": [ "order", "type", "anchor", "text", "heading_type", "canonical" ], "additionalProperties": false }, "paragraph": { "title": "Paragraph", "type": "object", "properties": { "order": { "type": "integer", "minimum": 0, "description": "Position of the entry in the array." }, "type": { "const": "paragraph" }, "start": { "type": "integer", "minimum": 1, "description": "First verse of the paragraph." }, "end": { "type": "integer", "minimum": 1, "description": "Last verse of the paragraph, inclusive." } }, "required": [ "order", "type", "start", "end" ], "additionalProperties": false } } } ```
### title Title metadata belonging to a translation or a book: its visible text, the OSIS title type when the source supplies one, the canonical flag and subtype the source states, and word-level tokens and spans when the title carries word markup.
View full title schema ```json { "title": "Title", "description": "Title metadata belonging to a translation or a book: its visible text, the OSIS title type when the source supplies one, the canonical flag and subtype the source states, and word-level tokens and spans when the title carries word markup.", "type": "object", "properties": { "type": { "type": "string", "description": "OSIS title type, such as main, chapter, section or psalm." }, "text": { "type": "string", "minLength": 1, "description": "The visible title text." }, "canonical": { "type": "boolean", "description": "Whether the source marks the title canonical; absent when the source does not say." }, "subtype": { "type": "string", "description": "OSIS subType of the title." }, "tokens": { "type": "array", "items": { "$ref": "#/components/schemas/token" }, "description": "Word-level tokens in reading order; present with spans when the source carries OSIS word markup." }, "spans": { "type": "array", "items": { "$ref": "#/components/schemas/span" }, "description": "Annotations over token and word ranges; present with tokens." } }, "required": [ "text" ], "dependentRequired": { "tokens": [ "spans" ], "spans": [ "tokens" ] }, "additionalProperties": false } ```
### introduction Introduction prose attached at its natural level: the translation (module or testament introductions), a book, or a chapter. Each entry is one source introduction.
View full introduction schema ```json { "title": "Introduction", "description": "Introduction prose attached at its natural level: the translation (module or testament introductions), a book, or a chapter. Each entry is one source introduction.", "type": "array", "minItems": 1, "items": { "type": "object", "properties": { "text": { "type": "string", "minLength": 1, "description": "The introduction text." } }, "required": [ "text" ], "additionalProperties": false } } ```
## Authentication contract ```json { "security": [], "securitySchemes": {} } ``` See [access and tokens](/tokens/) for public usage and token requests. --- # Bookmarks API Build topical Bible discovery with a reviewed collection of subjects, verse references, colors, and translated topic names. The Bookmarks API lets an application move in both directions: from a topic to its scripture references, and from a verse to the topics associated with it. The API stores references rather than scripture text. Use the [Bible API](/api/bible/) to retrieve verses in your chosen translation. ## Start here ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/index.json' ``` The index exposes resource paths, schema and catalog versions, current counts, locale codes, and a checksum for the complete catalog. Follow it with the topic list: ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/topics.json' ``` | Resource | Link | | --- | --- | | Complete v1 guide | [Bookmarks v1](/api/bookmarks/v1/) | | Discovery document | [index.json](https://bookmarks.getbible.net/v1/index.json) | | API service | [bookmarks.getbible.net](https://bookmarks.getbible.net/) | | Upstream v1 documentation | [Version 1 documentation](https://bookmarks.getbible.net/v1/) | | OpenAPI specification | [OpenAPI JSON](https://bookmarks.getbible.net/v1/openapi.json) | | Catalog and builder source | [getbible/v1_bookmark_builder](https://github.com/getbible/v1_bookmark_builder) | | Generated data | [getbible/bookmarks](https://github.com/getbible/bookmarks) | | Public support | [GetBible support](https://git.vdm.dev/getBible/support) | ## Designed for readers and applications Topic responses contain stable identifiers, English names, available translations, colors, and sorted `[book, chapter, verse]` coordinates. Book and chapter responses provide reverse lookups, so a Bible reader can display related topics next to a verse. A client can load individual topics on demand, download the whole catalog for offline use, or cache one locale's translated names. English is always available; applications select their own language and apply English fallback where a translated name is missing. ## Public topics and personal bookmarks This API publishes the project's shared topic catalog. It is a read-only static resource and does not store a user's personal bookmarks. Applications remain responsible for their own personal collections. Contributions are changes to reviewed source files in the builder repository. There is no write endpoint in this API. The [contribution guide](https://github.com/getbible/v1_bookmark_builder/blob/main/docs/CONTRIBUTING.md) covers editing source files and submitting changes through GitHub. ## A collection with a purpose The original collection grew from Brother Jaco van der Merwe's mission work and everyday conversations in Namibia. He collected verses by subject so that people could read what scripture says in response to their questions. His family continues to expand that work. The catalog is intended as a practical aid to finding and sharing scripture. Its coordinates contain no Bible translation text; the builder and catalog are published under the Apache License 2.0. Read the [complete v1 guide](/api/bookmarks/v1/) for all eleven routes, response models, localization, reverse lookup, caching, checksums, and contribution workflows. --- # Bookmarks API v1 Use `https://bookmarks.getbible.net/v1/` as the API directory. This is a public, read-only collection of static JSON documents. All eleven operations are GET requests with no request body or query parameters. [API overview](/api/bookmarks/) · [Service documentation](https://bookmarks.getbible.net/v1/) · [OpenAPI JSON](https://bookmarks.getbible.net/v1/openapi.json) · [Catalog source](https://github.com/getbible/v1_bookmark_builder) · [Public support](https://git.vdm.dev/getBible/support) ## Discover the catalog ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/index.json' curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/topics.json' ``` The index contains: | Field | Meaning | | --- | --- | | `schema_version` | Payload format version, currently 1 | | `catalog_version` | Content revision, incremented when the complete catalog checksum changes | | `checksum` | SHA-256 of the exact bytes of `all.json` | | `counts.topics` | Number of topics | | `counts.verses` | Number of topic-to-verse associations | | `counts.locales` | Number of locale documents | | `resources` | Relative paths and path templates for API resources | | `locales` | Available locale codes | A verse associated with two topics contributes two to `counts.verses`. This count does not mean distinct scripture verses. Use the index for current counts instead of embedding a fixed catalog size in a client. ## Choose a download | File | Best use | | --- | --- | | `topics.json` | Topic picker with English names, colors, and verse counts | | `topics/{id}.json` | One topic with coordinates and available translations | | `catalog.json` | All topics and coordinates without locale documents | | `all.json` | Complete offline collection, including every locale | | `verses/{book}.json` | Related-topic lookup for an entire book | | `verses/{book}/{chapter}.json` | Related-topic lookup for one displayed chapter | | `locales.json` | Discover languages and translation coverage | | `locales/{locale}.json` | Translated topic names for one locale | ## Topic identifiers and response fields Topic IDs are lowercase hyphenated slugs from `topics.json`. English names, aliases, and translated names are display values, not alternative endpoint addresses. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/topics/adultery.json' ``` Every individual topic includes: | Field | Type | Meaning | | --- | --- | --- | | `schema_version` | integer | Always 1 in v1 documents | | `id` | string | Stable topic slug | | `name` | string | Canonical English display name | | `color` | string | Lowercase six-digit hex color, prefixed with `#` | | `aliases` | string array | Alternative English display names | | `default` | boolean | Source catalog's default flag | | `names` | object | Available locale codes mapped to translated names, including English | | `verses` | array of triples | Sorted scripture coordinates | The `verses` member changes shape between resource types: in `topics.json`, it is an integer count; in individual topics, `catalog.json`, and `all.json`, it is an array of coordinates. Do not use a topic-summary parser for full topic documents. ## Verse coordinates Each coordinate is exactly `[book, chapter, verse]`, with integer values. The book follows the 66-book Protestant canon: Genesis is 1, Exodus 2, Matthew 40, John 43, and Revelation 66. The schema allows book 1–66, chapter 1–150, and verse 1–2,000; chapter validity is also specific to the selected book. Coordinates have no translation identifier and include no scripture text. They are intended to connect to a Bible translation chosen by the application. Preserve the selected translation's real verse numbering and handle missing verses according to that translation's coverage. For example, the coordinate `[2, 20, 14]` can be read by loading Exodus 20: ```bash curl --fail --silent --show-error \ 'https://api.getbible.net/v2/kjv/2/20.json' ``` Then select verse 14 using the [Bible API](/api/bible/v2/) response format. Coordinate triples are deduplicated within each topic and sorted. ## Reverse lookup: verse to topics ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/verses/2/20.json' ``` A published chapter example is: ```json { "schema_version": 1, "book": 2, "chapter": 20, "verses": { "6": ["obey-gods-commandments"], "12": ["longevity"], "14": ["adultery"] } } ``` Book and chapter fields are integers; chapter and verse object keys are JSON strings. Topic ID arrays are sorted. A missing verse key means no associations for that verse. A file exists for every canonical book and every valid canonical chapter, including empty chapters. An empty `verses` object means a valid chapter with no topic associations. A chapter beyond the selected book's chapter count has no file and returns the host's missing-file response. For all linked topics at Exodus 20:14: ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/verses/2/20.json' \ | jq --raw-output '.verses["14"] // [] | .[]' ``` The book-level response nests the same mapping one level deeper: `chapters["20"]["14"]`. ## Localization and English fallback ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/locales.json' curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/locales/af.json' curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/locales/en.json' ``` Locale codes are lowercase tags from `locales.json`, such as `en`, `af`, and `zh-hant`. English is generated from canonical topic names and covers the full catalog. Other locales may be partial. The API does not infer a language from request headers, fill missing translations, or redirect an unavailable locale to English. Implement the fallback in the client: ```javascript function topicName(topic, locale) { return topic.names?.[locale] ?? topic.names?.en ?? topic.name; } ``` For a locale document, use `locale.topics[topic.id] ?? topic.name`. In the locale list, `name` is always present and may be `null`. In an individual locale document, an unrecorded language `name` is omitted. The `all.json.locales` member contains locale documents keyed by locale. The aggregate topics array contains topic metadata and verse coordinates; an individual topic additionally assembles the available translations in `names`. ## Offline use, catalog versions, and checksums ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/all.json' \ --output bookmarks-all.json curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/checksums.json' \ --output bookmarks-checksums.json ``` Verify with jq and GNU `sha256sum`: ```bash set -euo pipefail expected="$(jq --raw-output --exit-status \ '.files["all.json"]' bookmarks-checksums.json)" printf '%s %s\n' "$expected" bookmarks-all.json | sha256sum --check - ``` `index.json.checksum` also describes the exact `all.json` bytes, including formatting and final newline. `catalog_version` increases when that content checksum changes. A documentation-only update can change `openapi.json` without incrementing the catalog version. `checksums.json.files` maps relative paths to SHA-256 hashes for all generated files except itself, including `index.json` and `openapi.json`. Compare hashes before refreshing large cached resources. Fetch content and its manifest from a consistent publication; if a deployment changes between requests, refetch and verify again. The files themselves are deterministic for identical inputs. HTTP cache headers, CORS, and host-specific limits are not prescribed by the generated contract. ## Errors and access The published API has no authentication system or write endpoint. A token is not part of these public GET requests. Contributions are managed through source control. Unknown topic IDs, deleted topics, unavailable locale codes, invalid books, and out-of-range chapter paths have no generated file. The OpenAPI contract describes 404 without a JSON error envelope; the hosting server controls the body. Check HTTP status before parsing. A missing topic is different from a valid topic with no linked verses. A valid chapter with no associations returns HTTP 200 and an empty map. Treat these cases separately in the interface. ## Import the OpenAPI description Import the [OpenAPI 3.1.1 JSON](https://bookmarks.getbible.net/v1/openapi.json) by URL into a compatible client such as Postman. The specification uses `servers[0].url: "./"`, resolving against its own published directory. Operation paths are relative to that directory and do not repeat `/v1`. When importing a downloaded file or pasting the specification, explicitly set the base/server URL to `https://bookmarks.getbible.net/v1/`. Local files do not identify the production host. Response schemas use JSON Schema Draft 2020-12 and are embedded with local references. Some examples are embedded; larger examples use relative `externalValue` links to complete published JSON. Those example links need the published base URL or a local copy of the generated files. ## Contribute to the shared catalog The [bookmark builder](https://github.com/getbible/v1_bookmark_builder) owns the reviewed sources: | Source | Purpose | | --- | --- | | `data/topics.json` | IDs, English names, colors, aliases, and default flags | | `data/links/{topic}.json` | Verse coordinates for one topic | | `data/locales/{locale}.json` | Translated topic names | A source change is validated and rebuilt into static output. Changes are reviewed through GitHub; the generated API accepts no POST, PATCH, or DELETE requests. See the [source data rules](https://github.com/getbible/v1_bookmark_builder/blob/main/docs/DATA.md) and [contribution guide](https://github.com/getbible/v1_bookmark_builder/blob/main/docs/CONTRIBUTING.md) for topic creation, renaming, translation, and bundle import. Deletion removes a topic from generated documents at the next build; it is not retained as an alias or tombstone. Keep application caches synchronized through the index checksum and catalog version. ## Complete endpoint reference All paths below are relative to `https://bookmarks.getbible.net/v1`. Every operation returns JSON for HTTP 200 and describes HTTP 404 for a missing document. ### GET `/index.json` Discover the catalogue and resource paths. Resource paths are relative to this directory. counts.verses counts topic-to-verse associations, not distinct verses. checksum is the SHA-256 of the exact all.json bytes. catalog_version increments when that content checksum changes; documentation-only changes do not increment it. schema_version describes the payload format. No parameters. Response model: `Index`. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/index.json' ``` ### GET `/all.json` Download the complete catalogue and all translations. Contains all topic metadata and verse coordinates, plus every locale's names. This is the content document hashed by index.json. No Scripture text is included. No parameters. Response model: `All`. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/all.json' ``` ### GET `/catalog.json` Download every topic with its verse coordinates. The same topics array as all.json, without locale documents. Verse coordinates are translation-independent [book, chapter, verse] triples in the 66-book Protestant canon, sorted without duplicates within a topic. No Scripture text is included. No parameters. Response model: `Catalog`. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/catalog.json' ``` ### GET `/topics.json` List topics with verse counts. Topic summaries use an integer verses count instead of the coordinate arrays returned by catalog.json and individual topic files. Use the stable id to request a topic. Names and aliases are English display text, not alternative URL identifiers. No parameters. Response model: `Topics`. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/topics.json' ``` ### GET `/topics/{id}.json` Read one topic and its translated names. Returns metadata, all verse coordinates, and names keyed by the locales that translate this topic. English (en) is always included. For a missing translation the client should display the English name. Deleted or unknown topic ids have no file. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `id` | string | Yes | Exact topic id from topics.json. Aliases and display names are not URL ids. Maximum length: 80. Pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$. | Response model: `Topic`. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/topics/adultery.json' ``` ### GET `/verses/{book}.json` Find topics associated with verses in a book. A file exists for each of the 66 books. chapters maps chapter-number strings to verse-number strings to sorted topic-id arrays. Only linked chapters and verses appear in the maps. An empty chapters object means no associations in the book. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `book` | integer | Yes | Book number in the 66-book Protestant canon, without leading zeros. \| Book \| Name \| Chapters \| \|---\|---\|---\| \| 1 \| Genesis \| 50 \| \| 2 \| Exodus \| 40 \| \| 3 \| Leviticus \| 27 \| \| 4 \| Numbers \| 36 \| \| 5 \| Deuteronomy \| 34 \| \| 6 \| Joshua \| 24 \| \| 7 \| Judges \| 21 \| \| 8 \| Ruth \| 4 \| \| 9 \| 1 Samuel \| 31 \| \| 10 \| 2 Samuel \| 24 \| \| 11 \| 1 Kings \| 22 \| \| 12 \| 2 Kings \| 25 \| \| 13 \| 1 Chronicles \| 29 \| \| 14 \| 2 Chronicles \| 36 \| \| 15 \| Ezra \| 10 \| \| 16 \| Nehemiah \| 13 \| \| 17 \| Esther \| 10 \| \| 18 \| Job \| 42 \| \| 19 \| Psalms \| 150 \| \| 20 \| Proverbs \| 31 \| \| 21 \| Ecclesiastes \| 12 \| \| 22 \| Song of Solomon \| 8 \| \| 23 \| Isaiah \| 66 \| \| 24 \| Jeremiah \| 52 \| \| 25 \| Lamentations \| 5 \| \| 26 \| Ezekiel \| 48 \| \| 27 \| Daniel \| 12 \| \| 28 \| Hosea \| 14 \| \| 29 \| Joel \| 3 \| \| 30 \| Amos \| 9 \| \| 31 \| Obadiah \| 1 \| \| 32 \| Jonah \| 4 \| \| 33 \| Micah \| 7 \| \| 34 \| Nahum \| 3 \| \| 35 \| Habakkuk \| 3 \| \| 36 \| Zephaniah \| 3 \| \| 37 \| Haggai \| 2 \| \| 38 \| Zechariah \| 14 \| \| 39 \| Malachi \| 4 \| \| 40 \| Matthew \| 28 \| \| 41 \| Mark \| 16 \| \| 42 \| Luke \| 24 \| \| 43 \| John \| 21 \| \| 44 \| Acts \| 28 \| \| 45 \| Romans \| 16 \| \| 46 \| 1 Corinthians \| 16 \| \| 47 \| 2 Corinthians \| 13 \| \| 48 \| Galatians \| 6 \| \| 49 \| Ephesians \| 6 \| \| 50 \| Philippians \| 4 \| \| 51 \| Colossians \| 4 \| \| 52 \| 1 Thessalonians \| 5 \| \| 53 \| 2 Thessalonians \| 3 \| \| 54 \| 1 Timothy \| 6 \| \| 55 \| 2 Timothy \| 4 \| \| 56 \| Titus \| 3 \| \| 57 \| Philemon \| 1 \| \| 58 \| Hebrews \| 13 \| \| 59 \| James \| 5 \| \| 60 \| 1 Peter \| 5 \| \| 61 \| 2 Peter \| 3 \| \| 62 \| 1 John \| 5 \| \| 63 \| 2 John \| 1 \| \| 64 \| 3 John \| 1 \| \| 65 \| Jude \| 1 \| \| 66 \| Revelation \| 22 \| Minimum: 1. Maximum: 66. | Response model: `Book`. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/verses/43.json' ``` ### GET `/verses/{book}/{chapter}.json` Find topics associated with verses in a chapter. Every valid canonical chapter has a file, even when verses is empty. Keys are verse numbers as strings; values are sorted topic-id arrays. A missing verse key means no associations. A chapter beyond the selected book's chapter count has no file. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `book` | integer | Yes | Book number in the 66-book Protestant canon, without leading zeros. \| Book \| Name \| Chapters \| \|---\|---\|---\| \| 1 \| Genesis \| 50 \| \| 2 \| Exodus \| 40 \| \| 3 \| Leviticus \| 27 \| \| 4 \| Numbers \| 36 \| \| 5 \| Deuteronomy \| 34 \| \| 6 \| Joshua \| 24 \| \| 7 \| Judges \| 21 \| \| 8 \| Ruth \| 4 \| \| 9 \| 1 Samuel \| 31 \| \| 10 \| 2 Samuel \| 24 \| \| 11 \| 1 Kings \| 22 \| \| 12 \| 2 Kings \| 25 \| \| 13 \| 1 Chronicles \| 29 \| \| 14 \| 2 Chronicles \| 36 \| \| 15 \| Ezra \| 10 \| \| 16 \| Nehemiah \| 13 \| \| 17 \| Esther \| 10 \| \| 18 \| Job \| 42 \| \| 19 \| Psalms \| 150 \| \| 20 \| Proverbs \| 31 \| \| 21 \| Ecclesiastes \| 12 \| \| 22 \| Song of Solomon \| 8 \| \| 23 \| Isaiah \| 66 \| \| 24 \| Jeremiah \| 52 \| \| 25 \| Lamentations \| 5 \| \| 26 \| Ezekiel \| 48 \| \| 27 \| Daniel \| 12 \| \| 28 \| Hosea \| 14 \| \| 29 \| Joel \| 3 \| \| 30 \| Amos \| 9 \| \| 31 \| Obadiah \| 1 \| \| 32 \| Jonah \| 4 \| \| 33 \| Micah \| 7 \| \| 34 \| Nahum \| 3 \| \| 35 \| Habakkuk \| 3 \| \| 36 \| Zephaniah \| 3 \| \| 37 \| Haggai \| 2 \| \| 38 \| Zechariah \| 14 \| \| 39 \| Malachi \| 4 \| \| 40 \| Matthew \| 28 \| \| 41 \| Mark \| 16 \| \| 42 \| Luke \| 24 \| \| 43 \| John \| 21 \| \| 44 \| Acts \| 28 \| \| 45 \| Romans \| 16 \| \| 46 \| 1 Corinthians \| 16 \| \| 47 \| 2 Corinthians \| 13 \| \| 48 \| Galatians \| 6 \| \| 49 \| Ephesians \| 6 \| \| 50 \| Philippians \| 4 \| \| 51 \| Colossians \| 4 \| \| 52 \| 1 Thessalonians \| 5 \| \| 53 \| 2 Thessalonians \| 3 \| \| 54 \| 1 Timothy \| 6 \| \| 55 \| 2 Timothy \| 4 \| \| 56 \| Titus \| 3 \| \| 57 \| Philemon \| 1 \| \| 58 \| Hebrews \| 13 \| \| 59 \| James \| 5 \| \| 60 \| 1 Peter \| 5 \| \| 61 \| 2 Peter \| 3 \| \| 62 \| 1 John \| 5 \| \| 63 \| 2 John \| 1 \| \| 64 \| 3 John \| 1 \| \| 65 \| Jude \| 1 \| \| 66 \| Revelation \| 22 \| Minimum: 1. Maximum: 66. | | `chapter` | integer | Yes | Chapter number without leading zeros. Must not exceed the selected book's chapter count (see the book parameter table); 150 is only the maximum across all books. Minimum: 1. Maximum: 150. | Response model: `Chapter`. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/verses/43/1.json' ``` ### GET `/locales.json` List available locales and translation coverage. Each entry gives the locale code, its English language name (null if unrecorded), and the number of topic names translated. English (en) is always complete; other locales may translate only part of the catalogue. No parameters. Response model: `Locales`. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/locales.json' ``` ### GET `/locales/{locale}.json` Read topic names for one locale. topics maps stable topic ids to translated names. name is omitted when no language name is recorded. en is derived from the English topic names and is always present. Other locales may be partial. Clients must implement English fallback; requesting an unavailable locale does not automatically return English. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `locale` | string | Yes | Exact lowercase locale code from locales.json, such as en or zh-hant. Unsupported locales do not fall back automatically. Maximum length: 16. Pattern: ^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$. | Response model: `Locale`. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/locales/en.json' ``` ### GET `/checksums.json` Read SHA-256 hashes for the generated files. files maps relative paths to SHA-256 hashes of the exact published bytes. Includes index.json and openapi.json; excludes checksums.json itself to avoid self-reference. Use this manifest to verify downloads from the same build. No parameters. Response model: `Checksums`. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/checksums.json' ``` ### GET `/openapi.json` Read this OpenAPI description. Generated with the API on every build. Describes the available GET routes, path parameters, response schemas and examples. Response schemas are embedded with local references so schema resolution does not require another download. No parameters. Response model: `JSON object`. ```bash curl --fail --silent --show-error \ 'https://bookmarks.getbible.net/v1/openapi.json' ``` ## Complete response field reference The tables preserve the generated OpenAPI field names, types, required fields, and constraints. Nested required fields are required when their containing object is present. Fields marked optional may be omitted. JSON Schemas in the linked specification provide the complete machine-readable contract. ### Index Discovery document. checksum is the SHA-256 of all.json; catalog_version increments whenever that checksum changes between published builds. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema_version` | number | Yes | Constant: 1. | | `catalog_version` | integer | Yes | Minimum: 1. | | `checksum` | string | Yes | Pattern: ^[0-9a-f]{64}$. | | `counts` | object | Yes | No additional fields. | | `counts.topics` | integer | Yes | Minimum: 0. | | `counts.verses` | integer | Yes | Minimum: 0. | | `counts.locales` | integer | Yes | Minimum: 0. | | `resources` | object | Yes | | | `resources.{key}` | string | — | | | `locales` | array | Yes | | ### All v1/all.json | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema_version` | number | Yes | Constant: 1. | | `topics` | array | Yes | | | `topics[].id` | string | Yes | Maximum length: 80. Pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$. | | `topics[].name` | string | Yes | Maximum length: 80. Pattern: ^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$. | | `topics[].color` | string | Yes | Pattern: ^#[0-9a-f]{6}$. | | `topics[].aliases` | array | Yes | Maximum items: 20. Items are unique. | | `topics[].default` | boolean | Yes | | | `topics[].verses` | array | Yes | Maximum items: 100000. | | `topics[].verses[][0]` | integer | Yes | Minimum: 1. Maximum: 66. | | `topics[].verses[][1]` | integer | Yes | Minimum: 1. Maximum: 150. | | `topics[].verses[][2]` | integer | Yes | Minimum: 1. Maximum: 2000. | | `locales` | object | Yes | | | `locales.{key}` | Locale | — | See Locale. | ### Catalog v1/catalog.json | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema_version` | number | Yes | Constant: 1. | | `topics` | array | Yes | | | `topics[].id` | string | Yes | Maximum length: 80. Pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$. | | `topics[].name` | string | Yes | Maximum length: 80. Pattern: ^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$. | | `topics[].color` | string | Yes | Pattern: ^#[0-9a-f]{6}$. | | `topics[].aliases` | array | Yes | Maximum items: 20. Items are unique. | | `topics[].default` | boolean | Yes | | | `topics[].verses` | array | Yes | Maximum items: 100000. | | `topics[].verses[][0]` | integer | Yes | Minimum: 1. Maximum: 66. | | `topics[].verses[][1]` | integer | Yes | Minimum: 1. Maximum: 150. | | `topics[].verses[][2]` | integer | Yes | Minimum: 1. Maximum: 2000. | ### Topics v1/topics.json | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema_version` | number | Yes | Constant: 1. | | `topics` | array | Yes | | | `topics[].id` | string | Yes | Maximum length: 80. Pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$. | | `topics[].name` | string | Yes | Maximum length: 80. Pattern: ^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$. | | `topics[].color` | string | Yes | Pattern: ^#[0-9a-f]{6}$. | | `topics[].aliases` | array | Yes | Maximum items: 20. Items are unique. | | `topics[].default` | boolean | Yes | | | `topics[].verses` | integer | Yes | Minimum: 0. | ### Topic v1/topics/.json | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema_version` | number | Yes | Constant: 1. | | `id` | string | Yes | Maximum length: 80. Pattern: ^[a-z0-9]+(?:-[a-z0-9]+)*$. | | `name` | string | Yes | Maximum length: 80. Pattern: ^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$. | | `color` | string | Yes | Pattern: ^#[0-9a-f]{6}$. | | `aliases` | array | Yes | Maximum items: 20. Items are unique. | | `default` | boolean | Yes | | | `names` | object | Yes | | | `names.{key}` | string | — | Minimum length: 1. Maximum length: 120. | | `verses` | array | Yes | Maximum items: 100000. | | `verses[][0]` | integer | Yes | Minimum: 1. Maximum: 66. | | `verses[][1]` | integer | Yes | Minimum: 1. Maximum: 150. | | `verses[][2]` | integer | Yes | Minimum: 1. Maximum: 2000. | ### Book v1/verses/.json | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema_version` | number | Yes | Constant: 1. | | `book` | integer | Yes | Minimum: 1. Maximum: 66. | | `chapters` | object | Yes | | | `chapters.{key}` | object | — | | ### Chapter v1/verses//.json | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema_version` | number | Yes | Constant: 1. | | `book` | integer | Yes | Minimum: 1. Maximum: 66. | | `chapter` | integer | Yes | Minimum: 1. Maximum: 150. | | `verses` | object | Yes | | | `verses.{key}` | array | — | Minimum items: 1. | ### Locales v1/locales.json | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema_version` | number | Yes | Constant: 1. | | `locales` | array | Yes | | | `locales[].code` | string | Yes | Maximum length: 16. Pattern: ^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$. | | `locales[].name` | string, null | Yes | Maximum length: 80. | | `locales[].topics` | integer | Yes | Minimum: 0. | ### Locale Translated topic names for one locale (data/locales/.json and v1/locales/.json) | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema_version` | number | Yes | Constant: 1. | | `locale` | string | Yes | Maximum length: 16. Pattern: ^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$. | | `name` | string | No | Minimum length: 1. Maximum length: 80. | | `topics` | object | Yes | | | `topics.{key}` | string | — | Minimum length: 1. Maximum length: 120. | ### Checksums v1/checksums.json | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema_version` | number | Yes | Constant: 1. | | `files` | object | Yes | | | `files.{key}` | string | — | Pattern: ^[0-9a-f]{64}$. | ## Sources - [Published bookmarks OpenAPI specification](https://bookmarks.getbible.net/v1/openapi.json) - [Generated bookmarks data repository](https://github.com/getbible/bookmarks) - [Bookmark builder API documentation](https://github.com/getbible/v1_bookmark_builder/blob/main/docs/OPENAPI.md) - [Bookmark builder architecture and contribution documentation](https://github.com/getbible/v1_bookmark_builder) ## Complete contract reference Open the [complete endpoint and schema reference](/api/bookmarks/v1/reference/) for every operation, parameter, response and component model in the published OpenAPI contract. --- # Bookmarks API v1: endpoint and schema reference This reference is generated from the checked-in [OpenAPI contract](https://bookmarks.getbible.net/v1/openapi.json). Return to the [integration guide](/api/bookmarks/v1/) for workflows and ready-to-run examples. Resolved request server: `https://bookmarks.getbible.net/v1`. ## GET /index.json Discover the catalogue and resource paths Resource paths are relative to this directory. counts.verses counts topic-to-verse associations, not distinct verses. checksum is the SHA-256 of the exact all.json bytes. catalog_version increments when that content checksum changes; documentation-only changes do not increment it. schema_version describes the payload format. Operation ID: `getIndex`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The published JSON document. | application/json | #/components/schemas/Index | | 404 | The requested static file is unavailable (for example an unknown topic or locale, or an invalid book/chapter). The hosting server determines the response body and content type; no JSON error envelope is defined by this builder. | — | See contract |
Complete operation contract ```json { "operationId": "getIndex", "tags": [ "Discovery" ], "summary": "Discover the catalogue and resource paths", "description": "Resource paths are relative to this directory. counts.verses counts topic-to-verse associations, not distinct verses. checksum is the SHA-256 of the exact all.json bytes. catalog_version increments when that content checksum changes; documentation-only changes do not increment it. schema_version describes the payload format.", "responses": { "200": { "description": "The published JSON document.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Index" }, "examples": { "published": { "summary": "Complete published response", "externalValue": "./index.json" } } } } }, "404": { "$ref": "#/components/responses/NotFound" } }, "parameters": [] } ```
## GET /all.json Download the complete catalogue and all translations Contains all topic metadata and verse coordinates, plus every locale's names. This is the content document hashed by index.json. No Scripture text is included. Operation ID: `getAll`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The published JSON document. | application/json | #/components/schemas/All | | 404 | The requested static file is unavailable (for example an unknown topic or locale, or an invalid book/chapter). The hosting server determines the response body and content type; no JSON error envelope is defined by this builder. | — | See contract |
Complete operation contract ```json { "operationId": "getAll", "tags": [ "Topics" ], "summary": "Download the complete catalogue and all translations", "description": "Contains all topic metadata and verse coordinates, plus every locale's names. This is the content document hashed by index.json. No Scripture text is included.", "responses": { "200": { "description": "The published JSON document.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/All" }, "examples": { "published": { "summary": "Complete published response", "externalValue": "./all.json" } } } } }, "404": { "$ref": "#/components/responses/NotFound" } }, "parameters": [] } ```
## GET /catalog.json Download every topic with its verse coordinates The same topics array as all.json, without locale documents. Verse coordinates are translation-independent [book, chapter, verse] triples in the 66-book Protestant canon, sorted without duplicates within a topic. No Scripture text is included. Operation ID: `getCatalog`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The published JSON document. | application/json | #/components/schemas/Catalog | | 404 | The requested static file is unavailable (for example an unknown topic or locale, or an invalid book/chapter). The hosting server determines the response body and content type; no JSON error envelope is defined by this builder. | — | See contract |
Complete operation contract ```json { "operationId": "getCatalog", "tags": [ "Topics" ], "summary": "Download every topic with its verse coordinates", "description": "The same topics array as all.json, without locale documents. Verse coordinates are translation-independent [book, chapter, verse] triples in the 66-book Protestant canon, sorted without duplicates within a topic. No Scripture text is included.", "responses": { "200": { "description": "The published JSON document.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Catalog" }, "examples": { "published": { "summary": "Complete published response", "externalValue": "./catalog.json" } } } } }, "404": { "$ref": "#/components/responses/NotFound" } }, "parameters": [] } ```
## GET /topics.json List topics with verse counts Topic summaries use an integer verses count instead of the coordinate arrays returned by catalog.json and individual topic files. Use the stable id to request a topic. Names and aliases are English display text, not alternative URL identifiers. Operation ID: `getTopics`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The published JSON document. | application/json | #/components/schemas/Topics | | 404 | The requested static file is unavailable (for example an unknown topic or locale, or an invalid book/chapter). The hosting server determines the response body and content type; no JSON error envelope is defined by this builder. | — | See contract |
Complete operation contract ```json { "operationId": "getTopics", "tags": [ "Topics" ], "summary": "List topics with verse counts", "description": "Topic summaries use an integer verses count instead of the coordinate arrays returned by catalog.json and individual topic files. Use the stable id to request a topic. Names and aliases are English display text, not alternative URL identifiers.", "responses": { "200": { "description": "The published JSON document.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Topics" }, "examples": { "published": { "summary": "Complete published response", "externalValue": "./topics.json" } } } } }, "404": { "$ref": "#/components/responses/NotFound" } }, "parameters": [] } ```
## GET /topics/{id}.json Read one topic and its translated names Returns metadata, all verse coordinates, and names keyed by the locales that translate this topic. English (en) is always included. For a missing translation the client should display the English name. Deleted or unknown topic ids have no file. Operation ID: `getTopic`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `id` | path | Yes | string | adultery | Exact topic id from topics.json. Aliases and display names are not URL ids. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The published JSON document. | application/json | #/components/schemas/Topic | | 404 | The requested static file is unavailable (for example an unknown topic or locale, or an invalid book/chapter). The hosting server determines the response body and content type; no JSON error envelope is defined by this builder. | — | See contract |
Complete operation contract ```json { "operationId": "getTopic", "tags": [ "Topics" ], "summary": "Read one topic and its translated names", "description": "Returns metadata, all verse coordinates, and names keyed by the locales that translate this topic. English (en) is always included. For a missing translation the client should display the English name. Deleted or unknown topic ids have no file.", "responses": { "200": { "description": "The published JSON document.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Topic" }, "examples": { "published": { "summary": "Complete response from topics/adultery.json", "value": { "schema_version": 1, "id": "adultery", "name": "Adultery", "color": "#f9a8b8", "aliases": [], "default": true, "names": { "af": "Owerspel", "ar": "الزنا", "br": "Avoultrie", "ch": "Adulterio", "cs": "Cizoložství", "da": "Utroskab", "de": "Ehebruch", "el": "Μοιχεία", "en": "Adultery", "eo": "Adulterio", "es": "Adulterio", "et": "Abielurikkumine", "eu": "Adulterioa", "fi": "Aviorikos", "fr": "Adultère", "gd": "Adhaltranas", "gv": "Brishey-poosey", "hbo": "ניאוף", "hr": "Preljub", "hu": "Házasságtörés", "hy": "Շնություն", "id": "Perzinahan", "it": "Adulterio", "ja": "姦淫", "ko": "간음", "la": "Adulterium", "lt": "Svetimavimas", "lv": "Laulības pārkāpšana", "mg": "fanitsakitsaham-bady", "mi": "puremu", "mn": "Садар самуун", "my": "အိမ်ထောင်ရေးဖောက်ပြန်မှု", "nb": "Utroskap", "nd": "Ukuphinga", "nl": "Overspel", "nn": "Utruskap", "pl": "Cudzołóstwo", "prs": "زنا", "pt": "Adultério", "ro": "Adulter", "ru": "Прелюбодеяние", "sn": "Upombwe", "sq": "Tradhtia bashkëshortore", "sr": "Прељуба", "sv": "Äktenskapsbrott", "sw": "Uzinzi", "th": "การล่วงประเวณี", "tl": "pangangalunya", "tpi": "Pasin pamuk", "tr": "Zina", "uk": "Подружня зрада", "vi": "Ngoại tình", "zh": "奸淫", "zh-hant": "姦淫" }, "verses": [ [ 2, 20, 14 ], [ 3, 18, 20 ], [ 3, 20, 10 ], [ 5, 22, 22 ], [ 18, 24, 15 ], [ 20, 2, 16 ], [ 20, 2, 17 ], [ 20, 5, 18 ], [ 20, 5, 19 ], [ 20, 5, 20 ], [ 20, 6, 24 ], [ 20, 6, 25 ], [ 20, 6, 26 ], [ 20, 6, 27 ], [ 20, 6, 28 ], [ 20, 6, 29 ], [ 20, 6, 30 ], [ 20, 6, 31 ], [ 20, 6, 32 ], [ 20, 7, 10 ], [ 20, 7, 11 ], [ 20, 7, 12 ], [ 20, 7, 25 ], [ 20, 7, 26 ], [ 20, 7, 27 ], [ 21, 5, 4 ], [ 21, 5, 5 ], [ 21, 5, 6 ], [ 39, 2, 14 ], [ 39, 2, 15 ], [ 39, 2, 16 ], [ 40, 5, 27 ], [ 40, 5, 28 ], [ 40, 5, 31 ], [ 40, 5, 32 ], [ 40, 15, 19 ], [ 40, 19, 3 ], [ 40, 19, 4 ], [ 40, 19, 5 ], [ 40, 19, 6 ], [ 40, 19, 7 ], [ 40, 19, 8 ], [ 40, 19, 9 ], [ 40, 19, 10 ], [ 41, 6, 17 ], [ 41, 6, 18 ], [ 41, 6, 19 ], [ 41, 7, 21 ], [ 41, 10, 2 ], [ 41, 10, 3 ], [ 41, 10, 4 ], [ 41, 10, 5 ], [ 41, 10, 6 ], [ 41, 10, 7 ], [ 41, 10, 8 ], [ 41, 10, 9 ], [ 41, 10, 10 ], [ 41, 10, 11 ], [ 41, 10, 12 ], [ 42, 16, 18 ], [ 45, 7, 1 ], [ 45, 7, 2 ], [ 45, 7, 3 ], [ 46, 6, 9 ], [ 46, 7, 10 ], [ 46, 7, 11 ], [ 46, 7, 12 ], [ 46, 7, 13 ], [ 46, 7, 14 ], [ 46, 7, 15 ], [ 46, 7, 16 ], [ 46, 7, 39 ], [ 48, 5, 19 ], [ 48, 5, 20 ], [ 48, 5, 21 ], [ 58, 13, 4 ], [ 59, 4, 4 ], [ 61, 2, 14 ] ] } } } } } }, "404": { "$ref": "#/components/responses/NotFound" } }, "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "maxLength": 80 }, "description": "Exact topic id from topics.json. Aliases and display names are not URL ids.", "example": "adultery" } ] } ```
## GET /verses/{book}.json Find topics associated with verses in a book A file exists for each of the 66 books. chapters maps chapter-number strings to verse-number strings to sorted topic-id arrays. Only linked chapters and verses appear in the maps. An empty chapters object means no associations in the book. Operation ID: `getBook`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `book` | path | Yes | integer | 2 | Book number in the 66-book Protestant canon, without leading zeros. \| Book \| Name \| Chapters \| \|---\|---\|---\| \| 1 \| Genesis \| 50 \| \| 2 \| Exodus \| 40 \| \| 3 \| Leviticus \| 27 \| \| 4 \| Numbers \| 36 \| \| 5 \| Deuteronomy \| 34 \| \| 6 \| Joshua \| 24 \| \| 7 \| Judges \| 21 \| \| 8 \| Ruth \| 4 \| \| 9 \| 1 Samuel \| 31 \| \| 10 \| 2 Samuel \| 24 \| \| 11 \| 1 Kings \| 22 \| \| 12 \| 2 Kings \| 25 \| \| 13 \| 1 Chronicles \| 29 \| \| 14 \| 2 Chronicles \| 36 \| \| 15 \| Ezra \| 10 \| \| 16 \| Nehemiah \| 13 \| \| 17 \| Esther \| 10 \| \| 18 \| Job \| 42 \| \| 19 \| Psalms \| 150 \| \| 20 \| Proverbs \| 31 \| \| 21 \| Ecclesiastes \| 12 \| \| 22 \| Song of Solomon \| 8 \| \| 23 \| Isaiah \| 66 \| \| 24 \| Jeremiah \| 52 \| \| 25 \| Lamentations \| 5 \| \| 26 \| Ezekiel \| 48 \| \| 27 \| Daniel \| 12 \| \| 28 \| Hosea \| 14 \| \| 29 \| Joel \| 3 \| \| 30 \| Amos \| 9 \| \| 31 \| Obadiah \| 1 \| \| 32 \| Jonah \| 4 \| \| 33 \| Micah \| 7 \| \| 34 \| Nahum \| 3 \| \| 35 \| Habakkuk \| 3 \| \| 36 \| Zephaniah \| 3 \| \| 37 \| Haggai \| 2 \| \| 38 \| Zechariah \| 14 \| \| 39 \| Malachi \| 4 \| \| 40 \| Matthew \| 28 \| \| 41 \| Mark \| 16 \| \| 42 \| Luke \| 24 \| \| 43 \| John \| 21 \| \| 44 \| Acts \| 28 \| \| 45 \| Romans \| 16 \| \| 46 \| 1 Corinthians \| 16 \| \| 47 \| 2 Corinthians \| 13 \| \| 48 \| Galatians \| 6 \| \| 49 \| Ephesians \| 6 \| \| 50 \| Philippians \| 4 \| \| 51 \| Colossians \| 4 \| \| 52 \| 1 Thessalonians \| 5 \| \| 53 \| 2 Thessalonians \| 3 \| \| 54 \| 1 Timothy \| 6 \| \| 55 \| 2 Timothy \| 4 \| \| 56 \| Titus \| 3 \| \| 57 \| Philemon \| 1 \| \| 58 \| Hebrews \| 13 \| \| 59 \| James \| 5 \| \| 60 \| 1 Peter \| 5 \| \| 61 \| 2 Peter \| 3 \| \| 62 \| 1 John \| 5 \| \| 63 \| 2 John \| 1 \| \| 64 \| 3 John \| 1 \| \| 65 \| Jude \| 1 \| \| 66 \| Revelation \| 22 \| | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The published JSON document. | application/json | #/components/schemas/Book | | 404 | The requested static file is unavailable (for example an unknown topic or locale, or an invalid book/chapter). The hosting server determines the response body and content type; no JSON error envelope is defined by this builder. | — | See contract |
Complete operation contract ```json { "operationId": "getBook", "tags": [ "Verse lookup" ], "summary": "Find topics associated with verses in a book", "description": "A file exists for each of the 66 books. chapters maps chapter-number strings to verse-number strings to sorted topic-id arrays. Only linked chapters and verses appear in the maps. An empty chapters object means no associations in the book.", "responses": { "200": { "description": "The published JSON document.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Book" }, "examples": { "published": { "summary": "Complete response from verses/2.json", "value": { "schema_version": 1, "book": 2, "chapters": { "6": { "6": [ "gods-judgment" ] }, "12": { "12": [ "gods-judgment" ] }, "20": { "6": [ "obey-gods-commandments" ], "12": [ "longevity" ], "14": [ "adultery" ] }, "22": { "28": [ "obey-government-laws" ] }, "23": { "2": [ "no-fellowship" ], "4": [ "non-resistance" ] }, "28": { "3": [ "wisdom-origin" ], "42": [ "christian-clothing" ] }, "31": { "3": [ "wisdom-origin" ] }, "33": { "20": [ "effective-prayer" ] }, "34": { "7": [ "gods-judgment" ], "12": [ "no-fellowship" ] } } } } } } } }, "404": { "$ref": "#/components/responses/NotFound" } }, "parameters": [ { "name": "book", "in": "path", "required": true, "schema": { "type": "integer", "minimum": 1, "maximum": 66 }, "description": "Book number in the 66-book Protestant canon, without leading zeros.\n\n| Book | Name | Chapters |\n|---|---|---|\n| 1 | Genesis | 50 |\n| 2 | Exodus | 40 |\n| 3 | Leviticus | 27 |\n| 4 | Numbers | 36 |\n| 5 | Deuteronomy | 34 |\n| 6 | Joshua | 24 |\n| 7 | Judges | 21 |\n| 8 | Ruth | 4 |\n| 9 | 1 Samuel | 31 |\n| 10 | 2 Samuel | 24 |\n| 11 | 1 Kings | 22 |\n| 12 | 2 Kings | 25 |\n| 13 | 1 Chronicles | 29 |\n| 14 | 2 Chronicles | 36 |\n| 15 | Ezra | 10 |\n| 16 | Nehemiah | 13 |\n| 17 | Esther | 10 |\n| 18 | Job | 42 |\n| 19 | Psalms | 150 |\n| 20 | Proverbs | 31 |\n| 21 | Ecclesiastes | 12 |\n| 22 | Song of Solomon | 8 |\n| 23 | Isaiah | 66 |\n| 24 | Jeremiah | 52 |\n| 25 | Lamentations | 5 |\n| 26 | Ezekiel | 48 |\n| 27 | Daniel | 12 |\n| 28 | Hosea | 14 |\n| 29 | Joel | 3 |\n| 30 | Amos | 9 |\n| 31 | Obadiah | 1 |\n| 32 | Jonah | 4 |\n| 33 | Micah | 7 |\n| 34 | Nahum | 3 |\n| 35 | Habakkuk | 3 |\n| 36 | Zephaniah | 3 |\n| 37 | Haggai | 2 |\n| 38 | Zechariah | 14 |\n| 39 | Malachi | 4 |\n| 40 | Matthew | 28 |\n| 41 | Mark | 16 |\n| 42 | Luke | 24 |\n| 43 | John | 21 |\n| 44 | Acts | 28 |\n| 45 | Romans | 16 |\n| 46 | 1 Corinthians | 16 |\n| 47 | 2 Corinthians | 13 |\n| 48 | Galatians | 6 |\n| 49 | Ephesians | 6 |\n| 50 | Philippians | 4 |\n| 51 | Colossians | 4 |\n| 52 | 1 Thessalonians | 5 |\n| 53 | 2 Thessalonians | 3 |\n| 54 | 1 Timothy | 6 |\n| 55 | 2 Timothy | 4 |\n| 56 | Titus | 3 |\n| 57 | Philemon | 1 |\n| 58 | Hebrews | 13 |\n| 59 | James | 5 |\n| 60 | 1 Peter | 5 |\n| 61 | 2 Peter | 3 |\n| 62 | 1 John | 5 |\n| 63 | 2 John | 1 |\n| 64 | 3 John | 1 |\n| 65 | Jude | 1 |\n| 66 | Revelation | 22 |", "example": 2 } ] } ```
## GET /verses/{book}/{chapter}.json Find topics associated with verses in a chapter Every valid canonical chapter has a file, even when verses is empty. Keys are verse numbers as strings; values are sorted topic-id arrays. A missing verse key means no associations. A chapter beyond the selected book's chapter count has no file. Operation ID: `getChapter`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `book` | path | Yes | integer | 2 | Book number in the 66-book Protestant canon, without leading zeros. \| Book \| Name \| Chapters \| \|---\|---\|---\| \| 1 \| Genesis \| 50 \| \| 2 \| Exodus \| 40 \| \| 3 \| Leviticus \| 27 \| \| 4 \| Numbers \| 36 \| \| 5 \| Deuteronomy \| 34 \| \| 6 \| Joshua \| 24 \| \| 7 \| Judges \| 21 \| \| 8 \| Ruth \| 4 \| \| 9 \| 1 Samuel \| 31 \| \| 10 \| 2 Samuel \| 24 \| \| 11 \| 1 Kings \| 22 \| \| 12 \| 2 Kings \| 25 \| \| 13 \| 1 Chronicles \| 29 \| \| 14 \| 2 Chronicles \| 36 \| \| 15 \| Ezra \| 10 \| \| 16 \| Nehemiah \| 13 \| \| 17 \| Esther \| 10 \| \| 18 \| Job \| 42 \| \| 19 \| Psalms \| 150 \| \| 20 \| Proverbs \| 31 \| \| 21 \| Ecclesiastes \| 12 \| \| 22 \| Song of Solomon \| 8 \| \| 23 \| Isaiah \| 66 \| \| 24 \| Jeremiah \| 52 \| \| 25 \| Lamentations \| 5 \| \| 26 \| Ezekiel \| 48 \| \| 27 \| Daniel \| 12 \| \| 28 \| Hosea \| 14 \| \| 29 \| Joel \| 3 \| \| 30 \| Amos \| 9 \| \| 31 \| Obadiah \| 1 \| \| 32 \| Jonah \| 4 \| \| 33 \| Micah \| 7 \| \| 34 \| Nahum \| 3 \| \| 35 \| Habakkuk \| 3 \| \| 36 \| Zephaniah \| 3 \| \| 37 \| Haggai \| 2 \| \| 38 \| Zechariah \| 14 \| \| 39 \| Malachi \| 4 \| \| 40 \| Matthew \| 28 \| \| 41 \| Mark \| 16 \| \| 42 \| Luke \| 24 \| \| 43 \| John \| 21 \| \| 44 \| Acts \| 28 \| \| 45 \| Romans \| 16 \| \| 46 \| 1 Corinthians \| 16 \| \| 47 \| 2 Corinthians \| 13 \| \| 48 \| Galatians \| 6 \| \| 49 \| Ephesians \| 6 \| \| 50 \| Philippians \| 4 \| \| 51 \| Colossians \| 4 \| \| 52 \| 1 Thessalonians \| 5 \| \| 53 \| 2 Thessalonians \| 3 \| \| 54 \| 1 Timothy \| 6 \| \| 55 \| 2 Timothy \| 4 \| \| 56 \| Titus \| 3 \| \| 57 \| Philemon \| 1 \| \| 58 \| Hebrews \| 13 \| \| 59 \| James \| 5 \| \| 60 \| 1 Peter \| 5 \| \| 61 \| 2 Peter \| 3 \| \| 62 \| 1 John \| 5 \| \| 63 \| 2 John \| 1 \| \| 64 \| 3 John \| 1 \| \| 65 \| Jude \| 1 \| \| 66 \| Revelation \| 22 \| | | `chapter` | path | Yes | integer | 20 | Chapter number without leading zeros. Must not exceed the selected book's chapter count (see the book parameter table); 150 is only the maximum across all books. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The published JSON document. | application/json | #/components/schemas/Chapter | | 404 | The requested static file is unavailable (for example an unknown topic or locale, or an invalid book/chapter). The hosting server determines the response body and content type; no JSON error envelope is defined by this builder. | — | See contract |
Complete operation contract ```json { "operationId": "getChapter", "tags": [ "Verse lookup" ], "summary": "Find topics associated with verses in a chapter", "description": "Every valid canonical chapter has a file, even when verses is empty. Keys are verse numbers as strings; values are sorted topic-id arrays. A missing verse key means no associations. A chapter beyond the selected book's chapter count has no file.", "responses": { "200": { "description": "The published JSON document.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Chapter" }, "examples": { "published": { "summary": "Complete response from verses/2/20.json", "value": { "schema_version": 1, "book": 2, "chapter": 20, "verses": { "6": [ "obey-gods-commandments" ], "12": [ "longevity" ], "14": [ "adultery" ] } } } } } } }, "404": { "$ref": "#/components/responses/NotFound" } }, "parameters": [ { "name": "book", "in": "path", "required": true, "schema": { "type": "integer", "minimum": 1, "maximum": 66 }, "description": "Book number in the 66-book Protestant canon, without leading zeros.\n\n| Book | Name | Chapters |\n|---|---|---|\n| 1 | Genesis | 50 |\n| 2 | Exodus | 40 |\n| 3 | Leviticus | 27 |\n| 4 | Numbers | 36 |\n| 5 | Deuteronomy | 34 |\n| 6 | Joshua | 24 |\n| 7 | Judges | 21 |\n| 8 | Ruth | 4 |\n| 9 | 1 Samuel | 31 |\n| 10 | 2 Samuel | 24 |\n| 11 | 1 Kings | 22 |\n| 12 | 2 Kings | 25 |\n| 13 | 1 Chronicles | 29 |\n| 14 | 2 Chronicles | 36 |\n| 15 | Ezra | 10 |\n| 16 | Nehemiah | 13 |\n| 17 | Esther | 10 |\n| 18 | Job | 42 |\n| 19 | Psalms | 150 |\n| 20 | Proverbs | 31 |\n| 21 | Ecclesiastes | 12 |\n| 22 | Song of Solomon | 8 |\n| 23 | Isaiah | 66 |\n| 24 | Jeremiah | 52 |\n| 25 | Lamentations | 5 |\n| 26 | Ezekiel | 48 |\n| 27 | Daniel | 12 |\n| 28 | Hosea | 14 |\n| 29 | Joel | 3 |\n| 30 | Amos | 9 |\n| 31 | Obadiah | 1 |\n| 32 | Jonah | 4 |\n| 33 | Micah | 7 |\n| 34 | Nahum | 3 |\n| 35 | Habakkuk | 3 |\n| 36 | Zephaniah | 3 |\n| 37 | Haggai | 2 |\n| 38 | Zechariah | 14 |\n| 39 | Malachi | 4 |\n| 40 | Matthew | 28 |\n| 41 | Mark | 16 |\n| 42 | Luke | 24 |\n| 43 | John | 21 |\n| 44 | Acts | 28 |\n| 45 | Romans | 16 |\n| 46 | 1 Corinthians | 16 |\n| 47 | 2 Corinthians | 13 |\n| 48 | Galatians | 6 |\n| 49 | Ephesians | 6 |\n| 50 | Philippians | 4 |\n| 51 | Colossians | 4 |\n| 52 | 1 Thessalonians | 5 |\n| 53 | 2 Thessalonians | 3 |\n| 54 | 1 Timothy | 6 |\n| 55 | 2 Timothy | 4 |\n| 56 | Titus | 3 |\n| 57 | Philemon | 1 |\n| 58 | Hebrews | 13 |\n| 59 | James | 5 |\n| 60 | 1 Peter | 5 |\n| 61 | 2 Peter | 3 |\n| 62 | 1 John | 5 |\n| 63 | 2 John | 1 |\n| 64 | 3 John | 1 |\n| 65 | Jude | 1 |\n| 66 | Revelation | 22 |", "example": 2 }, { "name": "chapter", "in": "path", "required": true, "schema": { "type": "integer", "minimum": 1, "maximum": 150 }, "description": "Chapter number without leading zeros. Must not exceed the selected book's chapter count (see the book parameter table); 150 is only the maximum across all books.", "example": 20 } ] } ```
## GET /locales.json List available locales and translation coverage Each entry gives the locale code, its English language name (null if unrecorded), and the number of topic names translated. English (en) is always complete; other locales may translate only part of the catalogue. Operation ID: `getLocales`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The published JSON document. | application/json | #/components/schemas/Locales | | 404 | The requested static file is unavailable (for example an unknown topic or locale, or an invalid book/chapter). The hosting server determines the response body and content type; no JSON error envelope is defined by this builder. | — | See contract |
Complete operation contract ```json { "operationId": "getLocales", "tags": [ "Translations" ], "summary": "List available locales and translation coverage", "description": "Each entry gives the locale code, its English language name (null if unrecorded), and the number of topic names translated. English (en) is always complete; other locales may translate only part of the catalogue.", "responses": { "200": { "description": "The published JSON document.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Locales" }, "examples": { "published": { "summary": "Complete published response", "externalValue": "./locales.json" } } } } }, "404": { "$ref": "#/components/responses/NotFound" } }, "parameters": [] } ```
## GET /locales/{locale}.json Read topic names for one locale topics maps stable topic ids to translated names. name is omitted when no language name is recorded. en is derived from the English topic names and is always present. Other locales may be partial. Clients must implement English fallback; requesting an unavailable locale does not automatically return English. Operation ID: `getLocale`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `locale` | path | Yes | string | en | Exact lowercase locale code from locales.json, such as en or zh-hant. Unsupported locales do not fall back automatically. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The published JSON document. | application/json | #/components/schemas/Locale | | 404 | The requested static file is unavailable (for example an unknown topic or locale, or an invalid book/chapter). The hosting server determines the response body and content type; no JSON error envelope is defined by this builder. | — | See contract |
Complete operation contract ```json { "operationId": "getLocale", "tags": [ "Translations" ], "summary": "Read topic names for one locale", "description": "topics maps stable topic ids to translated names. name is omitted when no language name is recorded. en is derived from the English topic names and is always present. Other locales may be partial. Clients must implement English fallback; requesting an unavailable locale does not automatically return English.", "responses": { "200": { "description": "The published JSON document.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Locale" }, "examples": { "published": { "summary": "Complete response from locales/en.json", "value": { "schema_version": 1, "locale": "en", "name": "English", "topics": { "adultery": "Adultery", "authority-of-the-bible": "Authority of the Bible", "baptism": "Baptism", "biblical-love": "Biblical Love", "blessings-and-curses": "Blessings and Curses", "christian-clothing": "Christian Clothing", "christian-offices": "Christian Offices", "communion": "Communion", "conditional-security": "Conditional Security", "dating": "Dating", "dietary-guidance": "Dietary Guidance", "discipline": "Discipline", "education": "Education", "effective-prayer": "Effective Prayer", "family-planning": "Family Planning", "fear-not": "Fear Not", "first-day": "First Day", "flattery": "Flattery", "free-will": "Free Will", "gods-judgment": "God's Judgment", "grace": "Grace", "home-church": "Home Church", "immutability": "Immutability", "jesus-christs-deity": "Jesus Christ's Deity", "jesus-christs-humanity": "Jesus Christ's Humanity", "leadership": "Leadership", "longevity": "Longevity", "mans-role": "Man's Role", "marriage": "Marriage", "musics-influence": "Music's Influence", "no-fellowship": "No Fellowship", "no-one-is-good": "No One is Good", "non-resistance": "Non-Resistance", "not-under-the-law": "Not Under the Law", "obey-gods-commandments": "Obey God's Commandments", "obey-government-laws": "Obey Government Laws", "omnipotent": "Omnipotent", "omnipresent": "Omnipresent", "omniscient": "Omniscient", "orderly-home": "Orderly Home", "ordinances": "Ordinances", "prince-of-this-world": "Prince of this World", "providence": "Providence", "renewing-of-the-mind": "Renewing of the Mind", "repentance": "Repentance", "saved-by-faith": "Saved by Faith", "sodomy": "Sodomy", "spirit-of-prophecy": "Spirit of Prophecy", "spiritual-gifts": "Spiritual Gifts", "spiritual-judgment": "Spiritual Judgment", "spiritual-rebirth": "Spiritual Rebirth", "temptation": "Temptation", "what-is-life": "What is Life", "wine": "Wine", "wisdom-cause": "Wisdom Cause", "wisdom-fruit": "Wisdom Fruit", "wisdom-origin": "Wisdom Origin", "wisdom-value": "Wisdom Value", "womans-role": "Woman's Role", "word-of-god": "Word of God", "worldly-wisdom": "Worldly Wisdom" } } } } } } }, "404": { "$ref": "#/components/responses/NotFound" } }, "parameters": [ { "name": "locale", "in": "path", "required": true, "schema": { "type": "string", "pattern": "^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$", "maxLength": 16 }, "description": "Exact lowercase locale code from locales.json, such as en or zh-hant. Unsupported locales do not fall back automatically.", "example": "en" } ] } ```
## GET /checksums.json Read SHA-256 hashes for the generated files files maps relative paths to SHA-256 hashes of the exact published bytes. Includes index.json and openapi.json; excludes checksums.json itself to avoid self-reference. Use this manifest to verify downloads from the same build. Operation ID: `getChecksums`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The published JSON document. | application/json | #/components/schemas/Checksums | | 404 | The requested static file is unavailable (for example an unknown topic or locale, or an invalid book/chapter). The hosting server determines the response body and content type; no JSON error envelope is defined by this builder. | — | See contract |
Complete operation contract ```json { "operationId": "getChecksums", "tags": [ "Discovery" ], "summary": "Read SHA-256 hashes for the generated files", "description": "files maps relative paths to SHA-256 hashes of the exact published bytes. Includes index.json and openapi.json; excludes checksums.json itself to avoid self-reference. Use this manifest to verify downloads from the same build.", "responses": { "200": { "description": "The published JSON document.", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Checksums" }, "examples": { "published": { "summary": "Complete published response", "externalValue": "./checksums.json" } } } } }, "404": { "$ref": "#/components/responses/NotFound" } }, "parameters": [] } ```
## GET /openapi.json Read this OpenAPI description Generated with the API on every build. Describes the available GET routes, path parameters, response schemas and examples. Response schemas are embedded with local references so schema resolution does not require another download. Operation ID: `getOpenapi`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The published JSON document. | application/json | object | | 404 | The requested static file is unavailable (for example an unknown topic or locale, or an invalid book/chapter). The hosting server determines the response body and content type; no JSON error envelope is defined by this builder. | — | See contract |
Complete operation contract ```json { "operationId": "getOpenapi", "tags": [ "Discovery" ], "summary": "Read this OpenAPI description", "description": "Generated with the API on every build. Describes the available GET routes, path parameters, response schemas and examples. Response schemas are embedded with local references so schema resolution does not require another download.", "responses": { "200": { "description": "The published JSON document.", "content": { "application/json": { "schema": { "type": "object", "description": "An OpenAPI 3.1 description." } } } }, "404": { "$ref": "#/components/responses/NotFound" } }, "parameters": [] } ```
## Component schemas Types, required properties, nested objects, constraints and examples below are copied directly from the contract. A property omitted from a schema’s `required` array is optional, even when examples include it. ### Index Discovery document. checksum is the SHA-256 of all.json; catalog_version increments whenever that checksum changes between published builds.
View full Index schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "v1/index.json", "type": "object", "additionalProperties": false, "required": [ "schema_version", "catalog_version", "checksum", "counts", "resources", "locales" ], "properties": { "schema_version": { "const": 1 }, "catalog_version": { "type": "integer", "minimum": 1 }, "checksum": { "type": "string", "pattern": "^[0-9a-f]{64}$" }, "counts": { "type": "object", "additionalProperties": false, "required": [ "topics", "verses", "locales" ], "properties": { "topics": { "type": "integer", "minimum": 0 }, "verses": { "type": "integer", "minimum": 0 }, "locales": { "type": "integer", "minimum": 0 } } }, "resources": { "type": "object", "additionalProperties": { "type": "string" } }, "locales": { "type": "array", "items": { "type": "string", "pattern": "^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$", "maxLength": 16 } } }, "description": "Discovery document. checksum is the SHA-256 of all.json; catalog_version increments whenever that checksum changes between published builds." } ```
### All
View full All schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "v1/all.json", "type": "object", "additionalProperties": false, "required": [ "schema_version", "topics", "locales" ], "properties": { "schema_version": { "const": 1 }, "topics": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "id", "name", "color", "aliases", "default", "verses" ], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "maxLength": 80 }, "name": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$", "maxLength": 80 }, "color": { "type": "string", "pattern": "^#[0-9a-f]{6}$" }, "aliases": { "type": "array", "maxItems": 20, "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$", "maxLength": 80 } }, "default": { "type": "boolean" }, "verses": { "type": "array", "maxItems": 100000, "items": { "type": "array", "minItems": 3, "maxItems": 3, "prefixItems": [ { "type": "integer", "minimum": 1, "maximum": 66 }, { "type": "integer", "minimum": 1, "maximum": 150 }, { "type": "integer", "minimum": 1, "maximum": 2000 } ], "items": false, "description": "Translation-independent [book, chapter, verse] in the 66-book Protestant canon." } } } } }, "locales": { "type": "object", "propertyNames": { "type": "string", "pattern": "^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$", "maxLength": 16 }, "additionalProperties": { "$ref": "#/components/schemas/Locale" } } } } ```
### Catalog
View full Catalog schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "v1/catalog.json", "type": "object", "additionalProperties": false, "required": [ "schema_version", "topics" ], "properties": { "schema_version": { "const": 1 }, "topics": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "id", "name", "color", "aliases", "default", "verses" ], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "maxLength": 80 }, "name": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$", "maxLength": 80 }, "color": { "type": "string", "pattern": "^#[0-9a-f]{6}$" }, "aliases": { "type": "array", "maxItems": 20, "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$", "maxLength": 80 } }, "default": { "type": "boolean" }, "verses": { "type": "array", "maxItems": 100000, "items": { "type": "array", "minItems": 3, "maxItems": 3, "prefixItems": [ { "type": "integer", "minimum": 1, "maximum": 66 }, { "type": "integer", "minimum": 1, "maximum": 150 }, { "type": "integer", "minimum": 1, "maximum": 2000 } ], "items": false, "description": "Translation-independent [book, chapter, verse] in the 66-book Protestant canon." } } } } } } } ```
### Topics
View full Topics schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "v1/topics.json", "type": "object", "additionalProperties": false, "required": [ "schema_version", "topics" ], "properties": { "schema_version": { "const": 1 }, "topics": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "id", "name", "color", "aliases", "default", "verses" ], "properties": { "id": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "maxLength": 80 }, "name": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$", "maxLength": 80 }, "color": { "type": "string", "pattern": "^#[0-9a-f]{6}$" }, "aliases": { "type": "array", "maxItems": 20, "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$", "maxLength": 80 } }, "default": { "type": "boolean" }, "verses": { "type": "integer", "minimum": 0 } } } } } } ```
### Topic
View full Topic schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "v1/topics/.json", "type": "object", "additionalProperties": false, "required": [ "schema_version", "id", "name", "color", "aliases", "default", "names", "verses" ], "properties": { "schema_version": { "const": 1 }, "id": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "maxLength": 80 }, "name": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$", "maxLength": 80 }, "color": { "type": "string", "pattern": "^#[0-9a-f]{6}$" }, "aliases": { "type": "array", "maxItems": 20, "uniqueItems": true, "items": { "type": "string", "pattern": "^[A-Za-z0-9][A-Za-z0-9 &'():?-]*[A-Za-z0-9)]$", "maxLength": 80 } }, "default": { "type": "boolean" }, "names": { "type": "object", "propertyNames": { "type": "string", "pattern": "^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$", "maxLength": 16 }, "additionalProperties": { "type": "string", "minLength": 1, "maxLength": 120 } }, "verses": { "type": "array", "maxItems": 100000, "items": { "type": "array", "minItems": 3, "maxItems": 3, "prefixItems": [ { "type": "integer", "minimum": 1, "maximum": 66 }, { "type": "integer", "minimum": 1, "maximum": 150 }, { "type": "integer", "minimum": 1, "maximum": 2000 } ], "items": false, "description": "Translation-independent [book, chapter, verse] in the 66-book Protestant canon." } } } } ```
### Book
View full Book schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "v1/verses/.json", "type": "object", "additionalProperties": false, "required": [ "schema_version", "book", "chapters" ], "properties": { "schema_version": { "const": 1 }, "book": { "type": "integer", "minimum": 1, "maximum": 66 }, "chapters": { "type": "object", "propertyNames": { "pattern": "^[1-9][0-9]{0,2}$" }, "additionalProperties": { "type": "object", "propertyNames": { "pattern": "^[1-9][0-9]{0,3}$" }, "additionalProperties": { "type": "array", "minItems": 1, "items": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "maxLength": 80 } } } } } } ```
### Chapter
View full Chapter schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "v1/verses//.json", "type": "object", "additionalProperties": false, "required": [ "schema_version", "book", "chapter", "verses" ], "properties": { "schema_version": { "const": 1 }, "book": { "type": "integer", "minimum": 1, "maximum": 66 }, "chapter": { "type": "integer", "minimum": 1, "maximum": 150 }, "verses": { "type": "object", "propertyNames": { "pattern": "^[1-9][0-9]{0,3}$" }, "additionalProperties": { "type": "array", "minItems": 1, "items": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "maxLength": 80 } } } } } ```
### Locales
View full Locales schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "v1/locales.json", "type": "object", "additionalProperties": false, "required": [ "schema_version", "locales" ], "properties": { "schema_version": { "const": 1 }, "locales": { "type": "array", "items": { "type": "object", "additionalProperties": false, "required": [ "code", "name", "topics" ], "properties": { "code": { "type": "string", "pattern": "^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$", "maxLength": 16 }, "name": { "type": [ "string", "null" ], "maxLength": 80 }, "topics": { "type": "integer", "minimum": 0 } } } } } } ```
### Locale
View full Locale schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "Translated topic names for one locale (data/locales/.json and v1/locales/.json)", "type": "object", "additionalProperties": false, "required": [ "schema_version", "locale", "topics" ], "properties": { "schema_version": { "const": 1 }, "locale": { "type": "string", "pattern": "^[a-z]{2,3}(?:-[a-z0-9]{2,8})*$", "maxLength": 16 }, "name": { "type": "string", "minLength": 1, "maxLength": 80 }, "topics": { "type": "object", "propertyNames": { "type": "string", "pattern": "^[a-z0-9]+(?:-[a-z0-9]+)*$", "maxLength": 80 }, "additionalProperties": { "type": "string", "minLength": 1, "maxLength": 120 } } } } ```
### Checksums
View full Checksums schema ```json { "$schema": "https://json-schema.org/draft/2020-12/schema", "title": "v1/checksums.json", "type": "object", "additionalProperties": false, "required": [ "schema_version", "files" ], "properties": { "schema_version": { "const": 1 }, "files": { "type": "object", "additionalProperties": { "type": "string", "pattern": "^[0-9a-f]{64}$" } } } } ```
## Authentication contract ```json { "security": [], "securitySchemes": {} } ``` See [access and tokens](/tokens/) for public usage and token requests. --- # Commentaries API Add historical commentary alongside scripture, from a single chapter through a complete offline collection. The Commentaries API publishes approved CrossWire SWORD commentaries as plain-text JSON addressed with the same numeric book, chapter, and verse coordinates used across GetBible. A commentary may cover a small selection of passages or an extensive part of scripture. Discover actual coverage through its book index; applications do not need to assume every commentary contains every book. ## Start here ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/commentaries.json' ``` Then inspect one commentary's coverage and read a chapter: ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke/books.json' curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke/43/1.json' ``` | Resource | Link | | --- | --- | | Complete v1 guide | [Commentaries v1](/api/commentaries/v1/) | | Current catalog | [commentaries.json](https://commentaries.getbible.net/v1/commentaries.json) | | API service | [commentaries.getbible.net](https://commentaries.getbible.net/) | | Upstream v1 documentation | [Version 1 documentation](https://commentaries.getbible.net/v1/) | | OpenAPI specification | [OpenAPI JSON](https://commentaries.getbible.net/v1/openapi.json) | | Builder source | [getbible/v1_study_builder](https://github.com/getbible/v1_study_builder) | | Generated data | [getbible/commentaries](https://github.com/getbible/commentaries) | | Public support | [GetBible support](https://git.vdm.dev/getBible/support) | ## Choose the right download | Reading experience | Document | | --- | --- | | Show a chapter next to a Bible reader | `{commentary}/{book}/{chapter}.json` | | Prepare one book for offline use | `{commentary}/{book}.json` | | Download an entire commentary | `{commentary}.json` | | List available books and chapters | `{commentary}/books.json` | | Check provenance, license, and download size | `{commentary}/metadata.json` | Chapter documents are embedded in book documents; book documents are embedded in whole-commentary documents. Applications can reuse the same rendering logic at each level. ## Verse ranges and introductions One comment may discuss several verses. The API stores that comment once and records its coverage in a `verses` array. A client looking up a verse must inspect that array when present; comparing only the anchor `verse` would miss comments that cover a range. Book introductions use chapter `0`. Chapter introductions use verse `0`. These are study material coordinates and should be displayed separately from scripture verses. ## Access and connected resources The published API is public and read-only. It defines no token requirement, request body, or server-side filtering. Each module's metadata records provenance, licensing, and the Bible shape used to resolve citations. Commentary text is plain text, with structured scripture references available for links to the [Bible API](/api/bible/) or [Query API](/api/query/). Use the [Dictionaries API](/api/dictionaries/) for word definitions and Strong's lexicons, and the [Bookmarks API](/api/bookmarks/) for topic-to-verse associations. The [complete v1 guide](/api/commentaries/v1/) documents every resource, exact addressing rules, response models, copyable cURL examples, reference handling, checksums, and build health. --- # Commentaries API v1 Read commentary as plain-text JSON at chapter, book, or whole-module scale. The document root is `https://commentaries.getbible.net/v1/`. All published operations are static GET requests, with no request bodies, query parameters, or authentication scheme defined by the contract. [API overview](/api/commentaries/) · [Service documentation](https://commentaries.getbible.net/v1/) · [OpenAPI JSON](https://commentaries.getbible.net/v1/openapi.json) · [Builder source](https://github.com/getbible/v1_study_builder) · [Public support](https://git.vdm.dev/getBible/support) ## Quick start ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/commentaries.json' curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke/metadata.json' curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke/books.json' curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke/43/1.json' ``` The catalog supplies the commentary identifiers, names, languages, licenses, counts, and whole-document byte sizes. The book index tells you which book and chapter documents exist for that commentary. ## Addressing and coverage | Parameter | Meaning | | --- | --- | | `commentary` | Exact module ID from `commentaries.json`, such as `clarke` | | `book` | GetBible integer book number, from 1 through 83 | | `chapter` | Chapter number, including 0 for a book introduction | Genesis is book 1, Daniel 27, Matthew 40, John 43, and Revelation 66. Deuterocanonical books continue through 83. A valid numeric range alone does not guarantee a commentary covers a book or chapter; use its `books.json` index. Book introductions use chapter `0`, for example `clarke/27/0.json`. A chapter introduction uses verse `0` inside its chapter response. Keep these in a study introduction view rather than treating them as scripture verse 0. ## Read a verse correctly A commentary can attach one paragraph to multiple verses. The API stores that comment once, anchors it at the lowest verse it covers, and includes a `verses` array for its full coverage. A comment without `verses` covers only its `verse`. This cURL and jq example returns all comments covering John 1:3: ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke/43/1.json' \ | jq '[.entries[] | select((.verses // [.verse]) | index(3))]' ``` Equivalent browser JavaScript: ```javascript async function getCommentsForVerse(commentary, book, chapter, verse) { const url = new URL( `v1/${encodeURIComponent(commentary)}/${book}/${chapter}.json`, 'https://commentaries.getbible.net/' ); const response = await fetch(url); if (!response.ok) { throw new Error(`Commentary request failed: HTTP ${response.status}`); } const document = await response.json(); return document.entries.filter(entry => (entry.verses ?? [entry.verse]).includes(verse) ); } const comments = await getCommentsForVerse('clarke', 43, 1, 3); console.log(comments); ``` Grouping stops at chapter boundaries. A comment that spans a chapter break can appear in both chapter documents so that each document remains usable on its own. ## Three compatible response levels | Resource | Container fields | Nested content | | --- | --- | --- | | Chapter | `schema`, `commentary`, `language`, `book`, `name`, `chapter` | `entries` | | Book | `schema`, `commentary`, `language`, `book`, `name` | `chapters` | | Whole commentary | `schema`, `commentary`, `language`, `name` | `books` | Each chapter is embedded unchanged in its book document, and each book is embedded unchanged in the whole commentary. Build a chapter renderer once, then reuse it for the larger downloads. Entries contain required `book`, `chapter`, `verse`, and `text`; `osis`, `verses`, and `references` are optional. When present, `osis` is the source module's key for the anchor verse. The book's display name belongs to the enclosing chapter rather than each entry. There is no separate entry `anchor` object. ## Scripture references Commentary text is plain text, with structured citations in optional `references` arrays. Each citation includes `ref`, `osis`, `book`, and `chapter`; it may include `text`, `verse`, and `verses`. - `text` is the citation as printed in the commentary, when located there. - `ref` is its canonical reference in the module's language. - `book`, `chapter`, and optional verse coverage are GetBible coordinates. - `verses` takes precedence over the anchor `verse`. - A reference without `verse` covers the whole chapter. A cross-chapter range becomes one item per chapter. Book names and verse existence are resolved against the Bible API during the build; the selected translations and naming rules are recorded in metadata. Numeric coordinates support links to the [Bible API](/api/bible/), while canonical strings support the [Query API](/api/query/). Split long lists when they exceed the query service's reference-length limit. Render commentary with a text-safe method such as `textContent`, preserving paragraph breaks. Build links from the structured citation data. ## Metadata, size, and offline use Metadata includes the source module, human name, language, version, license, driver, source type, versification, book/chapter/entry counts, whole-commentary `bytes`, copyright information, source page, conversion notes, URL templates, and reference provenance. Its `storage` block reports source entry and text sizes, deduplicated text size, repetition ratio, and the chapter/book/whole-commentary/published byte totals. These are build measurements, useful for understanding resource size; they do not change the reading contract. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke/43.json' \ --output clarke-john.json curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/hashes.json' \ --output commentary-hashes.json ``` With jq and GNU `sha256sum`, verify the book file against its exact manifest path: ```bash set -euo pipefail expected="$(jq --raw-output --exit-status \ '.files["clarke/43.json"]' commentary-hashes.json)" printf '%s %s\n' "$expected" clarke-john.json | sha256sum --check - ``` Fetch one chapter for normal online reading. Offer larger downloads deliberately after checking metadata size. Keep the manifest and content from a consistent build; if they disagree, refresh and retry rather than using an unverified file. ## Build health and refreshes `hashes.json` lists the SHA-256 of every generated document except itself. It also provides the definitive list of published paths. Unchanged content is byte-stable across builds, while catalogs and build records may change. `build.json` identifies the builder, extractor, contract, build time, source catalog, and Bible API. `build-report.json` records successful modules, failures, and retained previous modules. A `partial` report can still describe usable published data. The report is captured before publication; later deployment errors are recorded by the build workflow. ## Errors and missing material The contract describes HTTP 200 for a JSON document and HTTP 404 when a document does not exist. It does not define an error body format. Always check status before JSON parsing. A missing commentary chapter can mean that the source has no coverage there. An existing chapter with no entry covering a selected verse is a successful lookup with no commentary for that verse. Do not substitute an unrelated chapter. HTTP caching, CORS, request limits, and response headers belong to the hosting deployment and are not guaranteed by the generated static-tree specification. ## Import into Postman or another OpenAPI client Import the [OpenAPI 3.1 description](https://commentaries.getbible.net/v1/openapi.json). Its paths already contain `/v1`, and it intentionally specifies no production hostname. Set the client server/base URL to `https://commentaries.getbible.net`. Every response schema is embedded and also served from `/v1/schema/`. Keep per-module provenance and license details with redistributed commentary resources. ## Complete endpoint reference All paths below are relative to `https://commentaries.getbible.net`. Every operation returns JSON for HTTP 200 and describes HTTP 404 for a missing document. ### GET `/v1/commentaries.json` The catalog of every commentary in the tree. Every commentary this tree holds, with its counts and sizes, and the path template of each of its documents relative to v1/. No parameters. Response model: `commentary-catalog`. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/commentaries.json' ``` ### GET `/v1/build.json` How and when the tree was built. The builder and extractor versions, the build time, the module catalog the modules were selected from and the Bible API the references were resolved against. No parameters. Response model: `build`. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/build.json' ``` ### GET `/v1/build-report.json` The compilation outcome and module failures. The build status, successfully rebuilt modules, failures with their stage and reason, and previously verified modules retained after a failed rebuild. This snapshot describes compilation; the workflow report also records later publication errors. No parameters. Response model: `build-report`. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/build-report.json' ``` ### GET `/v1/hashes.json` The SHA-256 of every other document. The integrity manifest of the tree: a digest for every other document, which is also the complete list of the paths the tree contains. No parameters. Response model: `hashes`. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/hashes.json' ``` ### GET `/v1/openapi.json` This description. The OpenAPI description of the tree, generated with it. No parameters. Response model: `JSON object`. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/openapi.json' ``` ### GET `/v1/schema/{document}.json` The JSON Schema of one document type. The schemas embedded under components, served beside the data. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `document` | string | Yes | The document type. Allowed values: "commentary-catalog", "commentary-metadata", "commentary-books", "commentary-chapter", "commentary-book", "commentary", "build", "build-report", "hashes". | Response model: `JSON object`. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/schema/commentary-chapter.json' ``` ### GET `/v1/{commentary}/metadata.json` One commentary's provenance, licence, counts and sizes. Where the module came from, under which licence, how much it holds, how large its whole-commentary document is, and which Bible its references were resolved against. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `commentary` | string | Yes | The commentary's id, as commentaries.json lists it. Minimum length: 1. | Response model: `commentary-metadata`. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke/metadata.json' ``` ### GET `/v1/{commentary}/books.json` The books and chapters one commentary covers. Every book the commentary comments on, with the chapters it has and the number of entries in each book. Chapter 0 is a book introduction. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `commentary` | string | Yes | The commentary's id, as commentaries.json lists it. Minimum length: 1. | Response model: `commentary-books`. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke/books.json' ``` ### GET `/v1/{commentary}/{book}/{chapter}.json` One chapter of one commentary. Every comment on one chapter, each published once and anchored at the lowest verse it covers. Verse 0 is the chapter introduction. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `commentary` | string | Yes | The commentary's id, as commentaries.json lists it. Minimum length: 1. | | `book` | integer | Yes | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and the deuterocanonical books continue to 83. books.json lists the numbers the commentary has. Minimum: 1. Maximum: 83. | | `chapter` | integer | Yes | Chapter number; 0 is the book introduction. books.json lists the chapters each book has. Minimum: 0. | Response model: `commentary-chapter`. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke/43/1.json' ``` ### GET `/v1/{commentary}/{book}.json` Every chapter of one book. The chapter documents of one book, each byte-for-byte the document served at its own path. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `commentary` | string | Yes | The commentary's id, as commentaries.json lists it. Minimum length: 1. | | `book` | integer | Yes | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and the deuterocanonical books continue to 83. books.json lists the numbers the commentary has. Minimum: 1. Maximum: 83. | Response model: `commentary-book`. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke/43.json' ``` ### GET `/v1/{commentary}.json` The whole commentary. Every book document of the commentary, each byte-for-byte the document served at its own path. A bulk document: metadata.json states its size. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `commentary` | string | Yes | The commentary's id, as commentaries.json lists it. Minimum length: 1. | Response model: `commentary`. ```bash curl --fail --silent --show-error \ 'https://commentaries.getbible.net/v1/clarke.json' ``` ## Complete response field reference The tables preserve the generated OpenAPI field names, types, required fields, and constraints. Nested required fields are required when their containing object is present. Fields marked optional may be omitted. JSON Schemas in the linked specification provide the complete machine-readable contract. ### commentary-catalog Every commentary in one v1 tree, with the path template of each of its documents relative to the tree root. The catalog and build.json are the only documents that carry the build time. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-commentaries-catalog-v1". | | `version` | number | Yes | Constant: 1. | | `generated_at` | string | Yes | Format: date-time. | | `base_url` | string | Yes | Minimum length: 1. | | `metadata_url_template` | string | Yes | Constant: "{commentary}/metadata.json". | | `books_url_template` | string | Yes | Constant: "{commentary}/books.json". | | `commentary_url_template` | string | Yes | Constant: "{commentary}.json". | | `book_url_template` | string | Yes | Constant: "{commentary}/{book}.json". | | `chapter_url_template` | string | Yes | Constant: "{commentary}/{book}/{chapter}.json". | | `module_count` | integer | Yes | Minimum: 0. | | `commentaries` | array | Yes | | | `commentaries[].id` | string | Yes | Minimum length: 1. | | `commentaries[].name` | string | Yes | Minimum length: 1. | | `commentaries[].language` | string | Yes | Minimum length: 2. | | `commentaries[].license` | string | Yes | | | `commentaries[].book_count` | integer | Yes | Minimum: 0. | | `commentaries[].chapter_count` | integer | Yes | Minimum: 0. | | `commentaries[].entry_count` | integer | Yes | Minimum: 0. | | `commentaries[].bytes` | integer | Yes | Minimum: 0. | ### commentary-metadata One commentary's provenance, licence, counts and sizes. bytes is the size of the whole-commentary document; storage is the build's own measurement of the module. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-commentary-metadata-v1". | | `id` | string | Yes | Minimum length: 1. | | `module` | string | Yes | The source module's own name. Minimum length: 1. | | `name` | string | Yes | Minimum length: 1. | | `language` | string | Yes | Minimum length: 2. | | `version` | string | Yes | | | `license` | string | Yes | | | `driver` | string | Yes | | | `source_type` | string | Yes | | | `versification` | string | Yes | Minimum length: 1. | | `book_count` | integer | Yes | Minimum: 0. | | `chapter_count` | integer | Yes | Minimum: 0. | | `entry_count` | integer | Yes | Minimum: 0. | | `bytes` | integer | Yes | Minimum: 0. | | `storage` | object | Yes | How much text the source repeated across verse ranges and what each level of the output costs on disk. No additional fields. | | `storage.source_entry_count` | integer | Yes | Minimum: 0. | | `storage.source_text_bytes` | integer | Yes | Minimum: 0. | | `storage.text_bytes` | integer | Yes | Minimum: 0. | | `storage.repetition_ratio` | number | Yes | Minimum: 0. | | `storage.chapter_bytes` | integer | Yes | Minimum: 0. | | `storage.book_bytes` | integer | Yes | Minimum: 0. | | `storage.commentary_bytes` | integer | Yes | Minimum: 0. | | `storage.published_bytes` | integer | Yes | Minimum: 0. | | `books_url` | string | Yes | Constant: "books.json". | | `book_url_template` | string | Yes | Constant: "{book}.json". | | `chapter_url_template` | string | Yes | Constant: "{book}/{chapter}.json". | | `source` | string | Yes | Constant: "CrossWire SWORD". | | `source_module_url` | string | Yes | The module's own page at its source. Minimum length: 1. | | `text_source` | string | Yes | | | `copyright` | string | Yes | | | `copyright_holder` | string | Yes | | | `copyright_contact` | object | Yes | No additional fields. | | `copyright_contact.name` | string | Yes | | | `copyright_contact.email` | string | Yes | | | `copyright_contact.address` | string | Yes | | | `distribution_notes` | string | Yes | | | `about` | string | Yes | | | `conversion_note` | string | Yes | Minimum length: 1. | | `references` | object | Yes | Which Bible the module's scripture references were resolved against: the API, the versification, the translations whose shape decided which chapters and verses exist, the translation whose book names ref uses, and the librarian and alias tables that resolved the spellings. No additional fields. | | `references.api` | string | Yes | Constant: "getbible-v2". | | `references.versification` | string | Yes | | | `references.translations` | array | Yes | | | `references.names` | string, null | Yes | | | `references.language` | string | Yes | | | `references.librarian` | array | Yes | | | `references.aliases` | array | Yes | | ### commentary-books Which books and chapters one commentary covers. Chapter 0 is a book introduction. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-commentary-books-v1". | | `commentary` | string | Yes | Minimum length: 1. | | `language` | string | Yes | Minimum length: 2. | | `name` | string | Yes | Minimum length: 1. | | `book_url_template` | string | Yes | Constant: "{book}.json". | | `chapter_url_template` | string | Yes | Constant: "{book}/{chapter}.json". | | `book_count` | integer | Yes | Minimum: 0. | | `books` | array | Yes | | | `books[].book` | integer | Yes | Minimum: 1. Maximum: 83. | | `books[].name` | string | Yes | Minimum length: 1. | | `books[].chapters` | array | Yes | | | `books[].entry_count` | integer | Yes | Minimum: 0. | ### commentary-chapter One chapter of one commentary. Chapter 0 carries the book introduction and verse 0 carries a chapter introduction. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-commentary-chapter-v1". | | `commentary` | string | Yes | Minimum length: 1. | | `language` | string | Yes | Minimum length: 2. | | `book` | integer | Yes | Minimum: 1. Maximum: 83. | | `name` | string | Yes | Minimum length: 1. | | `chapter` | integer | Yes | Minimum: 0. | | `entries` | array | Yes | | | `entries[]` | entry | — | See commentary-chapter/$defs/entry. | #### commentary-chapter: entry One comment. A source module attaches a comment to a verse range and repeats it for every verse in that range; it is published once here, anchored at the lowest verse it covers, with `verses` listing every verse it applies to when that is more than one. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `book` | integer | Yes | Minimum: 1. Maximum: 83. | | `chapter` | integer | Yes | Minimum: 0. | | `verse` | integer | Yes | The lowest verse this comment covers. Minimum: 0. | | `verses` | array | No | Every verse this comment covers, including `verse`. Absent when it covers only `verse`. Minimum items: 2. Items are unique. | | `osis` | string | No | The source module's own key for the anchor verse. Minimum length: 1. | | `text` | string | Yes | | | `references` | references | No | See commentary-chapter/$defs/references. | #### commentary-chapter: references | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `text` | string | No | Minimum length: 1. | | `ref` | string | Yes | Minimum length: 1. | | `osis` | string | Yes | Minimum length: 1. | | `book` | integer | Yes | Minimum: 1. Maximum: 83. | | `chapter` | integer | Yes | Minimum: 0. | | `verse` | integer | No | Minimum: 0. | | `verses` | array | No | Every verse this reference covers, including verse. Absent when it covers only verse. Minimum items: 2. Items are unique. | ### commentary-book Every chapter of one book of one commentary. Each member of chapters is byte-for-byte the document served at {commentary}/{book}/{chapter}.json. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-commentary-book-v1". | | `commentary` | string | Yes | Minimum length: 1. | | `language` | string | Yes | Minimum length: 2. | | `book` | integer | Yes | Minimum: 1. Maximum: 83. | | `name` | string | Yes | Minimum length: 1. | | `chapters` | array | Yes | | | `chapters[]` | commentary-chapter | — | See commentary-chapter. | ### commentary One complete commentary. Each member of books is byte-for-byte the document served at {commentary}/{book}.json. This is a bulk document; metadata.json publishes its size in bytes. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-commentary-v1". | | `commentary` | string | Yes | Minimum length: 1. | | `language` | string | Yes | Minimum length: 2. | | `name` | string | Yes | Minimum length: 1. | | `books` | array | Yes | | | `books[]` | commentary-book | — | See commentary-book. | ### build How and when one v1 tree was built: the builder and extractor, the catalog the modules were selected from and the Bible API the references were resolved against. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-build-v1". | | `builder` | string | Yes | Constant: "v1_study_builder". | | `builder_version` | string | Yes | Minimum length: 1. | | `extractor` | string | Yes | Constant: "getbiblesword". | | `extractor_version` | string | Yes | Minimum length: 1. | | `extractor_contract` | string | Yes | Minimum length: 1. | | `api_version` | number | Yes | Constant: 1. | | `resource` | enum | Yes | Allowed values: "commentaries", "dictionaries". | | `generated_at` | string | Yes | Format: date-time. | | `catalog_url` | string | Yes | Minimum length: 1. | | `bible_api` | string | Yes | Minimum length: 1. | | `module_count` | integer | Yes | Minimum: 0. | ### build-report Compilation status and actionable diagnostics for one build. A published snapshot is captured before repository publication; the workflow report is updated with later publication errors. Successfully rebuilt modules and retained previous modules are listed separately. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-build-report-v1". | | `status` | enum | Yes | Running is an in-progress checkpoint. Success means all approved modules built; partial means usable output exists with reported failures. Failed means the run could not complete safely. Publication failures are recorded in the workflow report. Allowed values: "running", "success", "partial", "failed". | | `started_at` | string | Yes | Format: date-time. | | `completed_at` | string, null | Yes | Format: date-time. | | `requested_resource` | enum | Yes | Allowed values: "all", "commentaries", "dictionaries". | | `catalog_url` | string | Yes | Minimum length: 1. | | `built` | object | Yes | No additional fields. | | `built.commentaries` | array | Yes | | | `built.dictionaries` | array | Yes | | | `skipped` | array | Yes | | | `skipped[]` | moduleIssue | — | See build-report/$defs/moduleIssue. | | `failed` | array | Yes | | | `failed[]` | moduleFailure | — | See build-report/$defs/moduleFailure. | | `retained` | array | Yes | Failed modules whose prior verified documents remain in the published tree. | | `retained[]` | moduleIssue | — | See build-report/$defs/moduleIssue. | | `errors` | array | Yes | | | `errors[].stage` | string | Yes | Minimum length: 1. | | `errors[].error_type` | string | Yes | Minimum length: 1. | | `errors[].reason` | string | Yes | | | `errors[].resource` | enum | No | Allowed values: "commentaries", "dictionaries". | | `diagnostics` | object | Yes | | | `diagnostics.{key}` | array | — | | | `storage` | object | Yes | | | `storage.{key}` | object | — | | | `commits` | object | Yes | | | `commits.{key}` | string, null | — | | #### build-report: moduleIssue | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `resource` | enum | Yes | Allowed values: "commentaries", "dictionaries". | | `module` | string | Yes | Minimum length: 1. | | `reason` | string | Yes | | #### build-report: moduleFailure | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `resource` | enum | Yes | Allowed values: "commentaries", "dictionaries". | | `module` | string | Yes | Minimum length: 1. | | `reason` | string | Yes | | | `stage` | string | Yes | Minimum length: 1. | | `error_type` | string | Yes | Minimum length: 1. | ### hashes The SHA-256 of every other document in one v1 tree, keyed by path relative to the tree root; also the complete list of the paths the tree contains. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-hashes-v1". | | `algorithm` | string | Yes | Constant: "sha256". | | `files` | object | Yes | | | `files.{key}` | string | — | Pattern: ^[0-9a-f]{64}$. | ## Sources - [Published commentaries OpenAPI specification](https://commentaries.getbible.net/v1/openapi.json) - [Generated commentaries data repository](https://github.com/getbible/commentaries) - [Study builder contracts and implementation guide](https://github.com/getbible/v1_study_builder) ## Complete contract reference Open the [complete endpoint and schema reference](/api/commentaries/v1/reference/) for every operation, parameter, response and component model in the published OpenAPI contract. --- # Commentaries API v1: endpoint and schema reference This reference is generated from the checked-in [OpenAPI contract](https://commentaries.getbible.net/v1/openapi.json). Return to the [integration guide](/api/commentaries/v1/) for workflows and ready-to-run examples. Resolved request server: `https://commentaries.getbible.net`. ## GET /v1/commentaries.json The catalog of every commentary in the tree Every commentary this tree holds, with its counts and sizes, and the path template of each of its documents relative to v1/. Operation ID: `listCommentaries`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The catalog of every commentary in the tree | application/json | #/components/schemas/commentary-catalog | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The catalog of every commentary in the tree", "description": "Every commentary this tree holds, with its counts and sizes, and the path template of each of its documents relative to v1/.", "operationId": "listCommentaries", "responses": { "200": { "description": "The catalog of every commentary in the tree", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/commentary-catalog" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } }, "parameters": [] } ```
## GET /v1/build.json How and when the tree was built The builder and extractor versions, the build time, the module catalog the modules were selected from and the Bible API the references were resolved against. Operation ID: `getBuild`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | How and when the tree was built | application/json | #/components/schemas/build | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "How and when the tree was built", "description": "The builder and extractor versions, the build time, the module catalog the modules were selected from and the Bible API the references were resolved against.", "operationId": "getBuild", "responses": { "200": { "description": "How and when the tree was built", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/build" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } }, "parameters": [] } ```
## GET /v1/build-report.json The compilation outcome and module failures The build status, successfully rebuilt modules, failures with their stage and reason, and previously verified modules retained after a failed rebuild. This snapshot describes compilation; the workflow report also records later publication errors. Operation ID: `getBuildReport`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The compilation outcome and module failures | application/json | #/components/schemas/build-report | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The compilation outcome and module failures", "description": "The build status, successfully rebuilt modules, failures with their stage and reason, and previously verified modules retained after a failed rebuild. This snapshot describes compilation; the workflow report also records later publication errors.", "operationId": "getBuildReport", "responses": { "200": { "description": "The compilation outcome and module failures", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/build-report" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } }, "parameters": [] } ```
## GET /v1/hashes.json The SHA-256 of every other document The integrity manifest of the tree: a digest for every other document, which is also the complete list of the paths the tree contains. Operation ID: `getHashes`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-256 of every other document | application/json | #/components/schemas/hashes | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The SHA-256 of every other document", "description": "The integrity manifest of the tree: a digest for every other document, which is also the complete list of the paths the tree contains.", "operationId": "getHashes", "responses": { "200": { "description": "The SHA-256 of every other document", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/hashes" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } }, "parameters": [] } ```
## GET /v1/openapi.json This description The OpenAPI description of the tree, generated with it. Operation ID: `getOpenApi`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | This description | application/json | object | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "This description", "description": "The OpenAPI description of the tree, generated with it.", "operationId": "getOpenApi", "responses": { "200": { "description": "This description", "content": { "application/json": { "schema": { "type": "object" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } }, "parameters": [] } ```
## GET /v1/schema/{document}.json The JSON Schema of one document type The schemas embedded under components, served beside the data. Operation ID: `getSchema`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `document` | path | Yes | string | commentary-catalog | The document type. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The JSON Schema of one document type | application/json | object | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The JSON Schema of one document type", "description": "The schemas embedded under components, served beside the data.", "operationId": "getSchema", "parameters": [ { "name": "document", "in": "path", "required": true, "description": "The document type.", "schema": { "type": "string", "enum": [ "commentary-catalog", "commentary-metadata", "commentary-books", "commentary-chapter", "commentary-book", "commentary", "build", "build-report", "hashes" ] } } ], "responses": { "200": { "description": "The JSON Schema of one document type", "content": { "application/json": { "schema": { "type": "object" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } } } ```
## GET /v1/{commentary}/metadata.json One commentary's provenance, licence, counts and sizes Where the module came from, under which licence, how much it holds, how large its whole-commentary document is, and which Bible its references were resolved against. Operation ID: `getCommentaryMetadata`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `commentary` | path | Yes | string | mhc | The commentary's id, as commentaries.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | One commentary's provenance, licence, counts and sizes | application/json | #/components/schemas/commentary-metadata | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "commentary" ], "summary": "One commentary's provenance, licence, counts and sizes", "description": "Where the module came from, under which licence, how much it holds, how large its whole-commentary document is, and which Bible its references were resolved against.", "operationId": "getCommentaryMetadata", "parameters": [ { "name": "commentary", "in": "path", "required": true, "description": "The commentary's id, as commentaries.json lists it.", "schema": { "type": "string", "minLength": 1, "enum": [ "abbott", "barnes", "burkitt", "calvincommentaries", "catena", "clarke", "dtn", "dutkant", "freaug", "frechry", "jfb", "kd", "lightfoot", "luther", "mak", "mhc", "mhcc", "pnt", "quotingpassages", "rieger", "scofield", "sentiment", "spurious", "tdavid", "tfg", "tsk", "varapp", "vulgglossa", "wesley" ] } } ], "responses": { "200": { "description": "One commentary's provenance, licence, counts and sizes", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/commentary-metadata" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } } } ```
## GET /v1/{commentary}/books.json The books and chapters one commentary covers Every book the commentary comments on, with the chapters it has and the number of entries in each book. Chapter 0 is a book introduction. Operation ID: `getCommentaryBooks`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `commentary` | path | Yes | string | mhc | The commentary's id, as commentaries.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The books and chapters one commentary covers | application/json | #/components/schemas/commentary-books | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "commentary" ], "summary": "The books and chapters one commentary covers", "description": "Every book the commentary comments on, with the chapters it has and the number of entries in each book. Chapter 0 is a book introduction.", "operationId": "getCommentaryBooks", "parameters": [ { "name": "commentary", "in": "path", "required": true, "description": "The commentary's id, as commentaries.json lists it.", "schema": { "type": "string", "minLength": 1, "enum": [ "abbott", "barnes", "burkitt", "calvincommentaries", "catena", "clarke", "dtn", "dutkant", "freaug", "frechry", "jfb", "kd", "lightfoot", "luther", "mak", "mhc", "mhcc", "pnt", "quotingpassages", "rieger", "scofield", "sentiment", "spurious", "tdavid", "tfg", "tsk", "varapp", "vulgglossa", "wesley" ] } } ], "responses": { "200": { "description": "The books and chapters one commentary covers", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/commentary-books" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } } } ```
## GET /v1/{commentary}/{book}/{chapter}.json One chapter of one commentary Every comment on one chapter, each published once and anchored at the lowest verse it covers. Verse 0 is the chapter introduction. Operation ID: `getCommentaryChapter`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `commentary` | path | Yes | string | mhc | The commentary's id, as commentaries.json lists it. | | `book` | path | Yes | integer | 1 | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and the deuterocanonical books continue to 83. books.json lists the numbers the commentary has. | | `chapter` | path | Yes | integer | 1 | Chapter number; 0 is the book introduction. books.json lists the chapters each book has. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | One chapter of one commentary | application/json | #/components/schemas/commentary-chapter | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "commentary" ], "summary": "One chapter of one commentary", "description": "Every comment on one chapter, each published once and anchored at the lowest verse it covers. Verse 0 is the chapter introduction.", "operationId": "getCommentaryChapter", "parameters": [ { "name": "commentary", "in": "path", "required": true, "description": "The commentary's id, as commentaries.json lists it.", "schema": { "type": "string", "minLength": 1, "enum": [ "abbott", "barnes", "burkitt", "calvincommentaries", "catena", "clarke", "dtn", "dutkant", "freaug", "frechry", "jfb", "kd", "lightfoot", "luther", "mak", "mhc", "mhcc", "pnt", "quotingpassages", "rieger", "scofield", "sentiment", "spurious", "tdavid", "tfg", "tsk", "varapp", "vulgglossa", "wesley" ] } }, { "name": "book", "in": "path", "required": true, "description": "GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and the deuterocanonical books continue to 83. books.json lists the numbers the commentary has.", "schema": { "type": "integer", "minimum": 1, "maximum": 83 } }, { "name": "chapter", "in": "path", "required": true, "description": "Chapter number; 0 is the book introduction. books.json lists the chapters each book has.", "schema": { "type": "integer", "minimum": 0 } } ], "responses": { "200": { "description": "One chapter of one commentary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/commentary-chapter" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } } } ```
## GET /v1/{commentary}/{book}.json Every chapter of one book The chapter documents of one book, each byte-for-byte the document served at its own path. Operation ID: `getCommentaryBook`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `commentary` | path | Yes | string | mhc | The commentary's id, as commentaries.json lists it. | | `book` | path | Yes | integer | 1 | GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and the deuterocanonical books continue to 83. books.json lists the numbers the commentary has. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Every chapter of one book | application/json | #/components/schemas/commentary-book | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "commentary" ], "summary": "Every chapter of one book", "description": "The chapter documents of one book, each byte-for-byte the document served at its own path.", "operationId": "getCommentaryBook", "parameters": [ { "name": "commentary", "in": "path", "required": true, "description": "The commentary's id, as commentaries.json lists it.", "schema": { "type": "string", "minLength": 1, "enum": [ "abbott", "barnes", "burkitt", "calvincommentaries", "catena", "clarke", "dtn", "dutkant", "freaug", "frechry", "jfb", "kd", "lightfoot", "luther", "mak", "mhc", "mhcc", "pnt", "quotingpassages", "rieger", "scofield", "sentiment", "spurious", "tdavid", "tfg", "tsk", "varapp", "vulgglossa", "wesley" ] } }, { "name": "book", "in": "path", "required": true, "description": "GetBible book number: Genesis is 1, Matthew 40, Revelation 66, and the deuterocanonical books continue to 83. books.json lists the numbers the commentary has.", "schema": { "type": "integer", "minimum": 1, "maximum": 83 } } ], "responses": { "200": { "description": "Every chapter of one book", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/commentary-book" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } } } ```
## GET /v1/{commentary}.json The whole commentary Every book document of the commentary, each byte-for-byte the document served at its own path. A bulk document: metadata.json states its size. Operation ID: `getCommentary`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `commentary` | path | Yes | string | mhc | The commentary's id, as commentaries.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The whole commentary | application/json | #/components/schemas/commentary | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "commentary" ], "summary": "The whole commentary", "description": "Every book document of the commentary, each byte-for-byte the document served at its own path. A bulk document: metadata.json states its size.", "operationId": "getCommentary", "parameters": [ { "name": "commentary", "in": "path", "required": true, "description": "The commentary's id, as commentaries.json lists it.", "schema": { "type": "string", "minLength": 1, "enum": [ "abbott", "barnes", "burkitt", "calvincommentaries", "catena", "clarke", "dtn", "dutkant", "freaug", "frechry", "jfb", "kd", "lightfoot", "luther", "mak", "mhc", "mhcc", "pnt", "quotingpassages", "rieger", "scofield", "sentiment", "spurious", "tdavid", "tfg", "tsk", "varapp", "vulgglossa", "wesley" ] } } ], "responses": { "200": { "description": "The whole commentary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/commentary" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } } } ```
## Component schemas Types, required properties, nested objects, constraints and examples below are copied directly from the contract. A property omitted from a schema’s `required` array is optional, even when examples include it. ### commentary-catalog Every commentary in one v1 tree, with the path template of each of its documents relative to the tree root. The catalog and build.json are the only documents that carry the build time.
View full commentary-catalog schema ```json { "title": "GetBible Commentary Catalog v1", "description": "Every commentary in one v1 tree, with the path template of each of its documents relative to the tree root. The catalog and build.json are the only documents that carry the build time.", "type": "object", "required": [ "schema", "version", "generated_at", "base_url", "metadata_url_template", "books_url_template", "commentary_url_template", "book_url_template", "chapter_url_template", "module_count", "commentaries" ], "properties": { "schema": { "const": "getbible-commentaries-catalog-v1" }, "version": { "const": 1 }, "generated_at": { "type": "string", "format": "date-time" }, "base_url": { "type": "string", "minLength": 1 }, "metadata_url_template": { "const": "{commentary}/metadata.json" }, "books_url_template": { "const": "{commentary}/books.json" }, "commentary_url_template": { "const": "{commentary}.json" }, "book_url_template": { "const": "{commentary}/{book}.json" }, "chapter_url_template": { "const": "{commentary}/{book}/{chapter}.json" }, "module_count": { "type": "integer", "minimum": 0 }, "commentaries": { "type": "array", "items": { "type": "object", "description": "One commentary: its id is the first path segment of all of its documents, and bytes is the size of its whole-commentary document.", "required": [ "id", "name", "language", "license", "book_count", "chapter_count", "entry_count", "bytes" ], "properties": { "id": { "type": "string", "minLength": 1 }, "name": { "type": "string", "minLength": 1 }, "language": { "type": "string", "minLength": 2 }, "license": { "type": "string" }, "book_count": { "type": "integer", "minimum": 0 }, "chapter_count": { "type": "integer", "minimum": 0 }, "entry_count": { "type": "integer", "minimum": 0 }, "bytes": { "type": "integer", "minimum": 0 } }, "additionalProperties": false } } }, "additionalProperties": false } ```
### commentary-metadata One commentary's provenance, licence, counts and sizes. bytes is the size of the whole-commentary document; storage is the build's own measurement of the module.
View full commentary-metadata schema ```json { "title": "GetBible Commentary Metadata v1", "description": "One commentary's provenance, licence, counts and sizes. bytes is the size of the whole-commentary document; storage is the build's own measurement of the module.", "type": "object", "required": [ "schema", "id", "module", "name", "language", "version", "license", "driver", "source_type", "versification", "book_count", "chapter_count", "entry_count", "bytes", "storage", "books_url", "book_url_template", "chapter_url_template", "source", "source_module_url", "text_source", "copyright", "copyright_holder", "copyright_contact", "distribution_notes", "about", "conversion_note", "references" ], "properties": { "schema": { "const": "getbible-commentary-metadata-v1" }, "id": { "type": "string", "minLength": 1 }, "module": { "type": "string", "minLength": 1, "description": "The source module's own name." }, "name": { "type": "string", "minLength": 1 }, "language": { "type": "string", "minLength": 2 }, "version": { "type": "string" }, "license": { "type": "string" }, "driver": { "type": "string" }, "source_type": { "type": "string" }, "versification": { "type": "string", "minLength": 1 }, "book_count": { "type": "integer", "minimum": 0 }, "chapter_count": { "type": "integer", "minimum": 0 }, "entry_count": { "type": "integer", "minimum": 0 }, "bytes": { "type": "integer", "minimum": 0 }, "storage": { "type": "object", "description": "How much text the source repeated across verse ranges and what each level of the output costs on disk.", "required": [ "source_entry_count", "source_text_bytes", "text_bytes", "repetition_ratio", "chapter_bytes", "book_bytes", "commentary_bytes", "published_bytes" ], "properties": { "source_entry_count": { "type": "integer", "minimum": 0 }, "source_text_bytes": { "type": "integer", "minimum": 0 }, "text_bytes": { "type": "integer", "minimum": 0 }, "repetition_ratio": { "type": "number", "minimum": 0 }, "chapter_bytes": { "type": "integer", "minimum": 0 }, "book_bytes": { "type": "integer", "minimum": 0 }, "commentary_bytes": { "type": "integer", "minimum": 0 }, "published_bytes": { "type": "integer", "minimum": 0 } }, "additionalProperties": false }, "books_url": { "const": "books.json" }, "book_url_template": { "const": "{book}.json" }, "chapter_url_template": { "const": "{book}/{chapter}.json" }, "source": { "const": "CrossWire SWORD" }, "source_module_url": { "type": "string", "minLength": 1, "description": "The module's own page at its source." }, "text_source": { "type": "string" }, "copyright": { "type": "string" }, "copyright_holder": { "type": "string" }, "copyright_contact": { "type": "object", "required": [ "name", "email", "address" ], "properties": { "name": { "type": "string" }, "email": { "type": "string" }, "address": { "type": "string" } }, "additionalProperties": false }, "distribution_notes": { "type": "string" }, "about": { "type": "string" }, "conversion_note": { "type": "string", "minLength": 1 }, "references": { "type": "object", "description": "Which Bible the module's scripture references were resolved against: the API, the versification, the translations whose shape decided which chapters and verses exist, the translation whose book names ref uses, and the librarian and alias tables that resolved the spellings.", "required": [ "api", "versification", "translations", "names", "language", "librarian", "aliases" ], "properties": { "api": { "const": "getbible-v2" }, "versification": { "type": "string" }, "translations": { "type": "array", "items": { "type": "string", "minLength": 1 } }, "names": { "type": [ "string", "null" ] }, "language": { "type": "string" }, "librarian": { "type": "array", "items": { "type": "string", "minLength": 1 } }, "aliases": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "additionalProperties": false } }, "additionalProperties": false } ```
### commentary-books Which books and chapters one commentary covers. Chapter 0 is a book introduction.
View full commentary-books schema ```json { "title": "GetBible Commentary Books Index v1", "description": "Which books and chapters one commentary covers. Chapter 0 is a book introduction.", "type": "object", "required": [ "schema", "commentary", "language", "name", "book_url_template", "chapter_url_template", "book_count", "books" ], "properties": { "schema": { "const": "getbible-commentary-books-v1" }, "commentary": { "type": "string", "minLength": 1 }, "language": { "type": "string", "minLength": 2 }, "name": { "type": "string", "minLength": 1 }, "book_url_template": { "const": "{book}.json" }, "chapter_url_template": { "const": "{book}/{chapter}.json" }, "book_count": { "type": "integer", "minimum": 0 }, "books": { "type": "array", "items": { "type": "object", "required": [ "book", "name", "chapters", "entry_count" ], "properties": { "book": { "type": "integer", "minimum": 1, "maximum": 83 }, "name": { "type": "string", "minLength": 1 }, "chapters": { "type": "array", "items": { "type": "integer", "minimum": 0 } }, "entry_count": { "type": "integer", "minimum": 0 } }, "additionalProperties": false } } }, "additionalProperties": false } ```
### commentary-chapter One chapter of one commentary. Chapter 0 carries the book introduction and verse 0 carries a chapter introduction.
View full commentary-chapter schema ```json { "title": "GetBible Commentary Chapter v1", "description": "One chapter of one commentary. Chapter 0 carries the book introduction and verse 0 carries a chapter introduction.", "type": "object", "required": [ "schema", "commentary", "language", "book", "name", "chapter", "entries" ], "properties": { "schema": { "const": "getbible-commentary-chapter-v1" }, "commentary": { "type": "string", "minLength": 1 }, "language": { "type": "string", "minLength": 2 }, "book": { "type": "integer", "minimum": 1, "maximum": 83 }, "name": { "type": "string", "minLength": 1 }, "chapter": { "type": "integer", "minimum": 0 }, "entries": { "type": "array", "items": { "$ref": "#/components/schemas/commentary-chapter/$defs/entry" } } }, "additionalProperties": false, "$defs": { "entry": { "type": "object", "description": "One comment. A source module attaches a comment to a verse range and repeats it for every verse in that range; it is published once here, anchored at the lowest verse it covers, with `verses` listing every verse it applies to when that is more than one.", "required": [ "book", "chapter", "verse", "text" ], "properties": { "book": { "type": "integer", "minimum": 1, "maximum": 83 }, "chapter": { "type": "integer", "minimum": 0 }, "verse": { "type": "integer", "minimum": 0, "description": "The lowest verse this comment covers." }, "verses": { "type": "array", "description": "Every verse this comment covers, including `verse`. Absent when it covers only `verse`.", "items": { "type": "integer", "minimum": 0 }, "minItems": 2, "uniqueItems": true }, "osis": { "type": "string", "minLength": 1, "description": "The source module's own key for the anchor verse." }, "text": { "type": "string" }, "references": { "$ref": "#/components/schemas/commentary-chapter/$defs/references" } }, "additionalProperties": false }, "references": { "type": "array", "items": { "type": "object", "description": "One scripture reference, resolved against the GetBible Bible API. book, chapter, and verse are Bible API coordinates; verses lists every verse covered when there is more than one, and an item without verse covers the whole chapter. ref is the same reference written canonically, in the book name the module's language uses, in the form the Query API accepts. text is present when the citation was located in the entry text: the citation exactly as the text spells it.", "required": [ "ref", "osis", "book", "chapter" ], "properties": { "text": { "type": "string", "minLength": 1 }, "ref": { "type": "string", "minLength": 1 }, "osis": { "type": "string", "minLength": 1 }, "book": { "type": "integer", "minimum": 1, "maximum": 83 }, "chapter": { "type": "integer", "minimum": 0 }, "verse": { "type": "integer", "minimum": 0 }, "verses": { "type": "array", "description": "Every verse this reference covers, including verse. Absent when it covers only verse.", "items": { "type": "integer", "minimum": 0 }, "minItems": 2, "uniqueItems": true } }, "additionalProperties": false } } } } ```
### commentary-book Every chapter of one book of one commentary. Each member of chapters is byte-for-byte the document served at {commentary}/{book}/{chapter}.json.
View full commentary-book schema ```json { "title": "GetBible Commentary Book v1", "description": "Every chapter of one book of one commentary. Each member of chapters is byte-for-byte the document served at {commentary}/{book}/{chapter}.json.", "type": "object", "required": [ "schema", "commentary", "language", "book", "name", "chapters" ], "properties": { "schema": { "const": "getbible-commentary-book-v1" }, "commentary": { "type": "string", "minLength": 1 }, "language": { "type": "string", "minLength": 2 }, "book": { "type": "integer", "minimum": 1, "maximum": 83 }, "name": { "type": "string", "minLength": 1 }, "chapters": { "type": "array", "items": { "$ref": "#/components/schemas/commentary-chapter" } } }, "additionalProperties": false } ```
### commentary One complete commentary. Each member of books is byte-for-byte the document served at {commentary}/{book}.json. This is a bulk document; metadata.json publishes its size in bytes.
View full commentary schema ```json { "title": "GetBible Commentary v1", "description": "One complete commentary. Each member of books is byte-for-byte the document served at {commentary}/{book}.json. This is a bulk document; metadata.json publishes its size in bytes.", "type": "object", "required": [ "schema", "commentary", "language", "name", "books" ], "properties": { "schema": { "const": "getbible-commentary-v1" }, "commentary": { "type": "string", "minLength": 1 }, "language": { "type": "string", "minLength": 2 }, "name": { "type": "string", "minLength": 1 }, "books": { "type": "array", "items": { "$ref": "#/components/schemas/commentary-book" } } }, "additionalProperties": false } ```
### build How and when one v1 tree was built: the builder and extractor, the catalog the modules were selected from and the Bible API the references were resolved against.
View full build schema ```json { "title": "GetBible Build v1", "description": "How and when one v1 tree was built: the builder and extractor, the catalog the modules were selected from and the Bible API the references were resolved against.", "type": "object", "required": [ "schema", "builder", "builder_version", "extractor", "extractor_version", "extractor_contract", "api_version", "resource", "generated_at", "catalog_url", "bible_api", "module_count" ], "properties": { "schema": { "const": "getbible-build-v1" }, "builder": { "const": "v1_study_builder" }, "builder_version": { "type": "string", "minLength": 1 }, "extractor": { "const": "getbiblesword" }, "extractor_version": { "type": "string", "minLength": 1 }, "extractor_contract": { "type": "string", "minLength": 1 }, "api_version": { "const": 1 }, "resource": { "enum": [ "commentaries", "dictionaries" ] }, "generated_at": { "type": "string", "format": "date-time" }, "catalog_url": { "type": "string", "minLength": 1 }, "bible_api": { "type": "string", "minLength": 1 }, "module_count": { "type": "integer", "minimum": 0 } }, "additionalProperties": false } ```
### build-report Compilation status and actionable diagnostics for one build. A published snapshot is captured before repository publication; the workflow report is updated with later publication errors. Successfully rebuilt modules and retained previous modules are listed separately.
View full build-report schema ```json { "title": "GetBible Build Report v1", "description": "Compilation status and actionable diagnostics for one build. A published snapshot is captured before repository publication; the workflow report is updated with later publication errors. Successfully rebuilt modules and retained previous modules are listed separately.", "type": "object", "required": [ "schema", "status", "started_at", "completed_at", "requested_resource", "catalog_url", "built", "skipped", "failed", "retained", "errors", "diagnostics", "storage", "commits" ], "properties": { "schema": { "const": "getbible-build-report-v1" }, "status": { "enum": [ "running", "success", "partial", "failed" ], "description": "Running is an in-progress checkpoint. Success means all approved modules built; partial means usable output exists with reported failures. Failed means the run could not complete safely. Publication failures are recorded in the workflow report." }, "started_at": { "type": "string", "format": "date-time" }, "completed_at": { "type": [ "string", "null" ], "format": "date-time" }, "requested_resource": { "enum": [ "all", "commentaries", "dictionaries" ] }, "catalog_url": { "type": "string", "minLength": 1 }, "built": { "type": "object", "required": [ "commentaries", "dictionaries" ], "properties": { "commentaries": { "type": "array", "items": { "type": "string" } }, "dictionaries": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": false }, "skipped": { "type": "array", "items": { "$ref": "#/components/schemas/build-report/$defs/moduleIssue" } }, "failed": { "type": "array", "items": { "$ref": "#/components/schemas/build-report/$defs/moduleFailure" } }, "retained": { "type": "array", "description": "Failed modules whose prior verified documents remain in the published tree.", "items": { "$ref": "#/components/schemas/build-report/$defs/moduleIssue" } }, "errors": { "type": "array", "items": { "type": "object", "required": [ "stage", "error_type", "reason" ], "properties": { "stage": { "type": "string", "minLength": 1 }, "error_type": { "type": "string", "minLength": 1 }, "reason": { "type": "string" }, "resource": { "enum": [ "commentaries", "dictionaries" ] } }, "additionalProperties": false } }, "diagnostics": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "object" } } }, "storage": { "type": "object", "additionalProperties": { "type": "object" } }, "commits": { "type": "object", "additionalProperties": { "type": [ "string", "null" ] } } }, "$defs": { "moduleIssue": { "type": "object", "required": [ "resource", "module", "reason" ], "properties": { "resource": { "enum": [ "commentaries", "dictionaries" ] }, "module": { "type": "string", "minLength": 1 }, "reason": { "type": "string" } }, "additionalProperties": false }, "moduleFailure": { "type": "object", "required": [ "resource", "module", "reason", "stage", "error_type" ], "properties": { "resource": { "enum": [ "commentaries", "dictionaries" ] }, "module": { "type": "string", "minLength": 1 }, "reason": { "type": "string" }, "stage": { "type": "string", "minLength": 1 }, "error_type": { "type": "string", "minLength": 1 } }, "additionalProperties": false } }, "additionalProperties": false } ```
### hashes The SHA-256 of every other document in one v1 tree, keyed by path relative to the tree root; also the complete list of the paths the tree contains.
View full hashes schema ```json { "title": "GetBible Hashes v1", "description": "The SHA-256 of every other document in one v1 tree, keyed by path relative to the tree root; also the complete list of the paths the tree contains.", "type": "object", "required": [ "schema", "algorithm", "files" ], "properties": { "schema": { "const": "getbible-hashes-v1" }, "algorithm": { "const": "sha256" }, "files": { "type": "object", "additionalProperties": { "type": "string", "pattern": "^[0-9a-f]{64}$" } } }, "additionalProperties": false } ```
## Authentication contract ```json { "security": [], "securitySchemes": {} } ``` See [access and tokens](/tokens/) for public usage and token requests. --- # Dictionaries API Bring definitions, lexicons, and linked study resources into a Bible application. The Dictionaries API serves a catalog of dictionaries converted from approved CrossWire SWORD modules into plain-text JSON. A client can download a small word index for interactive search, retrieve one definition, follow related terms, or take an entire dictionary offline. The API uses stable document addresses. Strong's lexicons connect directly to the tokens in GetBible scripture data: Greek `G3056` resolves to the Greek entry, and Hebrew `H0430` resolves to the Hebrew entry. General dictionaries expose their own path-safe entry identifiers through an index. ## Start here ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/dictionaries.json' ``` Choose a dictionary from the response, check its metadata for language, provenance, license, and download size, then read its index or fetch an entry directly. | Resource | Link | | --- | --- | | Complete v1 guide | [Dictionaries v1](/api/dictionaries/v1/) | | Current catalog | [dictionaries.json](https://dictionaries.getbible.net/v1/dictionaries.json) | | API service | [dictionaries.getbible.net](https://dictionaries.getbible.net/) | | Upstream v1 documentation | [Version 1 documentation](https://dictionaries.getbible.net/v1/) | | OpenAPI specification | [OpenAPI JSON](https://dictionaries.getbible.net/v1/openapi.json) | | Builder source | [getbible/v1_study_builder](https://github.com/getbible/v1_study_builder) | | Generated data | [getbible/dictionaries](https://github.com/getbible/dictionaries) | | Public support | [GetBible support](https://git.vdm.dev/getBible/support) | ## What you can build - A word-study panel that opens a Strong's definition from scripture. - A dictionary picker organized by language and source. - Fast local search using each dictionary's normalized word index. - A study graph using forward links, backlinks, and scripture references. - An offline reader using a whole-dictionary download and the integrity manifest. Dictionary search is performed by your application over `index.json`; this static API does not have a server-side search query endpoint. For searching scripture text, use the [Search API](/api/search/). ## A connected study experience Each definition contains plain text and may include `see_also`, `backlinks`, and `references`. The first two link to other entries in the same dictionary. Scripture references provide numeric GetBible coordinates and a canonical reference string that the [Query API](/api/query/) understands. Commentary material is available independently from the [Commentaries API](/api/commentaries/). The Dictionaries API has its own v1 schema. Its version does not have to match the Bible API version selected by an application. ## Access and reuse The published documents are public GET resources. No application token or request body is defined by the generated API contract. Each module publishes its source and license in its metadata: retain those details when redistributing a resource. Version 1 documents contain no HTML markup. Preserve paragraphs when displaying definitions, and render text through a text-safe interface such as `textContent`. Content, catalogs, JSON Schemas, build provenance, and SHA-256 hashes are generated together by the study builder. Read the [complete v1 guide](/api/dictionaries/v1/) for every endpoint, field model, Strong's key rules, search examples, integrity verification, and error behavior. --- # Dictionaries API v1 Use `https://dictionaries.getbible.net/v1/` as the document root. Every route is a GET of a static JSON file. There are no request bodies, query parameters, or content-negotiated variants. The contract defines no authentication scheme. [API overview](/api/dictionaries/) · [Service documentation](https://dictionaries.getbible.net/v1/) · [OpenAPI JSON](https://dictionaries.getbible.net/v1/openapi.json) · [Builder source](https://github.com/getbible/v1_study_builder) · [Public support](https://git.vdm.dev/getBible/support) ## Quick start Fetch the catalog, inspect a dictionary, then retrieve one word: ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/dictionaries.json' curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/strongsgreek/metadata.json' curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/strongsgreek/G3056.json' ``` The catalog lists current dictionary identifiers, languages, licenses, entry counts, unique-key counts, Strong's prefixes, and whole-dictionary sizes. Read it at runtime or when refreshing an application cache instead of fixing the current module list in code. ## Find a word A dictionary's `index.json` returns an `entries` array. Each record includes: | Field | Meaning | | --- | --- | | `id` | Exact document identifier to use in the entry URL | | `key` | The dictionary's original display key | | `search` | Accent-insensitive lowercase search term | | `aliases` | Optional alternative spellings or keys | | `occurrence` | Optional position for later definitions of a repeated key | The index is sorted by `search`, which supports in-memory filtering, prefix matching, and binary search. Each result resolves directly to `{dictionary}/{id}.json`. Do not construct the document ID by uppercasing, slugifying, or normalizing a display name. This Bash example uses cURL and jq to fetch the first Easton entry whose normalized key is `kadesh`: ```bash set -euo pipefail dictionary_index="$(curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/easton/index.json')" entry_id="$(jq --raw-output --exit-status \ '[.entries[] | select(.search == "kadesh")][0].id' \ <<< "$dictionary_index")" curl --fail --silent --show-error \ "https://dictionaries.getbible.net/v1/easton/${entry_id}.json" ``` Repeated keys represent distinct definitions. The first definition keeps the base identifier; later definitions use deterministic suffixes such as `--2` and `--3`. Literal keys may already reserve a suffix, so the suffix itself is not a reliable occurrence counter. Use `occurrence` and keep all matching index records when showing multiple definitions. ## Strong's lexicons Strong's entry IDs follow GetBible tokens: | Lexicon | ID rule | Example | | --- | --- | --- | | Greek | `G` plus the unpadded number | `strongsgreek/G3056.json` | | Hebrew | `H0` plus the unpadded number | `strongshebrew/H0430.json` | ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/strongsgreek/G3056.json' curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/strongshebrew/H0430.json' ``` Preserve the published token, particularly the Hebrew prefix. A source module's `key` can have different padding from its public `id`; for example, an entry may have `key: "00430"` and `id: "H0430"`. ## Entry response Required fields are `schema`, `dictionary`, `language`, `id`, `key`, `occurrence`, `aliases`, and `text`. Optional `see_also` and `backlinks` arrays contain `{id, key}` pairs in the same dictionary. Optional `references` contains structured scripture citations. `text` is plain text with preserved line and paragraph breaks. For a browser interface, assign it to `textContent` and use an appropriate whitespace style. Dictionary links and scripture references are separate structured data; they are not HTML hidden inside the definition. The complete dictionary response contains `schema`, `dictionary`, `language`, `name`, and an `entries` array. Each entry is the same document served separately. Its order matches the index. ## Scripture references A reference has required `ref`, `osis`, `book`, and `chapter` fields: | Field | Type | Use | | --- | --- | --- | | `ref` | string | Canonical reference in the module's language | | `osis` | string | OSIS identifier for the reference anchor | | `book` | integer, 1–83 | GetBible book number | | `chapter` | integer, at least 0 | Chapter coordinate | | `verse` | optional integer, at least 0 | Single verse or first covered verse | | `verses` | optional integer array | All covered verses, including the anchor | | `text` | optional string | Citation exactly as it appears in the definition | If `verses` exists, it defines coverage. Otherwise `verse` means one verse. If neither exists, the reference covers the whole chapter. A range crossing chapters is represented by separate chapter references. Use numeric coordinates with the [Bible API](/api/bible/), or pass `ref` to the [Query API](/api/query/). Long topical references can exceed the Query API's reference-length limit; split their verse lists into smaller requests when necessary. The metadata's `references` object records the Bible versification, translation shape, naming translation, and parser tables used during the build. ## Offline downloads and integrity Check `metadata.json.bytes` before requesting a whole dictionary. Downloading the entire resource is useful for offline applications; fetching the index once and entries on demand is a lighter starting point for an online interface. ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/easton.json' \ --output easton.json curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/hashes.json' \ --output dictionary-hashes.json ``` Verify the exact downloaded bytes with jq and GNU `sha256sum`: ```bash set -euo pipefail expected="$(jq --raw-output --exit-status \ '.files["easton.json"]' dictionary-hashes.json)" printf '%s %s\n' "$expected" easton.json | sha256sum --check - ``` The manifest excludes itself and includes every other generated document. Refresh the manifest together with the files you verify. If a publication changes between requests, fetch a fresh manifest and retry the affected download rather than accepting a mismatch. Content is byte-stable while a module remains unchanged. Catalog and build records can change between builds. HTTP cache headers, CORS, rate controls, and hosting errors are deployment behavior; the static document contract does not prescribe them. ## Build provenance and licensing `build.json` identifies the builder, extractor, contract, build time, catalog source, Bible API, and module count. `build-report.json` describes compilation health: `success` means all approved modules built; `partial` can include successful output and failures. Its `retained` list identifies previously verified modules kept after their rebuild failed. Each dictionary's metadata includes the original module, license, copyright details, distribution notes, source page, conversion note, and reference-resolution provenance. Preserve resource-specific attribution and consult these fields when distributing downloaded modules. ## Errors and client behavior A successful document request returns JSON with HTTP 200. An unknown dictionary, missing entry, or path not present in `hashes.json` has no document and is described as HTTP 404. The contract does not define a JSON error envelope. Check the HTTP status before parsing the body as JSON; cURL's `--fail` makes unsuccessful HTTP responses fail the command. An absent optional link array means no such links were published. A missing entry is not an empty definition. Search the index first and follow its exact identifier. ## Import into an API client Import the [OpenAPI 3.1 JSON](https://dictionaries.getbible.net/v1/openapi.json) by URL in an OpenAPI-compatible client such as Postman. The generated description deliberately has no fixed hostname, and its operation paths already start with `/v1`. Set the imported client's server or base URL to `https://dictionaries.getbible.net`, without adding another `/v1`. The response schemas are embedded in the specification. They are also available under `/v1/schema/` for validation. This guide's endpoint and response reference below is generated from that contract. ## Complete endpoint reference All paths below are relative to `https://dictionaries.getbible.net`. Every operation returns JSON for HTTP 200 and describes HTTP 404 for a missing document. ### GET `/v1/dictionaries.json` The catalog of every dictionary in the tree. Every dictionary this tree holds, with its counts and sizes, and the path template of each of its documents relative to v1/. No parameters. Response model: `dictionary-catalog`. ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/dictionaries.json' ``` ### GET `/v1/build.json` How and when the tree was built. The builder and extractor versions, the build time, the module catalog the modules were selected from and the Bible API the references were resolved against. No parameters. Response model: `build`. ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/build.json' ``` ### GET `/v1/build-report.json` The compilation outcome and module failures. The build status, successfully rebuilt modules, failures with their stage and reason, and previously verified modules retained after a failed rebuild. This snapshot describes compilation; the workflow report also records later publication errors. No parameters. Response model: `build-report`. ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/build-report.json' ``` ### GET `/v1/hashes.json` The SHA-256 of every other document. The integrity manifest of the tree: a digest for every other document, which is also the complete list of the paths the tree contains. No parameters. Response model: `hashes`. ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/hashes.json' ``` ### GET `/v1/openapi.json` This description. The OpenAPI description of the tree, generated with it. No parameters. Response model: `JSON object`. ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/openapi.json' ``` ### GET `/v1/schema/{document}.json` The JSON Schema of one document type. The schemas embedded under components, served beside the data. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `document` | string | Yes | The document type. Allowed values: "dictionary-catalog", "dictionary-metadata", "dictionary-index", "dictionary-entry", "dictionary", "build", "build-report", "hashes". | Response model: `JSON object`. ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/schema/dictionary-entry.json' ``` ### GET `/v1/{dictionary}/metadata.json` One dictionary's provenance, licence, counts and sizes. Where the module came from, under which licence, how many words it holds, how large its whole-dictionary document is, and which Bible its references were resolved against. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `dictionary` | string | Yes | The dictionary's id, as dictionaries.json lists it. Minimum length: 1. | Response model: `dictionary-metadata`. ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/strongsgreek/metadata.json' ``` ### GET `/v1/{dictionary}/index.json` Every word of one dictionary. Every word once, sorted by its accent-insensitive lowercase search term, with the id of the document that holds it. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `dictionary` | string | Yes | The dictionary's id, as dictionaries.json lists it. Minimum length: 1. | Response model: `dictionary-index`. ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/strongsgreek/index.json' ``` ### GET `/v1/{dictionary}/{entry}.json` One word of one dictionary. The definition, the words it links to and from, and the scripture it cites. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `dictionary` | string | Yes | The dictionary's id, as dictionaries.json lists it. Minimum length: 1. | | `entry` | string | Yes | The word's id as index.json lists it: a Strong's token such as G3056 or H0430 in a Strong's lexicon, otherwise a deterministic path-safe id, with --2, --3 and so on for later definitions of a repeated key. Minimum length: 1. | Response model: `dictionary-entry`. ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/strongsgreek/G3056.json' ``` ### GET `/v1/{dictionary}.json` The whole dictionary. Every entry document in index order, each byte-for-byte the document served at its own path. A bulk document: metadata.json states its size. | Parameter | Type | Required | Meaning | | --- | --- | --- | --- | | `dictionary` | string | Yes | The dictionary's id, as dictionaries.json lists it. Minimum length: 1. | Response model: `dictionary`. ```bash curl --fail --silent --show-error \ 'https://dictionaries.getbible.net/v1/strongsgreek.json' ``` ## Complete response field reference The tables preserve the generated OpenAPI field names, types, required fields, and constraints. Nested required fields are required when their containing object is present. Fields marked optional may be omitted. JSON Schemas in the linked specification provide the complete machine-readable contract. ### dictionary-catalog Every dictionary in one v1 tree, with the path template of each of its documents relative to the tree root. The catalog and build.json are the only documents that carry the build time. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-dictionaries-catalog-v1". | | `version` | number | Yes | Constant: 1. | | `generated_at` | string | Yes | Format: date-time. | | `base_url` | string | Yes | Minimum length: 1. | | `metadata_url_template` | string | Yes | Constant: "{dictionary}/metadata.json". | | `index_url_template` | string | Yes | Constant: "{dictionary}/index.json". | | `dictionary_url_template` | string | Yes | Constant: "{dictionary}.json". | | `entry_url_template` | string | Yes | Constant: "{dictionary}/{entry}.json". | | `module_count` | integer | Yes | Minimum: 0. | | `dictionaries` | array | Yes | | | `dictionaries[].id` | string | Yes | Minimum length: 1. | | `dictionaries[].name` | string | Yes | Minimum length: 1. | | `dictionaries[].language` | string | Yes | Minimum length: 2. | | `dictionaries[].license` | string | Yes | | | `dictionaries[].entry_count` | integer | Yes | Minimum: 0. | | `dictionaries[].unique_key_count` | integer | Yes | Minimum: 0. | | `dictionaries[].strong_prefix` | string, null | Yes | Allowed values: "G", "H", null. | | `dictionaries[].bytes` | integer | Yes | Minimum: 0. | ### dictionary-metadata One dictionary's provenance, licence, counts and sizes. bytes is the size of the whole-dictionary document. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-dictionary-metadata-v1". | | `id` | string | Yes | Minimum length: 1. | | `module` | string | Yes | The source module's own name. Minimum length: 1. | | `name` | string | Yes | Minimum length: 1. | | `language` | string | Yes | Minimum length: 2. | | `version` | string | Yes | | | `license` | string | Yes | | | `driver` | string | Yes | | | `source_type` | string | Yes | | | `entry_count` | integer | Yes | Minimum: 0. | | `unique_key_count` | integer | Yes | Minimum: 0. | | `strong_prefix` | string, null | Yes | Allowed values: "G", "H", null. | | `bytes` | integer | Yes | Minimum: 0. | | `index_url` | string | Yes | Constant: "index.json". | | `entry_url_template` | string | Yes | Constant: "{entry}.json". | | `source` | string | Yes | Constant: "CrossWire SWORD". | | `source_module_url` | string | Yes | The module's own page at its source. Minimum length: 1. | | `text_source` | string | Yes | | | `copyright` | string | Yes | | | `copyright_holder` | string | Yes | | | `copyright_contact` | object | Yes | No additional fields. | | `copyright_contact.name` | string | Yes | | | `copyright_contact.email` | string | Yes | | | `copyright_contact.address` | string | Yes | | | `distribution_notes` | string | Yes | | | `about` | string | Yes | | | `conversion_note` | string | Yes | Minimum length: 1. | | `references` | object | Yes | Which Bible the module's scripture references were resolved against: the API, the versification, the translations whose shape decided which chapters and verses exist, the translation whose book names ref uses, and the librarian and alias tables that resolved the spellings. No additional fields. | | `references.api` | string | Yes | Constant: "getbible-v2". | | `references.versification` | string | Yes | | | `references.translations` | array | Yes | | | `references.names` | string, null | Yes | | | `references.language` | string | Yes | | | `references.librarian` | array | Yes | | | `references.aliases` | array | Yes | | ### dictionary-index Every word in one dictionary, sorted by the accent-insensitive lowercase search term. One fetch is enough to search a dictionary in any direction; the word itself is then at entry_url_template with the record's id. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-dictionary-index-v1". | | `dictionary` | string | Yes | Minimum length: 1. | | `language` | string | Yes | Minimum length: 2. | | `name` | string | Yes | Minimum length: 1. | | `entry_url_template` | string | Yes | Constant: "{entry}.json". | | `entry_count` | integer | Yes | Minimum: 0. | | `unique_key_count` | integer | Yes | Minimum: 0. | | `entries` | array | Yes | | | `entries[].id` | string | Yes | Minimum length: 1. | | `entries[].key` | string | Yes | Minimum length: 1. | | `entries[].search` | string | Yes | Minimum length: 1. | | `entries[].aliases` | array | No | Minimum items: 1. | | `entries[].occurrence` | integer | No | Minimum: 2. | ### dictionary-entry One word of one dictionary. see_also lists the words this entry points at; backlinks lists the words that point back. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-dictionary-entry-v1". | | `dictionary` | string | Yes | Minimum length: 1. | | `language` | string | Yes | Minimum length: 2. | | `id` | string | Yes | Minimum length: 1. | | `key` | string | Yes | Minimum length: 1. | | `occurrence` | integer | Yes | Minimum: 1. | | `aliases` | array | Yes | Minimum items: 1. | | `text` | string | Yes | | | `see_also` | links | No | See dictionary-entry/$defs/links. | | `backlinks` | links | No | See dictionary-entry/$defs/links. | | `references` | array | No | | | `references[].text` | string | No | Minimum length: 1. | | `references[].ref` | string | Yes | Minimum length: 1. | | `references[].osis` | string | Yes | Minimum length: 1. | | `references[].book` | integer | Yes | Minimum: 1. Maximum: 83. | | `references[].chapter` | integer | Yes | Minimum: 0. | | `references[].verse` | integer | No | Minimum: 0. | | `references[].verses` | array | No | Every verse this reference covers, including verse. Absent when it covers only verse. Minimum items: 2. Items are unique. | #### dictionary-entry: links | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `id` | string | Yes | Minimum length: 1. | | `key` | string | Yes | Minimum length: 1. | ### dictionary One complete dictionary in index order. Each member of entries is byte-for-byte the document served at {dictionary}/{entry}.json. This is a bulk document for offline clients; metadata.json publishes its size in bytes. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-dictionary-v1". | | `dictionary` | string | Yes | Minimum length: 1. | | `language` | string | Yes | Minimum length: 2. | | `name` | string | Yes | Minimum length: 1. | | `entries` | array | Yes | | | `entries[]` | dictionary-entry | — | See dictionary-entry. | ### build How and when one v1 tree was built: the builder and extractor, the catalog the modules were selected from and the Bible API the references were resolved against. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-build-v1". | | `builder` | string | Yes | Constant: "v1_study_builder". | | `builder_version` | string | Yes | Minimum length: 1. | | `extractor` | string | Yes | Constant: "getbiblesword". | | `extractor_version` | string | Yes | Minimum length: 1. | | `extractor_contract` | string | Yes | Minimum length: 1. | | `api_version` | number | Yes | Constant: 1. | | `resource` | enum | Yes | Allowed values: "commentaries", "dictionaries". | | `generated_at` | string | Yes | Format: date-time. | | `catalog_url` | string | Yes | Minimum length: 1. | | `bible_api` | string | Yes | Minimum length: 1. | | `module_count` | integer | Yes | Minimum: 0. | ### build-report Compilation status and actionable diagnostics for one build. A published snapshot is captured before repository publication; the workflow report is updated with later publication errors. Successfully rebuilt modules and retained previous modules are listed separately. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-build-report-v1". | | `status` | enum | Yes | Running is an in-progress checkpoint. Success means all approved modules built; partial means usable output exists with reported failures. Failed means the run could not complete safely. Publication failures are recorded in the workflow report. Allowed values: "running", "success", "partial", "failed". | | `started_at` | string | Yes | Format: date-time. | | `completed_at` | string, null | Yes | Format: date-time. | | `requested_resource` | enum | Yes | Allowed values: "all", "commentaries", "dictionaries". | | `catalog_url` | string | Yes | Minimum length: 1. | | `built` | object | Yes | No additional fields. | | `built.commentaries` | array | Yes | | | `built.dictionaries` | array | Yes | | | `skipped` | array | Yes | | | `skipped[]` | moduleIssue | — | See build-report/$defs/moduleIssue. | | `failed` | array | Yes | | | `failed[]` | moduleFailure | — | See build-report/$defs/moduleFailure. | | `retained` | array | Yes | Failed modules whose prior verified documents remain in the published tree. | | `retained[]` | moduleIssue | — | See build-report/$defs/moduleIssue. | | `errors` | array | Yes | | | `errors[].stage` | string | Yes | Minimum length: 1. | | `errors[].error_type` | string | Yes | Minimum length: 1. | | `errors[].reason` | string | Yes | | | `errors[].resource` | enum | No | Allowed values: "commentaries", "dictionaries". | | `diagnostics` | object | Yes | | | `diagnostics.{key}` | array | — | | | `storage` | object | Yes | | | `storage.{key}` | object | — | | | `commits` | object | Yes | | | `commits.{key}` | string, null | — | | #### build-report: moduleIssue | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `resource` | enum | Yes | Allowed values: "commentaries", "dictionaries". | | `module` | string | Yes | Minimum length: 1. | | `reason` | string | Yes | | #### build-report: moduleFailure | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `resource` | enum | Yes | Allowed values: "commentaries", "dictionaries". | | `module` | string | Yes | Minimum length: 1. | | `reason` | string | Yes | | | `stage` | string | Yes | Minimum length: 1. | | `error_type` | string | Yes | Minimum length: 1. | ### hashes The SHA-256 of every other document in one v1 tree, keyed by path relative to the tree root; also the complete list of the paths the tree contains. | Field | Type | Required | Meaning and constraints | | --- | --- | --- | --- | | `schema` | string | Yes | Constant: "getbible-hashes-v1". | | `algorithm` | string | Yes | Constant: "sha256". | | `files` | object | Yes | | | `files.{key}` | string | — | Pattern: ^[0-9a-f]{64}$. | ## Sources - [Published dictionaries OpenAPI specification](https://dictionaries.getbible.net/v1/openapi.json) - [Generated dictionaries data repository](https://github.com/getbible/dictionaries) - [Study builder contracts and implementation guide](https://github.com/getbible/v1_study_builder) ## Complete contract reference Open the [complete endpoint and schema reference](/api/dictionaries/v1/reference/) for every operation, parameter, response and component model in the published OpenAPI contract. --- # Dictionaries API v1: endpoint and schema reference This reference is generated from the checked-in [OpenAPI contract](https://dictionaries.getbible.net/v1/openapi.json). Return to the [integration guide](/api/dictionaries/v1/) for workflows and ready-to-run examples. Resolved request server: `https://dictionaries.getbible.net`. ## GET /v1/dictionaries.json The catalog of every dictionary in the tree Every dictionary this tree holds, with its counts and sizes, and the path template of each of its documents relative to v1/. Operation ID: `listDictionaries`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The catalog of every dictionary in the tree | application/json | #/components/schemas/dictionary-catalog | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The catalog of every dictionary in the tree", "description": "Every dictionary this tree holds, with its counts and sizes, and the path template of each of its documents relative to v1/.", "operationId": "listDictionaries", "responses": { "200": { "description": "The catalog of every dictionary in the tree", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/dictionary-catalog" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } }, "parameters": [] } ```
## GET /v1/build.json How and when the tree was built The builder and extractor versions, the build time, the module catalog the modules were selected from and the Bible API the references were resolved against. Operation ID: `getBuild`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | How and when the tree was built | application/json | #/components/schemas/build | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "How and when the tree was built", "description": "The builder and extractor versions, the build time, the module catalog the modules were selected from and the Bible API the references were resolved against.", "operationId": "getBuild", "responses": { "200": { "description": "How and when the tree was built", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/build" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } }, "parameters": [] } ```
## GET /v1/build-report.json The compilation outcome and module failures The build status, successfully rebuilt modules, failures with their stage and reason, and previously verified modules retained after a failed rebuild. This snapshot describes compilation; the workflow report also records later publication errors. Operation ID: `getBuildReport`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The compilation outcome and module failures | application/json | #/components/schemas/build-report | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The compilation outcome and module failures", "description": "The build status, successfully rebuilt modules, failures with their stage and reason, and previously verified modules retained after a failed rebuild. This snapshot describes compilation; the workflow report also records later publication errors.", "operationId": "getBuildReport", "responses": { "200": { "description": "The compilation outcome and module failures", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/build-report" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } }, "parameters": [] } ```
## GET /v1/hashes.json The SHA-256 of every other document The integrity manifest of the tree: a digest for every other document, which is also the complete list of the paths the tree contains. Operation ID: `getHashes`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The SHA-256 of every other document | application/json | #/components/schemas/hashes | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The SHA-256 of every other document", "description": "The integrity manifest of the tree: a digest for every other document, which is also the complete list of the paths the tree contains.", "operationId": "getHashes", "responses": { "200": { "description": "The SHA-256 of every other document", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/hashes" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } }, "parameters": [] } ```
## GET /v1/openapi.json This description The OpenAPI description of the tree, generated with it. Operation ID: `getOpenApi`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | This description | application/json | object | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "This description", "description": "The OpenAPI description of the tree, generated with it.", "operationId": "getOpenApi", "responses": { "200": { "description": "This description", "content": { "application/json": { "schema": { "type": "object" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } }, "parameters": [] } ```
## GET /v1/schema/{document}.json The JSON Schema of one document type The schemas embedded under components, served beside the data. Operation ID: `getSchema`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `document` | path | Yes | string | dictionary-catalog | The document type. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The JSON Schema of one document type | application/json | object | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "tree" ], "summary": "The JSON Schema of one document type", "description": "The schemas embedded under components, served beside the data.", "operationId": "getSchema", "parameters": [ { "name": "document", "in": "path", "required": true, "description": "The document type.", "schema": { "type": "string", "enum": [ "dictionary-catalog", "dictionary-metadata", "dictionary-index", "dictionary-entry", "dictionary", "build", "build-report", "hashes" ] } } ], "responses": { "200": { "description": "The JSON Schema of one document type", "content": { "application/json": { "schema": { "type": "object" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } } } ```
## GET /v1/{dictionary}/metadata.json One dictionary's provenance, licence, counts and sizes Where the module came from, under which licence, how many words it holds, how large its whole-dictionary document is, and which Bible its references were resolved against. Operation ID: `getDictionaryMetadata`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `dictionary` | path | Yes | string | strongsgreek | The dictionary's id, as dictionaries.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | One dictionary's provenance, licence, counts and sizes | application/json | #/components/schemas/dictionary-metadata | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "dictionary" ], "summary": "One dictionary's provenance, licence, counts and sizes", "description": "Where the module came from, under which licence, how many words it holds, how large its whole-dictionary document is, and which Bible its references were resolved against.", "operationId": "getDictionaryMetadata", "parameters": [ { "name": "dictionary", "in": "path", "required": true, "description": "The dictionary's id, as dictionaries.json lists it.", "schema": { "type": "string", "minLength": 1, "enum": [ "abbottsmith", "abbottsmithstrongs", "amtract", "bdbglosses_strongs", "cawdrey", "cbc", "daily", "dodson", "easton", "eusebian_num", "hitchcock", "isbe", "klven_iklingon", "klviklingon_en", "nave", "oshm", "saoa", "sme", "smith", "strongsgreek", "strongshebrew", "swe1917of", "tcr", "torrey", "viestrongsgreek", "webster1806", "webster1913" ] } } ], "responses": { "200": { "description": "One dictionary's provenance, licence, counts and sizes", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/dictionary-metadata" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } } } ```
## GET /v1/{dictionary}/index.json Every word of one dictionary Every word once, sorted by its accent-insensitive lowercase search term, with the id of the document that holds it. Operation ID: `getDictionaryIndex`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `dictionary` | path | Yes | string | strongsgreek | The dictionary's id, as dictionaries.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Every word of one dictionary | application/json | #/components/schemas/dictionary-index | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "dictionary" ], "summary": "Every word of one dictionary", "description": "Every word once, sorted by its accent-insensitive lowercase search term, with the id of the document that holds it.", "operationId": "getDictionaryIndex", "parameters": [ { "name": "dictionary", "in": "path", "required": true, "description": "The dictionary's id, as dictionaries.json lists it.", "schema": { "type": "string", "minLength": 1, "enum": [ "abbottsmith", "abbottsmithstrongs", "amtract", "bdbglosses_strongs", "cawdrey", "cbc", "daily", "dodson", "easton", "eusebian_num", "hitchcock", "isbe", "klven_iklingon", "klviklingon_en", "nave", "oshm", "saoa", "sme", "smith", "strongsgreek", "strongshebrew", "swe1917of", "tcr", "torrey", "viestrongsgreek", "webster1806", "webster1913" ] } } ], "responses": { "200": { "description": "Every word of one dictionary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/dictionary-index" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } } } ```
## GET /v1/{dictionary}/{entry}.json One word of one dictionary The definition, the words it links to and from, and the scripture it cites. Operation ID: `getDictionaryEntry`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `dictionary` | path | Yes | string | strongsgreek | The dictionary's id, as dictionaries.json lists it. | | `entry` | path | Yes | string | G3056 | The word's id as index.json lists it: a Strong's token such as G3056 or H0430 in a Strong's lexicon, otherwise a deterministic path-safe id, with --2, --3 and so on for later definitions of a repeated key. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | One word of one dictionary | application/json | #/components/schemas/dictionary-entry | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "dictionary" ], "summary": "One word of one dictionary", "description": "The definition, the words it links to and from, and the scripture it cites.", "operationId": "getDictionaryEntry", "parameters": [ { "name": "dictionary", "in": "path", "required": true, "description": "The dictionary's id, as dictionaries.json lists it.", "schema": { "type": "string", "minLength": 1, "enum": [ "abbottsmith", "abbottsmithstrongs", "amtract", "bdbglosses_strongs", "cawdrey", "cbc", "daily", "dodson", "easton", "eusebian_num", "hitchcock", "isbe", "klven_iklingon", "klviklingon_en", "nave", "oshm", "saoa", "sme", "smith", "strongsgreek", "strongshebrew", "swe1917of", "tcr", "torrey", "viestrongsgreek", "webster1806", "webster1913" ] } }, { "name": "entry", "in": "path", "required": true, "description": "The word's id as index.json lists it: a Strong's token such as G3056 or H0430 in a Strong's lexicon, otherwise a deterministic path-safe id, with --2, --3 and so on for later definitions of a repeated key.", "schema": { "type": "string", "minLength": 1 } } ], "responses": { "200": { "description": "One word of one dictionary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/dictionary-entry" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } } } ```
## GET /v1/{dictionary}.json The whole dictionary Every entry document in index order, each byte-for-byte the document served at its own path. A bulk document: metadata.json states its size. Operation ID: `getDictionary`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `dictionary` | path | Yes | string | strongsgreek | The dictionary's id, as dictionaries.json lists it. | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | The whole dictionary | application/json | #/components/schemas/dictionary | | 404 | No such document. The tree is static: a path that hashes.json does not list does not exist. | — | See contract |
Complete operation contract ```json { "tags": [ "dictionary" ], "summary": "The whole dictionary", "description": "Every entry document in index order, each byte-for-byte the document served at its own path. A bulk document: metadata.json states its size.", "operationId": "getDictionary", "parameters": [ { "name": "dictionary", "in": "path", "required": true, "description": "The dictionary's id, as dictionaries.json lists it.", "schema": { "type": "string", "minLength": 1, "enum": [ "abbottsmith", "abbottsmithstrongs", "amtract", "bdbglosses_strongs", "cawdrey", "cbc", "daily", "dodson", "easton", "eusebian_num", "hitchcock", "isbe", "klven_iklingon", "klviklingon_en", "nave", "oshm", "saoa", "sme", "smith", "strongsgreek", "strongshebrew", "swe1917of", "tcr", "torrey", "viestrongsgreek", "webster1806", "webster1913" ] } } ], "responses": { "200": { "description": "The whole dictionary", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/dictionary" } } } }, "404": { "description": "No such document. The tree is static: a path that hashes.json does not list does not exist." } } } ```
## Component schemas Types, required properties, nested objects, constraints and examples below are copied directly from the contract. A property omitted from a schema’s `required` array is optional, even when examples include it. ### dictionary-catalog Every dictionary in one v1 tree, with the path template of each of its documents relative to the tree root. The catalog and build.json are the only documents that carry the build time.
View full dictionary-catalog schema ```json { "title": "GetBible Dictionary Catalog v1", "description": "Every dictionary in one v1 tree, with the path template of each of its documents relative to the tree root. The catalog and build.json are the only documents that carry the build time.", "type": "object", "required": [ "schema", "version", "generated_at", "base_url", "metadata_url_template", "index_url_template", "dictionary_url_template", "entry_url_template", "module_count", "dictionaries" ], "properties": { "schema": { "const": "getbible-dictionaries-catalog-v1" }, "version": { "const": 1 }, "generated_at": { "type": "string", "format": "date-time" }, "base_url": { "type": "string", "minLength": 1 }, "metadata_url_template": { "const": "{dictionary}/metadata.json" }, "index_url_template": { "const": "{dictionary}/index.json" }, "dictionary_url_template": { "const": "{dictionary}.json" }, "entry_url_template": { "const": "{dictionary}/{entry}.json" }, "module_count": { "type": "integer", "minimum": 0 }, "dictionaries": { "type": "array", "items": { "type": "object", "description": "One dictionary: its id is the first path segment of all of its documents, strong_prefix is G or H for a Strong's lexicon and null otherwise, and bytes is the size of its whole-dictionary document.", "required": [ "id", "name", "language", "license", "entry_count", "unique_key_count", "strong_prefix", "bytes" ], "properties": { "id": { "type": "string", "minLength": 1 }, "name": { "type": "string", "minLength": 1 }, "language": { "type": "string", "minLength": 2 }, "license": { "type": "string" }, "entry_count": { "type": "integer", "minimum": 0 }, "unique_key_count": { "type": "integer", "minimum": 0 }, "strong_prefix": { "type": [ "string", "null" ], "enum": [ "G", "H", null ] }, "bytes": { "type": "integer", "minimum": 0 } }, "additionalProperties": false } } }, "additionalProperties": false } ```
### dictionary-metadata One dictionary's provenance, licence, counts and sizes. bytes is the size of the whole-dictionary document.
View full dictionary-metadata schema ```json { "title": "GetBible Dictionary Metadata v1", "description": "One dictionary's provenance, licence, counts and sizes. bytes is the size of the whole-dictionary document.", "type": "object", "required": [ "schema", "id", "module", "name", "language", "version", "license", "driver", "source_type", "entry_count", "unique_key_count", "strong_prefix", "bytes", "index_url", "entry_url_template", "source", "source_module_url", "text_source", "copyright", "copyright_holder", "copyright_contact", "distribution_notes", "about", "conversion_note", "references" ], "properties": { "schema": { "const": "getbible-dictionary-metadata-v1" }, "id": { "type": "string", "minLength": 1 }, "module": { "type": "string", "minLength": 1, "description": "The source module's own name." }, "name": { "type": "string", "minLength": 1 }, "language": { "type": "string", "minLength": 2 }, "version": { "type": "string" }, "license": { "type": "string" }, "driver": { "type": "string" }, "source_type": { "type": "string" }, "entry_count": { "type": "integer", "minimum": 0 }, "unique_key_count": { "type": "integer", "minimum": 0 }, "strong_prefix": { "type": [ "string", "null" ], "enum": [ "G", "H", null ] }, "bytes": { "type": "integer", "minimum": 0 }, "index_url": { "const": "index.json" }, "entry_url_template": { "const": "{entry}.json" }, "source": { "const": "CrossWire SWORD" }, "source_module_url": { "type": "string", "minLength": 1, "description": "The module's own page at its source." }, "text_source": { "type": "string" }, "copyright": { "type": "string" }, "copyright_holder": { "type": "string" }, "copyright_contact": { "type": "object", "required": [ "name", "email", "address" ], "properties": { "name": { "type": "string" }, "email": { "type": "string" }, "address": { "type": "string" } }, "additionalProperties": false }, "distribution_notes": { "type": "string" }, "about": { "type": "string" }, "conversion_note": { "type": "string", "minLength": 1 }, "references": { "type": "object", "description": "Which Bible the module's scripture references were resolved against: the API, the versification, the translations whose shape decided which chapters and verses exist, the translation whose book names ref uses, and the librarian and alias tables that resolved the spellings.", "required": [ "api", "versification", "translations", "names", "language", "librarian", "aliases" ], "properties": { "api": { "const": "getbible-v2" }, "versification": { "type": "string" }, "translations": { "type": "array", "items": { "type": "string", "minLength": 1 } }, "names": { "type": [ "string", "null" ] }, "language": { "type": "string" }, "librarian": { "type": "array", "items": { "type": "string", "minLength": 1 } }, "aliases": { "type": "array", "items": { "type": "string", "minLength": 1 } } }, "additionalProperties": false } }, "additionalProperties": false } ```
### dictionary-index Every word in one dictionary, sorted by the accent-insensitive lowercase search term. One fetch is enough to search a dictionary in any direction; the word itself is then at entry_url_template with the record's id.
View full dictionary-index schema ```json { "title": "GetBible Dictionary Index v1", "description": "Every word in one dictionary, sorted by the accent-insensitive lowercase search term. One fetch is enough to search a dictionary in any direction; the word itself is then at entry_url_template with the record's id.", "type": "object", "required": [ "schema", "dictionary", "language", "name", "entry_url_template", "entry_count", "unique_key_count", "entries" ], "properties": { "schema": { "const": "getbible-dictionary-index-v1" }, "dictionary": { "type": "string", "minLength": 1 }, "language": { "type": "string", "minLength": 2 }, "name": { "type": "string", "minLength": 1 }, "entry_url_template": { "const": "{entry}.json" }, "entry_count": { "type": "integer", "minimum": 0 }, "unique_key_count": { "type": "integer", "minimum": 0 }, "entries": { "type": "array", "items": { "type": "object", "required": [ "id", "key", "search" ], "properties": { "id": { "type": "string", "minLength": 1 }, "key": { "type": "string", "minLength": 1 }, "search": { "type": "string", "minLength": 1 }, "aliases": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, "occurrence": { "type": "integer", "minimum": 2 } }, "additionalProperties": false } } }, "additionalProperties": false } ```
### dictionary-entry One word of one dictionary. see_also lists the words this entry points at; backlinks lists the words that point back.
View full dictionary-entry schema ```json { "title": "GetBible Dictionary Entry v1", "description": "One word of one dictionary. see_also lists the words this entry points at; backlinks lists the words that point back.", "type": "object", "required": [ "schema", "dictionary", "language", "id", "key", "occurrence", "aliases", "text" ], "properties": { "schema": { "const": "getbible-dictionary-entry-v1" }, "dictionary": { "type": "string", "minLength": 1 }, "language": { "type": "string", "minLength": 2 }, "id": { "type": "string", "minLength": 1 }, "key": { "type": "string", "minLength": 1 }, "occurrence": { "type": "integer", "minimum": 1 }, "aliases": { "type": "array", "items": { "type": "string" }, "minItems": 1 }, "text": { "type": "string" }, "see_also": { "$ref": "#/components/schemas/dictionary-entry/$defs/links" }, "backlinks": { "$ref": "#/components/schemas/dictionary-entry/$defs/links" }, "references": { "type": "array", "items": { "type": "object", "description": "One scripture reference, resolved against the GetBible Bible API. book, chapter, and verse are Bible API coordinates; verses lists every verse covered when there is more than one, and an item without verse covers the whole chapter. ref is the same reference written canonically, in the book name the module's language uses, in the form the Query API accepts. text is present when the citation was located in the entry text: the citation exactly as the text spells it.", "required": [ "ref", "osis", "book", "chapter" ], "properties": { "text": { "type": "string", "minLength": 1 }, "ref": { "type": "string", "minLength": 1 }, "osis": { "type": "string", "minLength": 1 }, "book": { "type": "integer", "minimum": 1, "maximum": 83 }, "chapter": { "type": "integer", "minimum": 0 }, "verse": { "type": "integer", "minimum": 0 }, "verses": { "type": "array", "description": "Every verse this reference covers, including verse. Absent when it covers only verse.", "items": { "type": "integer", "minimum": 0 }, "minItems": 2, "uniqueItems": true } }, "additionalProperties": false } } }, "additionalProperties": false, "$defs": { "links": { "type": "array", "items": { "type": "object", "required": [ "id", "key" ], "properties": { "id": { "type": "string", "minLength": 1 }, "key": { "type": "string", "minLength": 1 } }, "additionalProperties": false } } } } ```
### dictionary One complete dictionary in index order. Each member of entries is byte-for-byte the document served at {dictionary}/{entry}.json. This is a bulk document for offline clients; metadata.json publishes its size in bytes.
View full dictionary schema ```json { "title": "GetBible Dictionary v1", "description": "One complete dictionary in index order. Each member of entries is byte-for-byte the document served at {dictionary}/{entry}.json. This is a bulk document for offline clients; metadata.json publishes its size in bytes.", "type": "object", "required": [ "schema", "dictionary", "language", "name", "entries" ], "properties": { "schema": { "const": "getbible-dictionary-v1" }, "dictionary": { "type": "string", "minLength": 1 }, "language": { "type": "string", "minLength": 2 }, "name": { "type": "string", "minLength": 1 }, "entries": { "type": "array", "items": { "$ref": "#/components/schemas/dictionary-entry" } } }, "additionalProperties": false } ```
### build How and when one v1 tree was built: the builder and extractor, the catalog the modules were selected from and the Bible API the references were resolved against.
View full build schema ```json { "title": "GetBible Build v1", "description": "How and when one v1 tree was built: the builder and extractor, the catalog the modules were selected from and the Bible API the references were resolved against.", "type": "object", "required": [ "schema", "builder", "builder_version", "extractor", "extractor_version", "extractor_contract", "api_version", "resource", "generated_at", "catalog_url", "bible_api", "module_count" ], "properties": { "schema": { "const": "getbible-build-v1" }, "builder": { "const": "v1_study_builder" }, "builder_version": { "type": "string", "minLength": 1 }, "extractor": { "const": "getbiblesword" }, "extractor_version": { "type": "string", "minLength": 1 }, "extractor_contract": { "type": "string", "minLength": 1 }, "api_version": { "const": 1 }, "resource": { "enum": [ "commentaries", "dictionaries" ] }, "generated_at": { "type": "string", "format": "date-time" }, "catalog_url": { "type": "string", "minLength": 1 }, "bible_api": { "type": "string", "minLength": 1 }, "module_count": { "type": "integer", "minimum": 0 } }, "additionalProperties": false } ```
### build-report Compilation status and actionable diagnostics for one build. A published snapshot is captured before repository publication; the workflow report is updated with later publication errors. Successfully rebuilt modules and retained previous modules are listed separately.
View full build-report schema ```json { "title": "GetBible Build Report v1", "description": "Compilation status and actionable diagnostics for one build. A published snapshot is captured before repository publication; the workflow report is updated with later publication errors. Successfully rebuilt modules and retained previous modules are listed separately.", "type": "object", "required": [ "schema", "status", "started_at", "completed_at", "requested_resource", "catalog_url", "built", "skipped", "failed", "retained", "errors", "diagnostics", "storage", "commits" ], "properties": { "schema": { "const": "getbible-build-report-v1" }, "status": { "enum": [ "running", "success", "partial", "failed" ], "description": "Running is an in-progress checkpoint. Success means all approved modules built; partial means usable output exists with reported failures. Failed means the run could not complete safely. Publication failures are recorded in the workflow report." }, "started_at": { "type": "string", "format": "date-time" }, "completed_at": { "type": [ "string", "null" ], "format": "date-time" }, "requested_resource": { "enum": [ "all", "commentaries", "dictionaries" ] }, "catalog_url": { "type": "string", "minLength": 1 }, "built": { "type": "object", "required": [ "commentaries", "dictionaries" ], "properties": { "commentaries": { "type": "array", "items": { "type": "string" } }, "dictionaries": { "type": "array", "items": { "type": "string" } } }, "additionalProperties": false }, "skipped": { "type": "array", "items": { "$ref": "#/components/schemas/build-report/$defs/moduleIssue" } }, "failed": { "type": "array", "items": { "$ref": "#/components/schemas/build-report/$defs/moduleFailure" } }, "retained": { "type": "array", "description": "Failed modules whose prior verified documents remain in the published tree.", "items": { "$ref": "#/components/schemas/build-report/$defs/moduleIssue" } }, "errors": { "type": "array", "items": { "type": "object", "required": [ "stage", "error_type", "reason" ], "properties": { "stage": { "type": "string", "minLength": 1 }, "error_type": { "type": "string", "minLength": 1 }, "reason": { "type": "string" }, "resource": { "enum": [ "commentaries", "dictionaries" ] } }, "additionalProperties": false } }, "diagnostics": { "type": "object", "additionalProperties": { "type": "array", "items": { "type": "object" } } }, "storage": { "type": "object", "additionalProperties": { "type": "object" } }, "commits": { "type": "object", "additionalProperties": { "type": [ "string", "null" ] } } }, "$defs": { "moduleIssue": { "type": "object", "required": [ "resource", "module", "reason" ], "properties": { "resource": { "enum": [ "commentaries", "dictionaries" ] }, "module": { "type": "string", "minLength": 1 }, "reason": { "type": "string" } }, "additionalProperties": false }, "moduleFailure": { "type": "object", "required": [ "resource", "module", "reason", "stage", "error_type" ], "properties": { "resource": { "enum": [ "commentaries", "dictionaries" ] }, "module": { "type": "string", "minLength": 1 }, "reason": { "type": "string" }, "stage": { "type": "string", "minLength": 1 }, "error_type": { "type": "string", "minLength": 1 } }, "additionalProperties": false } }, "additionalProperties": false } ```
### hashes The SHA-256 of every other document in one v1 tree, keyed by path relative to the tree root; also the complete list of the paths the tree contains.
View full hashes schema ```json { "title": "GetBible Hashes v1", "description": "The SHA-256 of every other document in one v1 tree, keyed by path relative to the tree root; also the complete list of the paths the tree contains.", "type": "object", "required": [ "schema", "algorithm", "files" ], "properties": { "schema": { "const": "getbible-hashes-v1" }, "algorithm": { "const": "sha256" }, "files": { "type": "object", "additionalProperties": { "type": "string", "pattern": "^[0-9a-f]{64}$" } } }, "additionalProperties": false } ```
## Authentication contract ```json { "security": [], "securitySchemes": {} } ``` See [access and tokens](/tokens/) for public usage and token requests. --- Give the Query API a Scripture reference and it returns the selected verses. It accepts familiar names and abbreviations, verse lists, ranges and multiple references in one call. The response groups verses by translation, book and chapter so the same renderer can display a single verse or a selection spanning several books. ## Choose your data version | Version | Endpoint | Guide | | --- | --- | --- | | v2 | `https://query.getbible.net/v2/{translation}/{reference}` | [Query v2](/api/query/v2/) | | v3 | `https://query.getbible.net/v3/{translation}/{reference}` | [Query v3](/api/query/v3/) | Both versions use the same route and grouping contract. Version 3 preserves the selected source verses' optional `paragraph`, `tokens` and `spans`. Static chapter `editorial` is not part of assembled query results. If the application needs complete chapter headings or paragraph ranges, fetch the chapter from the [Bible API](/api/bible/). ## Request one verse ```bash curl --fail-with-body --compressed \ 'https://query.getbible.net/v3/kjv/John3:16' ``` The top-level key is `kjv_43_3`: KJV, book 43, chapter 3. The chapter contains compact translation metadata, `book_nr`, `book_name`, `chapter`, `name`, `ref` and a `verses` array. ## Request several passages ```bash curl --fail-with-body --compressed \ 'https://query.getbible.net/v3/kjv/Genesis%201:1-3;John%203:16,18-21;Romans%208:1-4' ``` Spaces are percent-encoded. Semicolons separate references; commas select verses within a chapter; a hyphen describes a range. Quote URLs in the shell so semicolons are not interpreted as command separators. Application code should encode the entire reference as one URL path segment. ```javascript const reference = 'Genesis 1:1-3;John 3:16'; const url = `https://query.getbible.net/v3/kjv/${encodeURIComponent(reference)}`; const response = await fetch(url); const payload = await response.json(); if (!response.ok) { throw new Error(payload.detail ?? `HTTP ${response.status}`); } for (const chapter of Object.values(payload)) { for (const verse of chapter.verses) { console.log(verse.name, verse.text); } } ``` ## Explicit references and predictable errors A missing reference returns `404 missing_reference`. An unresolvable reference returns a `404` problem document. If one reference in a multi-reference request cannot resolve, the entire request is rejected; the response is not silently reduced to the references that happened to work. Omitting the translation on a valid short reference uses the configured default, KJV on the public service. For example, `/v3/John3:16` redirects to `/v3/kjv/John3:16`. Explicitly supplying an unknown translation returns `404`; it does not substitute KJV. No invalid input is replaced by a default passage. Use an explicit version in production links. Unversioned aliases follow the domain's configured default endpoint, which can change independently of the application. ## Query versus search | Your input | API | | --- | --- | | A chapter or verse reference | Query | | Several known references | Query | | Words, a phrase or search filters | [Search](/api/search/) | | A complete chapter with editorial layout | [Bible](/api/bible/) | | A whole translation for offline use | [Bible](/api/bible/) | Query takes no query parameters and no JSON body. A URL such as `?reference=John3:16` is not the Query API contract. Put the translation and reference in the path. ## Access, caching and support The public service is metered without a token. Application/partner tokens provide exemption from public rate budgets and must be used on their issuing domain. [Request access by email](mailto:getBible@TrueChristian.church) or through the shared [support desk](https://git.vdm.dev/getBible/support). Respect the actual `Cache-Control` response and retain `ETag` for conditional requests. Include the API version, translation and reference in cache keys. If a v2 query result combines chapters, persistent caching needs the hashes of every participating chapter, as described in the [v2 cache contract](https://github.com/getbible/mcp/blob/main/site/v2/cache-policy.md). ## Contracts and upstream documentation | Resource | Link | | --- | --- | | Service overview | [query.getbible.net](https://query.getbible.net/) | | Version discovery | [versions.json](https://query.getbible.net/versions.json) | | v2 service docs and OpenAPI | [Documentation](https://query.getbible.net/v2/) · [OpenAPI JSON](https://query.getbible.net/v2/openapi.json) | | v3 service docs and OpenAPI | [Documentation](https://query.getbible.net/v3/) · [OpenAPI JSON](https://query.getbible.net/v3/openapi.json) | | Runtime response and routing policy | [Runtime endpoints](https://github.com/getbible/api/blob/main/docs/RUNTIME_ENDPOINTS.md) | | Reference grammar and grouping | [Librarian usage](https://github.com/getbible/librarian/blob/master/docs/USAGE.md) | | Compact metadata contract | [Translation metadata](https://github.com/getbible/librarian/blob/master/docs/TRANSLATION_METADATA.md) | Quote the API's `X-Request-ID` when asking [support](https://git.vdm.dev/getBible/support) about a failed request. --- Query v2 resolves Scripture references against the Bible v2 data tree. Send the translation and reference in the path; receive the selected verses grouped by translation, book and chapter. **Data route:** `GET https://query.getbible.net/v2/{translation}/{reference}` [Live documentation](https://query.getbible.net/v2/) · [OpenAPI JSON](https://query.getbible.net/v2/openapi.json) · [Query overview](/api/query/) · [Support](https://git.vdm.dev/getBible/support) ## Quick start ```bash curl --fail-with-body --compressed \ 'https://query.getbible.net/v2/kjv/John3:16' ``` This returns a JSON object with `kjv_43_3` as its chapter key and John 3:16 in that chapter's `verses` array. No authentication is necessary for a public request within the service's anonymous budget. ## Parameters and reference syntax | Input | Location | Meaning | | --- | --- | --- | | API version | Path | `v2`; select it explicitly in production integrations | | `translation` | Path | Translation abbreviation such as `kjv`, resolved case-insensitively | | `reference` | Path | Required nonempty Scripture reference, up to 512 characters in the published contract | Query accepts no URL query parameters. It does not accept a JSON search body. The route is a GET operation; HEAD can retrieve its headers and OPTIONS handles preflight. | Reference | Selection | | --- | --- | | `John3:16` | One verse | | `John 3:16` | The same verse with a space in the book/chapter form | | `Genesis 1:1-3` | An inclusive verse range | | `John 3:16,18-21` | One verse and a second range in the same chapter | | `Psalm 23` | A whole chapter | | `Genesis 1:1-3;John 3:16` | Multiple references separated by semicolons | | `1 John 3:16` | A numbered book name | Book aliases depend on the resolver and selected translation. Use the published book catalogue for names and availability; an alias that parses still must refer to Scripture available in that translation. Chapter and verse numbering follows the source's versification. ```bash # Verse list plus another passage curl --fail-with-body --compressed \ 'https://query.getbible.net/v2/kjv/John%203:16,18-21;Romans%208:1-4' # A complete short chapter curl --fail-with-body --compressed \ 'https://query.getbible.net/v2/kjv/Psalm%2023' ``` Percent-encode spaces as `%20`, quote the whole URL in the shell and encode application input as one path segment. The standard managed query service is configured for at most 8 references and 200 total verses per request; oversized selections return `400 request_limit`. The version's live documentation and error response remain authoritative if deployment settings change. ## Response envelope The top-level object has one entry per selected chapter. Its key format is `{translation}_{book}_{chapter}`, for example `kjv_43_3`. | Chapter member | Type | Description | | --- | --- | --- | | `translation` | String | Translation display name | | `abbreviation` | String | Translation identifier | | `lang` | String | Source language code | | `language` | String | Source language label | | `direction` | String | Source text direction | | `encoding` | String | Source encoding label | | `book_nr` | Integer | GetBible book number | | `book_name` | String | Book display name | | `chapter` | Integer | Chapter number | | `name` | String | Chapter display name | | `ref` | Array of strings | Input references contributing to this group | | `verses` | Array of objects | Ordered selected verses | The six translation metadata fields are copied as available from the validated source; optional omissions and accepted empty values remain unchanged. `name` belongs to the chapter, while the translation name is `translation`. The full translation history, description, distribution terms and source details are available separately from [the v2 catalogue](https://api.getbible.net/v2/translations.json). Every returned verse has `verse`, `name` and `text`; source verses also carry `chapter`. Preserve whole verse objects when storing or forwarding results rather than rebuilding them from a fixed short field list. ### v2 response example The complete response to the single-verse quick start is: ```json { "kjv_43_3": { "translation": "King James Version", "abbreviation": "kjv", "lang": "en", "language": "English", "direction": "LTR", "encoding": "UTF-8", "book_nr": 43, "book_name": "John", "chapter": 3, "name": "John 3", "ref": [ "John3:16" ], "verses": [ { "chapter": 3, "verse": 16, "name": "John 3:16", "text": "For God so loved the world, that he gave his only begotten Son, that whosoever believeth in him should not perish, but have everlasting life." } ] } } ``` For source lexical annotations and paragraph-start metadata, select [Query v3](/api/query/v3/). The v2 route continues to read v2 source data; it does not synthesize v3 metadata. ## Canonical URLs and defaults | Request | Behavior | | --- | --- | | `/v2/kjv/John3:16` | Returns the requested selection | | `/v2/John3:16` | Valid short reference; `301` to `/v2/kjv/John3:16` | | `/John3:16` | Uses the domain's configured default endpoint and translation | | `/aov/John3:16` | Retains `aov`, uses the default endpoint and redirects if the reference resolves | | `/v2/kjv` | `404 missing_reference` | | `/v2/unknowntranslation/John3:16` | `404 translation_not_found` | | Invalid or unavailable reference | `404` problem document | Only an omitted translation gets the configured default, KJV on the public endpoint. A supplied unknown translation does not fall back to KJV. No absent or invalid reference is replaced with Matthew or another passage. One unresolvable reference rejects an entire multiple-reference request. Handle a failed request as a failed selection; do not assume the API returned a partial list. Short forms are resolved before redirecting, so a plausible but unavailable reference does not trigger a redirect to substitute content. ```bash # Follow the valid default-translation redirect curl --fail-with-body --location --compressed \ 'https://query.getbible.net/v2/John3:16' # Inspect the documented error for a missing reference curl --include \ 'https://query.getbible.net/v2/kjv' ``` The documentation page is `/v2/` with its trailing slash. Use its documented URL when linking to the human guide; a scripture route without the required reference is a different request. ## Complete JavaScript example ```javascript async function getScripture(reference, translation = 'kjv') { const url = `https://query.getbible.net/v2/${encodeURIComponent(translation)}/${encodeURIComponent(reference)}`; const response = await fetch(url, { headers: { Accept: 'application/json' } }); const body = await response.json(); if (!response.ok) { const error = new Error(body.detail ?? `GetBible returned HTTP ${response.status}`); error.status = response.status; error.code = body.code; throw error; } return body; } const chapters = await getScripture('Genesis 1:1-3;John 3:16'); for (const chapter of Object.values(chapters)) { for (const verse of chapter.verses) { console.log(verse.name, verse.text); } } ``` This works in a modern browser console or an ES module with `fetch`. Render `verse.text` using text content in a user interface and apply the returned reading direction. ## Access and bearer tokens The public endpoint advertises metered anonymous access. Valid tokens exempt their holders from public rate budgets. Tokens are domain-scoped; request one for `query.getbible.net` through [support](https://git.vdm.dev/getBible/support) or [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). Set the issued value as `GETBIBLE_QUERY_TOKEN` before running this authenticated example: ```bash curl --fail-with-body --compressed \ --header "Authorization: Bearer ${GETBIBLE_QUERY_TOKEN:?Set GETBIBLE_QUERY_TOKEN to your issued token}" \ 'https://query.getbible.net/v2/kjv/John3:16' ``` Never place tokens in URLs or publish them in browser bundles. Documentation, OpenAPI and public health/readiness routes remain accessible without tokens. A token does not bypass reference-count or verse-count validation. ## Caching and freshness Read `Cache-Control` and save the returned `ETag`. On later requests for the identical URL, send `If-None-Match`; a `304` response has no body and means the stored representation can be reused. Actual cache lifetimes are deployment settings, so use response headers instead of a hardcoded number. Namespace application caches by API version, translation, reference and the response contract the application expects. Source hashes and response-format versions solve different invalidation problems. Persistent v2 selections spanning several chapters must retain every participating chapter hash and recheck at least weekly according to the [v2 Scripture cache policy](https://github.com/getbible/mcp/blob/main/site/v2/cache-policy.md). The service allows cross-origin browser requests. Token-only deployments use `private, no-store` for data and bypass shared caches. An authorized request still must pass access checks before receiving a conditional response. ## Error contract Errors use `application/problem+json`. The document has `type`, `title`, `status`, `code`, `detail` and `instance`; temporary responses may add `retry_after` and an HTTP `Retry-After` header. Use `code` for program behavior and `detail` for an explanatory message. | HTTP | Code | Meaning | | --- | --- | --- | | 400 | `parameters_not_accepted` | Remove the URL query string | | 400 | `request_limit` | Reduce the number of references or selected verses | | 401 | `unauthorized` | Check credentials when token-only access applies | | 404 | `missing_reference` | Supply a reference after the translation | | 404 | `invalid_reference` | Reference cannot resolve | | 404 | `not_found` | Requested Scripture or route is unavailable | | 404 | `translation_not_found` | Translation is unknown/unavailable | | 404 | `unknown_version` | Requested API version is not served by this endpoint | | 405 | `method_not_allowed` | Use the documented HTTP method | | 429 | `rate_limited` | Wait for `Retry-After` and reuse cached results | | 503 | `repository_unavailable`, `readiness_failed` | Temporary inability to read Scripture | The OpenAPI contract also covers deployment/proxy failures such as 413, 500, 502 and 504. Handle non-success statuses even when the body comes from an intermediary. Retrying malformed or missing input will not repair it; fix 400/404 requests before trying again. ## Health, OpenAPI and support `GET /healthz` reports liveness. `GET /readyz` verifies that the configured default Scripture can actually be read; a failure returns a 503 problem document with `Retry-After`. The readiness passage is a service probe, never a fallback for user references. ```bash curl --fail-with-body 'https://query.getbible.net/healthz' curl --fail-with-body 'https://query.getbible.net/readyz' curl --fail-with-body --compressed \ 'https://query.getbible.net/v2/openapi.json' \ --output getbible-query-v2-openapi.json ``` Import the OpenAPI URL or downloaded JSON in Postman. The contract includes the host and versioned paths. Use the canonical route to avoid an extra redirect during testing. This guide follows the [live v2 contract](https://query.getbible.net/v2/openapi.json), [service documentation](https://query.getbible.net/v2/), [runtime policy](https://github.com/getbible/api/blob/main/docs/RUNTIME_ENDPOINTS.md), [reference examples](https://github.com/getbible/librarian/blob/master/docs/USAGE.md), and [query limit configuration](https://github.com/getbible/api/blob/main/src/apps/query/getbible_query_api/config.py). Report problems at [GetBible support](https://git.vdm.dev/getBible/support), including the request URL, HTTP status and `X-Request-ID` header. ## Complete contract reference Open the [complete endpoint and schema reference](/api/query/v2/reference/) for every operation, parameter, response and component model in the published OpenAPI contract. --- # Query API v2: endpoint and schema reference This reference is generated from the checked-in [OpenAPI contract](https://query.getbible.net/v2/openapi.json). Return to the [integration guide](/api/query/v2/) for workflows and ready-to-run examples. Resolved request server: `https://query.getbible.net`. ## GET /healthz Liveness Operation ID: `health`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Service is online | application/json | #/components/schemas/Health |
Complete operation contract ```json { "operationId": "health", "responses": { "200": { "content": { "application/json": { "example": { "status": "ok" }, "schema": { "$ref": "#/components/schemas/Health" } } }, "description": "Service is online" } }, "security": [], "summary": "Liveness", "parameters": [] } ```
## GET /readyz Readiness: read the configured probe reference Reads the configured readiness reference Mat7:7 in the default translation. This reference is only a health probe, never a fallback for scripture requests. Operation ID: `readiness`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Scripture is readable | application/json | #/components/schemas/Health | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "readiness", "responses": { "200": { "content": { "application/json": { "example": { "status": "ready" }, "schema": { "$ref": "#/components/schemas/Health" } } }, "description": "Scripture is readable" }, "503": { "$ref": "#/components/responses/Problem" } }, "security": [], "description": "Reads the configured readiness reference Mat7:7 in the default translation. This reference is only a health probe, never a fallback for scripture requests.", "summary": "Readiness: read the configured probe reference", "parameters": [] } ```
## GET /{reference} Short form: reference in the default translation Operation ID: `redirectReference`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `reference` | path | Yes | string | John3:16 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 301 | A valid reference redirects to /v2/kjv/{reference}. Missing or unresolved references return 404. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "redirectReference", "parameters": [ { "in": "path", "name": "reference", "required": true, "schema": { "type": "string" } } ], "responses": { "301": { "description": "A valid reference redirects to /v2/kjv/{reference}. Missing or unresolved references return 404." }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form: reference in the default translation" } ```
## GET /{translation}/{reference} Short form without a version segment Operation ID: `redirectUnversioned`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | — | | `reference` | path | Yes | string | John3:16 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 301 | A valid reference in a known translation redirects to /v2/{translation}/{reference}. Unknown translations and missing or unresolved references return 404. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "redirectUnversioned", "parameters": [ { "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "reference", "required": true, "schema": { "type": "string" } } ], "responses": { "301": { "description": "A valid reference in a known translation redirects to /v2/{translation}/{reference}. Unknown translations and missing or unresolved references return 404.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form without a version segment" } ```
## GET /v2 A scripture reference is required This API request supplies no scripture reference and returns a 404 missing_reference problem document. The public documentation page is at /v2/. Operation ID: `missingReference`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "missingReference", "responses": { "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "description": "This API request supplies no scripture reference and returns a 404 missing_reference problem document. The public documentation page is at /v2/.", "summary": "A scripture reference is required", "parameters": [] } ```
## GET /v2/openapi.json Public API contract Operation ID: `openapi`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Generated OpenAPI 3.1 JSON document. | application/json | object |
Complete operation contract ```json { "operationId": "openapi", "responses": { "200": { "content": { "application/json": { "schema": { "properties": { "info": { "type": "object" }, "openapi": { "type": "string" }, "paths": { "type": "object" } }, "required": [ "openapi", "info", "paths" ], "type": "object" } } }, "description": "Generated OpenAPI 3.1 JSON document." } }, "security": [], "summary": "Public API contract", "parameters": [] } ```
## GET /v2/{translation} Resolve a reference in the default translation; a translation alone returns 404 Operation ID: `redirectTranslation`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 301 | Only when this segment is a valid scripture reference: redirect to /v2/kjv/{reference}. A translation without a reference returns 404 missing_reference; an unresolved reference returns a 404 problem document. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "redirectTranslation", "parameters": [ { "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } } ], "responses": { "301": { "description": "Only when this segment is a valid scripture reference: redirect to /v2/kjv/{reference}. A translation without a reference returns 404 missing_reference; an unresolved reference returns a 404 problem document." }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Resolve a reference in the default translation; a translation alone returns 404" } ```
## GET /v2/{translation}/{reference} Verses for one or more references Every reference must resolve in the requested translation. A missing or unresolved reference returns a 404 problem document, including a mixed list containing an unresolved reference. Unknown translations also return 404. No default verse is substituted. Operation ID: `getScripture`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation, e.g. kjv | | `reference` | path | Yes | string | John3:16 | One or more scripture references separated by ';', e.g. John3:16 or Genesis 1:1-3;Psalm 23 | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Chapter-keyed scripture object | application/json | #/components/schemas/Scripture | | 304 | Not modified (conditional request) | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "getScripture", "description": "Every reference must resolve in the requested translation. A missing or unresolved reference returns a 404 problem document, including a mixed list containing an unresolved reference. Unknown translations also return 404. No default verse is substituted.", "parameters": [ { "description": "Translation abbreviation, e.g. kjv", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "One or more scripture references separated by ';', e.g. John3:16 or Genesis 1:1-3;Psalm 23", "in": "path", "name": "reference", "required": true, "schema": { "maxLength": 512, "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Scripture" } } }, "description": "Chapter-keyed scripture object" }, "304": { "description": "Not modified (conditional request)" }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Verses for one or more references" } ```
## Component schemas Types, required properties, nested objects, constraints and examples below are copied directly from the contract. A property omitted from a schema’s `required` array is optional, even when examples include it. ### Health
View full Health schema ```json { "properties": { "status": { "enum": [ "ok", "ready" ], "type": "string" } }, "required": [ "status" ], "type": "object" } ```
### Problem RFC 9457 problem document.
View full Problem schema ```json { "description": "RFC 9457 problem document.", "properties": { "code": { "type": "string" }, "detail": { "type": "string" }, "instance": { "type": "string" }, "retry_after": { "minimum": 0, "type": "integer" }, "status": { "type": "integer" }, "title": { "type": "string" }, "type": { "format": "uri", "type": "string" } }, "required": [ "type", "title", "status", "code", "detail", "instance" ], "type": "object" } ```
### Scripture One entry per chapter, keyed {translation}_{book}_{chapter}, with compact API translation metadata and selected verses. Verse source fields are retained; static chapter editorial is excluded.
View full Scripture schema ```json { "additionalProperties": { "properties": { "abbreviation": { "type": "string" }, "book_name": { "type": "string" }, "book_nr": { "type": "integer" }, "chapter": { "type": "integer" }, "direction": { "type": "string" }, "encoding": { "type": "string" }, "lang": { "type": "string" }, "language": { "type": "string" }, "name": { "type": "string" }, "ref": { "items": { "type": "string" }, "type": "array" }, "translation": { "type": "string" }, "verses": { "items": { "$ref": "#/components/schemas/Verse" }, "type": "array" } }, "required": [ "book_nr", "chapter", "verses" ], "type": "object" }, "description": "One entry per chapter, keyed {translation}_{book}_{chapter}, with compact API translation metadata and selected verses. Verse source fields are retained; static chapter editorial is excluded.", "type": "object" } ```
### Verse A source verse from the selected v2 data. Core fields are shared by v2 and v3. Optional v3 paragraph, tokens and spans are retained when present, as are other source fields and nested values.
View full Verse schema ```json { "additionalProperties": true, "description": "A source verse from the selected v2 data. Core fields are shared by v2 and v3. Optional v3 paragraph, tokens and spans are retained when present, as are other source fields and nested values.", "properties": { "chapter": { "type": "integer" }, "name": { "type": "string" }, "paragraph": { "description": "V3: true when this verse begins a paragraph; omitted when absent from the source.", "type": "boolean" }, "spans": { "description": "V3 annotations over token and word ranges, when supplied by the source.", "items": { "$ref": "#/components/schemas/VerseSpan" }, "type": "array" }, "text": { "type": "string" }, "tokens": { "description": "V3 word tokens in reading order, when supplied by the source.", "items": { "$ref": "#/components/schemas/VerseToken" }, "type": "array" }, "verse": { "type": "integer" } }, "required": [ "verse", "name", "text" ], "type": "object" } ```
### VerseSpan V3 source annotation. Token positions index the verse tokens array from zero, inclusive. Word positions count display words from one, inclusive; zero means unlocated.
View full VerseSpan schema ```json { "additionalProperties": true, "description": "V3 source annotation. Token positions index the verse tokens array from zero, inclusive. Word positions count display words from one, inclusive; zero means unlocated.", "properties": { "attrs": { "additionalProperties": { "type": "string" }, "type": "object" }, "span": { "type": "string" }, "tag": { "type": "string" }, "token_end": { "minimum": 0, "type": "integer" }, "token_start": { "minimum": 0, "type": "integer" }, "word_end": { "minimum": 0, "type": "integer" }, "word_start": { "minimum": 0, "type": "integer" } }, "required": [ "tag", "span", "token_start", "token_end", "word_start", "word_end" ], "type": "object" } ```
### VerseToken V3 word token. Word positions count whitespace-separated display words from one, inclusive; zero means unlocated. Additional source attributes are retained.
View full VerseToken schema ```json { "additionalProperties": true, "description": "V3 word token. Word positions count whitespace-separated display words from one, inclusive; zero means unlocated. Additional source attributes are retained.", "properties": { "gloss": { "type": "string" }, "lemma": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Lexical identifiers grouped by scheme, such as strong.", "type": "object" }, "morph": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Morphology codes grouped by scheme.", "type": "object" }, "morphSegmented": { "type": "boolean" }, "n": { "type": "string" }, "src": { "items": { "type": [ "integer", "string" ] }, "type": "array" }, "subType": { "type": "string" }, "token": { "type": "string" }, "type": { "type": "string" }, "variant": { "type": "boolean" }, "variantType": { "type": "string" }, "word_end": { "minimum": 0, "type": "integer" }, "word_start": { "minimum": 0, "type": "integer" }, "xlit": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Transliterations grouped by scheme.", "type": "object" } }, "required": [ "token", "word_start", "word_end" ], "type": "object" } ```
## Authentication contract ```json { "security": [], "securitySchemes": { "bearer": { "description": "Required for API data only on token-only domains. Valid tokens retain unrestricted rate access.", "scheme": "bearer", "type": "http" } } } ``` See [access and tokens](/tokens/) for public usage and token requests. --- Query v3 resolves Scripture references against the Bible v3 data tree. Send the translation and reference in the path; receive the selected verses grouped by translation, book and chapter. **Data route:** `GET https://query.getbible.net/v3/{translation}/{reference}` [Live documentation](https://query.getbible.net/v3/) · [OpenAPI JSON](https://query.getbible.net/v3/openapi.json) · [Query overview](/api/query/) · [Support](https://git.vdm.dev/getBible/support) ## Quick start ```bash curl --fail-with-body --compressed \ 'https://query.getbible.net/v3/kjv/John3:16' ``` This returns a JSON object with `kjv_43_3` as its chapter key and John 3:16 in that chapter's `verses` array. No authentication is necessary for a public request within the service's anonymous budget. ## Parameters and reference syntax | Input | Location | Meaning | | --- | --- | --- | | API version | Path | `v3`; select it explicitly in production integrations | | `translation` | Path | Translation abbreviation such as `kjv`, resolved case-insensitively | | `reference` | Path | Required nonempty Scripture reference, up to 512 characters in the published contract | Query accepts no URL query parameters. It does not accept a JSON search body. The route is a GET operation; HEAD can retrieve its headers and OPTIONS handles preflight. | Reference | Selection | | --- | --- | | `John3:16` | One verse | | `John 3:16` | The same verse with a space in the book/chapter form | | `Genesis 1:1-3` | An inclusive verse range | | `John 3:16,18-21` | One verse and a second range in the same chapter | | `Psalm 23` | A whole chapter | | `Genesis 1:1-3;John 3:16` | Multiple references separated by semicolons | | `1 John 3:16` | A numbered book name | Book aliases depend on the resolver and selected translation. Use the published book catalogue for names and availability; an alias that parses still must refer to Scripture available in that translation. Chapter and verse numbering follows the source's versification. ```bash # Verse list plus another passage curl --fail-with-body --compressed \ 'https://query.getbible.net/v3/kjv/John%203:16,18-21;Romans%208:1-4' # A complete short chapter curl --fail-with-body --compressed \ 'https://query.getbible.net/v3/kjv/Psalm%2023' ``` Percent-encode spaces as `%20`, quote the whole URL in the shell and encode application input as one path segment. The standard managed query service is configured for at most 8 references and 200 total verses per request; oversized selections return `400 request_limit`. The version's live documentation and error response remain authoritative if deployment settings change. ## Response envelope The top-level object has one entry per selected chapter. Its key format is `{translation}_{book}_{chapter}`, for example `kjv_43_3`. | Chapter member | Type | Description | | --- | --- | --- | | `translation` | String | Translation display name | | `abbreviation` | String | Translation identifier | | `lang` | String | Source language code | | `language` | String | Source language label | | `direction` | String | Source text direction | | `encoding` | String | Source encoding label | | `book_nr` | Integer | GetBible book number | | `book_name` | String | Book display name | | `chapter` | Integer | Chapter number | | `name` | String | Chapter display name | | `ref` | Array of strings | Input references contributing to this group | | `verses` | Array of objects | Ordered selected verses | The six translation metadata fields are copied as available from the validated source; optional omissions and accepted empty values remain unchanged. `name` belongs to the chapter, while the translation name is `translation`. The full translation history, description, distribution terms and source details are available separately from [the v3 catalogue](https://api.getbible.net/v3/translations.json). Every returned verse has `verse`, `name` and `text`; source verses also carry `chapter`. Preserve whole verse objects when storing or forwarding results rather than rebuilding them from a fixed short field list. ### v3 source metadata Version 3 retains optional `paragraph`, `tokens` and `spans` from the source verse, together with any other source verse fields. A verse without these fields remains without them. Word positions are one-based inclusive display-word positions; token ranges in spans are zero-based inclusive indexes into the verse token array. Do not assume a token equals exactly one displayed word. The live John 3:16 response includes a paragraph-start flag and lexical records. One actual token from that response is: ```json { "token": "the world", "lemma": { "strong": [ "G3588", "G2889" ], "lemma.TR": [ "τον", "κοσμον" ] }, "morph": { "robinson": [ "T-ASM", "N-ASM" ] }, "src": [ 6, 7 ], "word_start": 5, "word_end": 6 } ``` The source chapter's `editorial` array is deliberately omitted from assembled query results. Request [the static chapter](https://api.getbible.net/v3/kjv/43/3.json) when rendering its complete headings and paragraph ranges. See [Bible v3](/api/bible/v3/) for full token, span and editorial semantics. ## Canonical URLs and defaults | Request | Behavior | | --- | --- | | `/v3/kjv/John3:16` | Returns the requested selection | | `/v3/John3:16` | Valid short reference; `301` to `/v3/kjv/John3:16` | | `/John3:16` | Uses the domain's configured default endpoint and translation | | `/aov/John3:16` | Retains `aov`, uses the default endpoint and redirects if the reference resolves | | `/v3/kjv` | `404 missing_reference` | | `/v3/unknowntranslation/John3:16` | `404 translation_not_found` | | Invalid or unavailable reference | `404` problem document | Only an omitted translation gets the configured default, KJV on the public endpoint. A supplied unknown translation does not fall back to KJV. No absent or invalid reference is replaced with Matthew or another passage. One unresolvable reference rejects an entire multiple-reference request. Handle a failed request as a failed selection; do not assume the API returned a partial list. Short forms are resolved before redirecting, so a plausible but unavailable reference does not trigger a redirect to substitute content. ```bash # Follow the valid default-translation redirect curl --fail-with-body --location --compressed \ 'https://query.getbible.net/v3/John3:16' # Inspect the documented error for a missing reference curl --include \ 'https://query.getbible.net/v3/kjv' ``` The documentation page is `/v3/` with its trailing slash. Use its documented URL when linking to the human guide; a scripture route without the required reference is a different request. ## Complete JavaScript example ```javascript async function getScripture(reference, translation = 'kjv') { const url = `https://query.getbible.net/v3/${encodeURIComponent(translation)}/${encodeURIComponent(reference)}`; const response = await fetch(url, { headers: { Accept: 'application/json' } }); const body = await response.json(); if (!response.ok) { const error = new Error(body.detail ?? `GetBible returned HTTP ${response.status}`); error.status = response.status; error.code = body.code; throw error; } return body; } const chapters = await getScripture('Genesis 1:1-3;John 3:16'); for (const chapter of Object.values(chapters)) { for (const verse of chapter.verses) { console.log(verse.name, verse.text); } } ``` This works in a modern browser console or an ES module with `fetch`. Render `verse.text` using text content in a user interface and apply the returned reading direction. ## Access and bearer tokens The public endpoint advertises metered anonymous access. Valid tokens exempt their holders from public rate budgets. Tokens are domain-scoped; request one for `query.getbible.net` through [support](https://git.vdm.dev/getBible/support) or [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). Set the issued value as `GETBIBLE_QUERY_TOKEN` before running this authenticated example: ```bash curl --fail-with-body --compressed \ --header "Authorization: Bearer ${GETBIBLE_QUERY_TOKEN:?Set GETBIBLE_QUERY_TOKEN to your issued token}" \ 'https://query.getbible.net/v3/kjv/John3:16' ``` Never place tokens in URLs or publish them in browser bundles. Documentation, OpenAPI and public health/readiness routes remain accessible without tokens. A token does not bypass reference-count or verse-count validation. ## Caching and freshness Read `Cache-Control` and save the returned `ETag`. On later requests for the identical URL, send `If-None-Match`; a `304` response has no body and means the stored representation can be reused. Actual cache lifetimes are deployment settings, so use response headers instead of a hardcoded number. Namespace application caches by API version, translation, reference and the response contract the application expects. Source hashes and response-format versions solve different invalidation problems. Persistent v2 selections spanning several chapters must retain every participating chapter hash and recheck at least weekly according to the [v2 Scripture cache policy](https://github.com/getbible/mcp/blob/main/site/v2/cache-policy.md). The service allows cross-origin browser requests. Token-only deployments use `private, no-store` for data and bypass shared caches. An authorized request still must pass access checks before receiving a conditional response. ## Error contract Errors use `application/problem+json`. The document has `type`, `title`, `status`, `code`, `detail` and `instance`; temporary responses may add `retry_after` and an HTTP `Retry-After` header. Use `code` for program behavior and `detail` for an explanatory message. | HTTP | Code | Meaning | | --- | --- | --- | | 400 | `parameters_not_accepted` | Remove the URL query string | | 400 | `request_limit` | Reduce the number of references or selected verses | | 401 | `unauthorized` | Check credentials when token-only access applies | | 404 | `missing_reference` | Supply a reference after the translation | | 404 | `invalid_reference` | Reference cannot resolve | | 404 | `not_found` | Requested Scripture or route is unavailable | | 404 | `translation_not_found` | Translation is unknown/unavailable | | 404 | `unknown_version` | Requested API version is not served by this endpoint | | 405 | `method_not_allowed` | Use the documented HTTP method | | 429 | `rate_limited` | Wait for `Retry-After` and reuse cached results | | 503 | `repository_unavailable`, `readiness_failed` | Temporary inability to read Scripture | The OpenAPI contract also covers deployment/proxy failures such as 413, 500, 502 and 504. Handle non-success statuses even when the body comes from an intermediary. Retrying malformed or missing input will not repair it; fix 400/404 requests before trying again. ## Health, OpenAPI and support `GET /healthz` reports liveness. `GET /readyz` verifies that the configured default Scripture can actually be read; a failure returns a 503 problem document with `Retry-After`. The readiness passage is a service probe, never a fallback for user references. ```bash curl --fail-with-body 'https://query.getbible.net/healthz' curl --fail-with-body 'https://query.getbible.net/readyz' curl --fail-with-body --compressed \ 'https://query.getbible.net/v3/openapi.json' \ --output getbible-query-v3-openapi.json ``` Import the OpenAPI URL or downloaded JSON in Postman. The contract includes the host and versioned paths. Use the canonical route to avoid an extra redirect during testing. This guide follows the [live v3 contract](https://query.getbible.net/v3/openapi.json), [service documentation](https://query.getbible.net/v3/), [runtime policy](https://github.com/getbible/api/blob/main/docs/RUNTIME_ENDPOINTS.md), [reference examples](https://github.com/getbible/librarian/blob/master/docs/USAGE.md), and [query limit configuration](https://github.com/getbible/api/blob/main/src/apps/query/getbible_query_api/config.py). Report problems at [GetBible support](https://git.vdm.dev/getBible/support), including the request URL, HTTP status and `X-Request-ID` header. ## Complete contract reference Open the [complete endpoint and schema reference](/api/query/v3/reference/) for every operation, parameter, response and component model in the published OpenAPI contract. --- # Query API v3: endpoint and schema reference This reference is generated from the checked-in [OpenAPI contract](https://query.getbible.net/v3/openapi.json). Return to the [integration guide](/api/query/v3/) for workflows and ready-to-run examples. Resolved request server: `https://query.getbible.net`. ## GET /healthz Liveness Operation ID: `health`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Service is online | application/json | #/components/schemas/Health |
Complete operation contract ```json { "operationId": "health", "responses": { "200": { "content": { "application/json": { "example": { "status": "ok" }, "schema": { "$ref": "#/components/schemas/Health" } } }, "description": "Service is online" } }, "security": [], "summary": "Liveness", "parameters": [] } ```
## GET /readyz Readiness: read the configured probe reference Reads the configured readiness reference Mat7:7 in the default translation. This reference is only a health probe, never a fallback for scripture requests. Operation ID: `readiness`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Scripture is readable | application/json | #/components/schemas/Health | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "readiness", "responses": { "200": { "content": { "application/json": { "example": { "status": "ready" }, "schema": { "$ref": "#/components/schemas/Health" } } }, "description": "Scripture is readable" }, "503": { "$ref": "#/components/responses/Problem" } }, "security": [], "description": "Reads the configured readiness reference Mat7:7 in the default translation. This reference is only a health probe, never a fallback for scripture requests.", "summary": "Readiness: read the configured probe reference", "parameters": [] } ```
## GET /{reference} Short form: reference in the default translation Operation ID: `redirectReference`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `reference` | path | Yes | string | John3:16 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 301 | A valid reference redirects to /v3/kjv/{reference}. Missing or unresolved references return 404. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "redirectReference", "parameters": [ { "in": "path", "name": "reference", "required": true, "schema": { "type": "string" } } ], "responses": { "301": { "description": "A valid reference redirects to /v3/kjv/{reference}. Missing or unresolved references return 404." }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form: reference in the default translation" } ```
## GET /{translation}/{reference} Short form without a version segment Operation ID: `redirectUnversioned`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | — | | `reference` | path | Yes | string | John3:16 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 301 | A valid reference in a known translation redirects to /v3/{translation}/{reference}. Unknown translations and missing or unresolved references return 404. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "redirectUnversioned", "parameters": [ { "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "in": "path", "name": "reference", "required": true, "schema": { "type": "string" } } ], "responses": { "301": { "description": "A valid reference in a known translation redirects to /v3/{translation}/{reference}. Unknown translations and missing or unresolved references return 404.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form without a version segment" } ```
## GET /v3 A scripture reference is required This API request supplies no scripture reference and returns a 404 missing_reference problem document. The public documentation page is at /v3/. Operation ID: `missingReference`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "missingReference", "responses": { "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "description": "This API request supplies no scripture reference and returns a 404 missing_reference problem document. The public documentation page is at /v3/.", "summary": "A scripture reference is required", "parameters": [] } ```
## GET /v3/openapi.json Public API contract Operation ID: `openapi`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Generated OpenAPI 3.1 JSON document. | application/json | object |
Complete operation contract ```json { "operationId": "openapi", "responses": { "200": { "content": { "application/json": { "schema": { "properties": { "info": { "type": "object" }, "openapi": { "type": "string" }, "paths": { "type": "object" } }, "required": [ "openapi", "info", "paths" ], "type": "object" } } }, "description": "Generated OpenAPI 3.1 JSON document." } }, "security": [], "summary": "Public API contract", "parameters": [] } ```
## GET /v3/{translation} Resolve a reference in the default translation; a translation alone returns 404 Operation ID: `redirectTranslation`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 301 | Only when this segment is a valid scripture reference: redirect to /v3/kjv/{reference}. A translation without a reference returns 404 missing_reference; an unresolved reference returns a 404 problem document. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "redirectTranslation", "parameters": [ { "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } } ], "responses": { "301": { "description": "Only when this segment is a valid scripture reference: redirect to /v3/kjv/{reference}. A translation without a reference returns 404 missing_reference; an unresolved reference returns a 404 problem document." }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Resolve a reference in the default translation; a translation alone returns 404" } ```
## GET /v3/{translation}/{reference} Verses for one or more references Every reference must resolve in the requested translation. A missing or unresolved reference returns a 404 problem document, including a mixed list containing an unresolved reference. Unknown translations also return 404. No default verse is substituted. Operation ID: `getScripture`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation, e.g. kjv | | `reference` | path | Yes | string | John3:16 | One or more scripture references separated by ';', e.g. John3:16 or Genesis 1:1-3;Psalm 23 | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Chapter-keyed scripture object | application/json | #/components/schemas/Scripture | | 304 | Not modified (conditional request) | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "getScripture", "description": "Every reference must resolve in the requested translation. A missing or unresolved reference returns a 404 problem document, including a mixed list containing an unresolved reference. Unknown translations also return 404. No default verse is substituted.", "parameters": [ { "description": "Translation abbreviation, e.g. kjv", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "One or more scripture references separated by ';', e.g. John3:16 or Genesis 1:1-3;Psalm 23", "in": "path", "name": "reference", "required": true, "schema": { "maxLength": 512, "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Scripture" } } }, "description": "Chapter-keyed scripture object" }, "304": { "description": "Not modified (conditional request)" }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Verses for one or more references" } ```
## Component schemas Types, required properties, nested objects, constraints and examples below are copied directly from the contract. A property omitted from a schema’s `required` array is optional, even when examples include it. ### Health
View full Health schema ```json { "properties": { "status": { "enum": [ "ok", "ready" ], "type": "string" } }, "required": [ "status" ], "type": "object" } ```
### Problem RFC 9457 problem document.
View full Problem schema ```json { "description": "RFC 9457 problem document.", "properties": { "code": { "type": "string" }, "detail": { "type": "string" }, "instance": { "type": "string" }, "retry_after": { "minimum": 0, "type": "integer" }, "status": { "type": "integer" }, "title": { "type": "string" }, "type": { "format": "uri", "type": "string" } }, "required": [ "type", "title", "status", "code", "detail", "instance" ], "type": "object" } ```
### Scripture One entry per chapter, keyed {translation}_{book}_{chapter}, with compact API translation metadata and selected verses. Verse source fields are retained; static chapter editorial is excluded.
View full Scripture schema ```json { "additionalProperties": { "properties": { "abbreviation": { "type": "string" }, "book_name": { "type": "string" }, "book_nr": { "type": "integer" }, "chapter": { "type": "integer" }, "direction": { "type": "string" }, "encoding": { "type": "string" }, "lang": { "type": "string" }, "language": { "type": "string" }, "name": { "type": "string" }, "ref": { "items": { "type": "string" }, "type": "array" }, "translation": { "type": "string" }, "verses": { "items": { "$ref": "#/components/schemas/Verse" }, "type": "array" } }, "required": [ "book_nr", "chapter", "verses" ], "type": "object" }, "description": "One entry per chapter, keyed {translation}_{book}_{chapter}, with compact API translation metadata and selected verses. Verse source fields are retained; static chapter editorial is excluded.", "type": "object" } ```
### Verse A source verse from the selected v3 data. Core fields are shared by v2 and v3. Optional v3 paragraph, tokens and spans are retained when present, as are other source fields and nested values.
View full Verse schema ```json { "additionalProperties": true, "description": "A source verse from the selected v3 data. Core fields are shared by v2 and v3. Optional v3 paragraph, tokens and spans are retained when present, as are other source fields and nested values.", "properties": { "chapter": { "type": "integer" }, "name": { "type": "string" }, "paragraph": { "description": "V3: true when this verse begins a paragraph; omitted when absent from the source.", "type": "boolean" }, "spans": { "description": "V3 annotations over token and word ranges, when supplied by the source.", "items": { "$ref": "#/components/schemas/VerseSpan" }, "type": "array" }, "text": { "type": "string" }, "tokens": { "description": "V3 word tokens in reading order, when supplied by the source.", "items": { "$ref": "#/components/schemas/VerseToken" }, "type": "array" }, "verse": { "type": "integer" } }, "required": [ "verse", "name", "text" ], "type": "object" } ```
### VerseSpan V3 source annotation. Token positions index the verse tokens array from zero, inclusive. Word positions count display words from one, inclusive; zero means unlocated.
View full VerseSpan schema ```json { "additionalProperties": true, "description": "V3 source annotation. Token positions index the verse tokens array from zero, inclusive. Word positions count display words from one, inclusive; zero means unlocated.", "properties": { "attrs": { "additionalProperties": { "type": "string" }, "type": "object" }, "span": { "type": "string" }, "tag": { "type": "string" }, "token_end": { "minimum": 0, "type": "integer" }, "token_start": { "minimum": 0, "type": "integer" }, "word_end": { "minimum": 0, "type": "integer" }, "word_start": { "minimum": 0, "type": "integer" } }, "required": [ "tag", "span", "token_start", "token_end", "word_start", "word_end" ], "type": "object" } ```
### VerseToken V3 word token. Word positions count whitespace-separated display words from one, inclusive; zero means unlocated. Additional source attributes are retained.
View full VerseToken schema ```json { "additionalProperties": true, "description": "V3 word token. Word positions count whitespace-separated display words from one, inclusive; zero means unlocated. Additional source attributes are retained.", "properties": { "gloss": { "type": "string" }, "lemma": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Lexical identifiers grouped by scheme, such as strong.", "type": "object" }, "morph": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Morphology codes grouped by scheme.", "type": "object" }, "morphSegmented": { "type": "boolean" }, "n": { "type": "string" }, "src": { "items": { "type": [ "integer", "string" ] }, "type": "array" }, "subType": { "type": "string" }, "token": { "type": "string" }, "type": { "type": "string" }, "variant": { "type": "boolean" }, "variantType": { "type": "string" }, "word_end": { "minimum": 0, "type": "integer" }, "word_start": { "minimum": 0, "type": "integer" }, "xlit": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Transliterations grouped by scheme.", "type": "object" } }, "required": [ "token", "word_start", "word_end" ], "type": "object" } ```
## Authentication contract ```json { "security": [], "securitySchemes": { "bearer": { "description": "Required for API data only on token-only domains. Valid tokens retain unrestricted rate access.", "scheme": "bearer", "type": "http" } } } ``` See [access and tokens](/tokens/) for public usage and token requests. --- The Search API finds verses containing words or phrases and returns both an ordered match list and chapter-grouped Scripture. It applies matching rules derived from the writing system of the text, so applications can send an ordinary search string without implementing their own language detector. ## Choose a data version | Version | Base route | Guide | | --- | --- | --- | | v2 | `https://search.getbible.net/v2/{translation}/{search}` | [Search v2](/api/search/v2/) | | v3 | `https://search.getbible.net/v3/{translation}/{search}` | [Search v3](/api/search/v3/) | The HTTP filters and result envelope are the same. The selected data version controls the source verses: v3 can retain lexical tokens, annotation spans and paragraph-start metadata. Chapter-level editorial layout is obtained from the static Bible API. ## Search in one request ```bash curl --fail-with-body --compressed --get \ 'https://search.getbible.net/v3/kjv' \ --data-urlencode 'q=faith hope' \ --data-urlencode 'scope=new_testament' \ --data-urlencode 'limit=25' ``` By default, every search unit must occur in the verse, matching is case-insensitive, applicable diacritics are folded and results are in canonical order. The full version guides document every filter, accepted type, limit and error. ## GET and POST use the same search GET accepts URL parameters. POST accepts the same parameters, a JSON object, or both. A value supplied in the path wins over the query string, which wins over the body, which wins over configured defaults. Explicit `false` and `0` are values; JSON `null` leaves a lower-priority/default value unchanged. ```bash curl --fail-with-body --compressed \ --header 'Content-Type: application/json' \ --data '{"translation":"kjv","q":"faith hope","words":"all","sort":"relevance","limit":25}' \ 'https://search.getbible.net/v3' ``` Use GET for shareable, cacheable searches and POST when a structured body is more convenient. POST search responses are not cached. Neither method writes or modifies Scripture. ## One envelope, two kinds of result | Member | Contents | | --- | --- | | `query` | Search text, kind, translation, engine version and counts; full-text searches also include criteria, pagination, source hash, cache state, analysis and cost | | `results` | Scripture grouped by `{translation}_{book}_{chapter}` | | `matches` | Ordered verse identities; full-text matches also include score, occurrences and matched terms | Check `query.kind`. A string that resolves as a Scripture reference returns `kind: "reference"`; it does not apply full-text filtering or pagination. Full-text results use `kind: "search"`. For relevance sorting, `matches` is the authoritative order; do not use the property order of chapter objects as the ranking. ## Matching across scripts The librarian inspects Unicode script properties in both the query and corpus. Alphabetic scripts use word units; continuous scripts such as Han and Hangul use positional character units; abjad handling supports optional vowel-point folding and attached-particle stems. Brahmic scripts preserve vowel-bearing combining marks. Mixed-script input is handled by its individual runs rather than switching the entire string to substring matching. Original returned verse text remains unchanged. See the [librarian search documentation](https://github.com/getbible/librarian/blob/master/docs/SEARCH.md). ## Pagination and limits The public HTTP contract accepts `limit` from 1 to 100 and `offset` from 0 to 10000. Use `query.has_more` and advance the offset by the number returned. Keep the query, translation, API version and criteria unchanged while paging. If the source hash changes between pages, restart to avoid combining different data generations. The Python librarian's local limits can differ from the public HTTP service. Use the API's OpenAPI limits when integrating over HTTP. A partner bearer token exempts public rate budgets; it does not disable search cost, input or execution limits. ## Access and operational behavior Public calls work without a token under per-address budgets. Request application access through [support](https://git.vdm.dev/getBible/support) or [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church), naming `search.getbible.net` among the domains needed. Send the issued token in the `Authorization` header. Retry `429` and temporary `503` responses according to `Retry-After`. Narrow a repeatedly expensive request with a scope, book filter or more precise words. A first request for an uncached translation can include corpus preparation time. Handle timeouts without assuming that the translation does not exist. ## Contracts and upstream documentation | Resource | Link | | --- | --- | | Service overview | [search.getbible.net](https://search.getbible.net/) | | Version discovery | [versions.json](https://search.getbible.net/versions.json) | | v2 documentation and OpenAPI | [Documentation](https://search.getbible.net/v2/) · [OpenAPI JSON](https://search.getbible.net/v2/openapi.json) | | v3 documentation and OpenAPI | [Documentation](https://search.getbible.net/v3/) · [OpenAPI JSON](https://search.getbible.net/v3/openapi.json) | | Matching and search fields | [Librarian search](https://github.com/getbible/librarian/blob/master/docs/SEARCH.md) | | Runtime contract | [Runtime endpoints](https://github.com/getbible/api/blob/main/docs/RUNTIME_ENDPOINTS.md) | | Source data and study metadata | [Bible v3](/api/bible/v3/) | Use the central [GetBible support desk](https://git.vdm.dev/getBible/support) for help with search behavior or an integration. --- Search v2 finds Scripture in the Bible v2 data tree. It accepts words, phrases and structured filters through GET or POST, returning both an ordered match list and the matching verses grouped by chapter. If the input resolves as a Scripture reference, it returns that passage in the same outer envelope. **Canonical route:** `https://search.getbible.net/v2/{translation}/{search}` [Live documentation](https://search.getbible.net/v2/) · [OpenAPI JSON](https://search.getbible.net/v2/openapi.json) · [Search overview](/api/search/) · [Support](https://git.vdm.dev/getBible/support) ## Quick start ```bash curl --fail-with-body --compressed --get \ 'https://search.getbible.net/v2/kjv' \ --data-urlencode 'q=faith hope' \ --data-urlencode 'limit=25' ``` The default `words=all` mode requires both units in the verse. `words=any` permits either; `words=phrase` requests their ordered phrase. No token is required for public requests within the anonymous budget. ## All request forms | Method | Path | Where the query comes from | | --- | --- | --- | | GET | `/v2/{translation}/{search}` | Search text in the path; filters in query parameters | | GET | `/v2/{translation}?q=...` | Translation in the path, search text and filters in query parameters | | GET | `/v2?q=...&translation=...` | Search text and translation in query parameters | | POST | `/v2/{translation}/{search}` | Path text; filters in query parameters and/or JSON | | POST | `/v2/{translation}` | Search text in query parameters and/or JSON | | POST | `/v2` | Translation, search text and filters in query parameters and/or JSON | POST bodies must be JSON objects sent with `Content-Type: application/json`. They are optional when the URL supplies the search. GET bodies are not read. Neither method modifies Scripture. Values have this precedence: path, then query string, then JSON body, then configured defaults. If a path contains `faith hope`, a body `q` does not replace it. Explicit `false` and `0` override a lower-priority value. A JSON `null` value is ignored, leaving the underlying/default value available. `translation` defaults to `kjv` when omitted on a route accepting it as a parameter. An explicitly supplied unknown translation returns `404`. Use an abbreviation from [the v2 translation catalogue](https://api.getbible.net/v2/translations.json). ## Every input and filter All filters are optional. These limits follow the published HTTP OpenAPI contract; local Python librarian limits are different in some cases. | Field | Values or type | Default | Notes | | --- | --- | --- | --- | | `q` | String, 1–500 characters | None | Required when text is not in the path; words or a Scripture reference | | `translation` | String abbreviation | `kjv` | Case-insensitive; overridden by a path translation | | `words` | `all`, `any`, `phrase` | `all` | Relationship among analysed query units | | `match` | `whole_word`, `substring` | `whole_word` | Substring permits a match within an indexed word | | `case_sensitive` | Boolean | `false` | URL forms accept true/false, 1/0 or yes/no, case-insensitively | | `scope` | `bible`, `old_testament`, `new_testament`, `deuterocanon` | `bible` | Restricts the search corpus | | `book` | Repeated names or numbers | All books | Repeat in query strings, or use a scalar/array in JSON | | `books` | Comma-separated names/numbers; JSON also accepts arrays | All books | Combined with `book`; at most 83 combined selections | | `diacritics` | `fold`, `exact` | `fold` | Compatibility aliases: `insensitive` → `fold`, `sensitive` → `exact` | | `exclude` | Repeated words; scalar/array in JSON | None | At most 32 terms, each 1–100 characters | | `proximity` | Integer 0–100 | None | Maximum intervening units; requires `words=all` | | `sort` | `canonical`, `relevance` | `canonical` | Use `matches` as the authoritative result order | | `limit` | Integer 1–100 | `100` | Maximum returned verses per full-text page | | `offset` | Integer 0–10000 | `0` | Number of full-text matches to skip | `book` and `exclude` are repeatable query parameters. Repeating another parameter, such as `limit=10&limit=20`, returns `400 repeated_parameter`. Unknown fields are rejected. Combine book selectors with scope: `scope=new_testament&book=John` searches only John, not the union of John and the New Testament. ## Copy-and-run search recipes ### A phrase in the New Testament ```bash curl --fail-with-body --compressed --get \ 'https://search.getbible.net/v2/kjv' \ --data-urlencode 'q=eternal life' \ --data-urlencode 'words=phrase' \ --data-urlencode 'scope=new_testament' \ --data-urlencode 'limit=25' ``` ### Several books, an exclusion and relevance order ```bash curl --fail-with-body --compressed --get \ 'https://search.getbible.net/v2/kjv' \ --data-urlencode 'q=word life' \ --data-urlencode 'book=John' \ --data-urlencode 'book=1 John' \ --data-urlencode 'exclude=darkness' \ --data-urlencode 'sort=relevance' \ --data-urlencode 'limit=20' ``` ### Near one another ```bash curl --fail-with-body --compressed --get \ 'https://search.getbible.net/v2/kjv' \ --data-urlencode 'q=faith hope' \ --data-urlencode 'words=all' \ --data-urlencode 'proximity=5' ``` ### Structured JSON request ```bash curl --fail-with-body --compressed \ --header 'Content-Type: application/json' \ --data '{"translation":"kjv","q":"faith hope","words":"all","scope":"new_testament","books":["Romans","1 Corinthians"],"sort":"relevance","limit":20,"offset":0}' \ 'https://search.getbible.net/v2' ``` ### Search a continuous script ```bash curl --fail-with-body --compressed --get \ 'https://search.getbible.net/v2/cus' \ --data-urlencode 'q=神爱世人' \ --data-urlencode 'limit=20' ``` The normal matching defaults handle the script; the caller does not need to force substring matching. Translation availability comes from the selected version's catalogue. ## How matching works `all` requires every distinct analysed unit somewhere in the same verse. `any` requires at least one. `phrase` requires ordered units at the spacing represented by the query; punctuation can occur between them. `proximity` narrows an `all` search by the number of intervening units. Alphabetic scripts use word boundaries. Continuous scripts use position-aware character units. Abjad analysis accounts for optional pointing and supported attached-particle stems. Brahmic and continuous scripts preserve combining marks that carry meaningful vowels. Mixed-script text keeps the appropriate rules for each run. The engine derives these choices from Unicode script properties rather than trusting the translation language label alone. Case-insensitive analysis uses Unicode case folding. `diacritics=fold` removes applicable accents or optional pointing and folds additional supported characters; `exact` distinguishes them. Returned Scripture text is preserved as supplied by the source. For space-delimited scripts, substring fragments normally need at least three characters. That Latin-style floor is not imposed on ordinary short units in Han, Hangul, Thai, Hebrew, Arabic or Devanagari. A mixed query still applies the floor to an applicable alphabetic run. The [librarian matching documentation](https://github.com/getbible/librarian/blob/master/docs/SEARCH.md) explains these rules and their version history. ## The response envelope Every successful response contains three members: | Member | Type | Meaning | | --- | --- | --- | | `query` | Object | Request interpretation, selected translation and counts | | `results` | Object | Chapter-grouped Scripture keyed by `{translation}_{book}_{chapter}` | | `matches` | Array | Ordered match records pointing into those chapters | ### Query metadata | Field | Available on | Meaning | | --- | --- | --- | | `text` | Both kinds | Search/reference input | | `kind` | Both | `search` or `reference` | | `translation` | Both | Compact translation object; schema also permits an identifier string fallback | | `engine_version` | Both | Search/response semantics version; use it in downstream cache invalidation | | `total` | Both | Total matching/selected verses | | `returned` | Both | Number of verses in this response | | `criteria` | Full-text | Normalized criteria applied by the engine | | `sha` | Full-text | Underlying translation content version, or null if unavailable | | `offset`, `limit` | Full-text | Effective pagination | | `has_more` | Full-text | Whether additional matching verses remain | | `cache.checked_at` | Full-text | Last source-check timestamp, or null | | `cache.stale` | Full-text | Whether retained data is marked stale | | `analysis.script` | Full-text | Analysis classification such as `alphabetic` or `continuous` | | `cost.work_units` | Full-text | Measured search work units | | `cost.deadline_seconds` | Full-text | Configured execution deadline | | `cost.expensive` | Full-text | Whether expensive-query handling applies | `query.translation` contains the source's available `translation`, `abbreviation`, `lang`, `language`, `direction` and `encoding` fields. The same compact translation fields appear in each result chapter. Fetch the static translation catalogue separately for descriptions, source terms and history. Empty results still retain query/translation metadata. ### Chapter and verse data Each entry in `results` contains the compact translation fields, `book_nr`, `book_name`, `chapter`, `name`, `ref` and `verses`. Its selected verse objects retain their source fields and nested values. The chapter name uses `name`; the translation display name uses `translation`. ### v2 verse representation Version 2 reads the v2 source tree and returns the established verse fields: `chapter`, `verse`, `name` and `text`. The outer search envelope does not require the application to adopt a new Scripture renderer. For optional source lexical and annotation metadata, use [Search v3](/api/search/v3/). ### Match records and ordering Every match has `reference`, `book_nr`, `chapter` and `verse`. Full-text matches additionally provide numeric `score`, integer `occurrences` and a `terms` array. Reference-kind matches omit those scoring fields. `matches` determines the displayed order, especially under relevance sorting. `results` is organized for Scripture retrieval and rendering rather than ranking. Find a matched verse in its chapter using its integer verse number; do not assume its position in the selected `verses` array equals `verse - 1`. ```javascript async function searchScripture(text, offset = 0) { const parameters = new URLSearchParams({ q: text, sort: 'relevance', limit: '25', offset: String(offset) }); const response = await fetch(`https://search.getbible.net/v2/kjv?${parameters}`); const body = await response.json(); if (!response.ok) throw new Error(body.detail ?? `HTTP ${response.status}`); return body; } const page = await searchScripture('faith hope'); for (const match of page.matches) { const key = `kjv_${match.book_nr}_${match.chapter}`; const chapter = page.results[key]; const verse = chapter?.verses.find(item => item.verse === match.verse); if (verse) console.log(match.reference, verse.text, match.score); } if (page.query.kind === 'search' && page.query.has_more) { console.log('Next offset:', page.query.offset + page.query.returned); } ``` This complete example works in a modern browser console or an ES module with `fetch`. ## Reference detection is a separate result kind ```bash curl --fail-with-body --compressed \ 'https://search.getbible.net/v2/kjv/John3:16' ``` This input resolves as a reference, so `query.kind` is `reference`. Full-text criteria, pagination, source SHA, cache, analysis and cost are absent from `query`; score, occurrences and terms are absent from matches. Full-text filters are not applied to this kind, including a supplied `limit` or book restriction. Branch on `query.kind` before building pagination controls or assuming score data exists. Use [Query v2](/api/query/v2/) when the input is explicitly a Scripture reference. ## Pagination and empty results A full-text search with no matches is a successful response with `query.total = 0`, empty `results` and empty `matches`. A page beyond the final result is also empty. It is not a missing-translation error. Advance a full-text search by `offset + returned` while `has_more` is true. Keep all criteria unchanged, stay within the 10000 offset bound and avoid combining pages if the returned source `sha` changes. Namespace persisted search results by API version, translation, query, normalized criteria, source SHA and `engine_version`. The live inspected responses use engine version 5; treat the returned value as authoritative instead of hardcoding it. ## Redirects, encoding and caching Short forms such as `/v2/faith%20hope` redirect to the default translation. Unversioned aliases follow the domain's configured default endpoint. GET aliases use `301`; POST aliases use `308` to preserve method and body. Prefer an explicit canonical route when integrating. Use `curl --get --data-urlencode` or your language's URL builder for search text and filters. A literal `&` separates URL fields; percent-encode characters belonging to the search value. Plain spaces in a path should be encoded as `%20`. Public GET/HEAD data responses advertise cache lifetimes and ETags. Cache the entire URL including every filter. Conditional `If-None-Match` requests may return `304` with no body. Read actual `Cache-Control` rather than assuming a fixed lifetime. POST responses and runtime error responses are not cached. Token-only data uses `private, no-store`; tokens on an otherwise public service do not make the underlying Scripture private. ## Access and request limits Public access is metered by client address. Application and partner bearer tokens remove those public rate budgets but do not disable filter validation, pagination bounds, cost limits or concurrency controls. Request a token for `search.getbible.net` through [support](https://git.vdm.dev/getBible/support) or [email](mailto:getBible@TrueChristian.church). Set your issued value as `GETBIBLE_SEARCH_TOKEN` and use: ```bash curl --fail-with-body --compressed --get \ --header "Authorization: Bearer ${GETBIBLE_SEARCH_TOKEN:?Set GETBIBLE_SEARCH_TOKEN to your issued token}" \ 'https://search.getbible.net/v2/kjv' \ --data-urlencode 'q=faith hope' \ --data-urlencode 'limit=25' ``` The standard execution deadline is 5 seconds and the service also enforces a work budget. Corpus loading and index preparation can happen outside that execution deadline, so a cold request can take longer. `503 busy` signals capacity pressure. Respect `Retry-After`, avoid immediate retry loops and narrow repeated expensive searches. ## Error handling Errors are `application/problem+json` documents with `type`, `title`, `status`, `code`, `detail` and `instance`. Optional `retry_after` accompanies temporary failures where supplied. Branch on HTTP status/code and use the human-readable `detail` in diagnostics. | HTTP | Code | Meaning | | --- | --- | --- | | 400 | `missing_search` | No search text in path, `q` parameter or body | | 400 | `invalid_search` | Invalid text, criteria or values outside the contract | | 400 | `invalid_body` | JSON body is not a valid object of parameters | | 400 | `unknown_parameter` | Parameter is not supported | | 400 | `repeated_parameter` | A non-repeatable query parameter was repeated | | 400 | `request_limit` | Request exceeds a structural/work limit | | 401 | `unauthorized` | Credentials required by token-only access are missing or invalid | | 404 | `translation_not_found` | Translation unavailable | | 404 | `unknown_version` | API version unavailable on this endpoint | | 405 | `method_not_allowed` | Unsupported HTTP method | | 415 | `unsupported_media_type` | Non-JSON POST body | | 429 | `rate_limited` | Public client-address budget exceeded | | 503 | `busy`, `search_timeout`, `repository_unavailable`, `readiness_failed` | Temporary capacity, execution or source-read problem | The contract also describes intermediary/deployment statuses such as 413, 500, 502 and 504. Do not retry invalid 400-class requests unchanged. Retry temporary errors using the supplied `Retry-After` interval and a bounded retry policy. ## Health and API client import ```bash curl --fail-with-body 'https://search.getbible.net/healthz' curl --fail-with-body 'https://search.getbible.net/readyz' curl --fail-with-body --compressed \ 'https://search.getbible.net/v2/openapi.json' \ --output getbible-search-v2-openapi.json ``` `healthz` checks liveness; `readyz` verifies that the default Scripture is readable. Documentation and these health routes are public without a token. The server's private deployment `/probez` is not a public API endpoint. Import the OpenAPI URL or downloaded contract through Postman's Import dialog. It contains the server host, versioned routes, shared query parameters, JSON body schema and response schemas. Prefer GET for reproducible shareable tests and POST to exercise structured body values. This guide follows the [live v2 OpenAPI](https://search.getbible.net/v2/openapi.json), [live service guide](https://search.getbible.net/v2/), [runtime implementation contract](https://github.com/getbible/api/blob/main/docs/RUNTIME_ENDPOINTS.md), [librarian search semantics](https://github.com/getbible/librarian/blob/master/docs/SEARCH.md), and [compact metadata contract](https://github.com/getbible/librarian/blob/master/docs/TRANSLATION_METADATA.md). Ask for help at [GetBible support](https://git.vdm.dev/getBible/support), including the URL, status and `X-Request-ID` response header without any access token. ## Complete contract reference Open the [complete endpoint and schema reference](/api/search/v2/reference/) for every operation, parameter, response and component model in the published OpenAPI contract. --- # Search API v2: endpoint and schema reference This reference is generated from the checked-in [OpenAPI contract](https://search.getbible.net/v2/openapi.json). Return to the [integration guide](/api/search/v2/) for workflows and ready-to-run examples. Resolved request server: `https://search.getbible.net`. ## GET /healthz Liveness Operation ID: `health`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Service is online | application/json | #/components/schemas/Health |
Complete operation contract ```json { "operationId": "health", "responses": { "200": { "content": { "application/json": { "example": { "status": "ok" }, "schema": { "$ref": "#/components/schemas/Health" } } }, "description": "Service is online" } }, "security": [], "summary": "Liveness", "parameters": [] } ```
## GET /readyz Readiness: read a verse from the default translation Operation ID: `readiness`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Scripture is readable | application/json | #/components/schemas/Health | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "readiness", "responses": { "200": { "content": { "application/json": { "example": { "status": "ready" }, "schema": { "$ref": "#/components/schemas/Health" } } }, "description": "Scripture is readable" }, "503": { "$ref": "#/components/responses/Problem" } }, "security": [], "summary": "Readiness: read a verse from the default translation", "parameters": [] } ```
## GET /{segment} Short form: translation or search string Operation ID: `searchAlias`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `segment` | path | Yes | string | faith hope | — | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 301 | Redirect to the versioned endpoint, preserving query parameters. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "searchAlias", "responses": { "301": { "description": "Redirect to the versioned endpoint, preserving query parameters.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form: translation or search string", "parameters": [ { "in": "path", "name": "segment", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## POST /{segment} Short form with POST Operation ID: `searchAliasPost`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `segment` | path | Yes | string | faith hope | — | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Request body Optional. Media type: `application/json`. Schema: `#/components/schemas/SearchRequest`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 308 | Redirect preserving method, JSON body and query parameters. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "searchAliasPost", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": false }, "responses": { "308": { "description": "Redirect preserving method, JSON body and query parameters.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form with POST", "parameters": [ { "in": "path", "name": "segment", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## GET /{translation}/{search} Short form: translation or search string Operation ID: `searchUnversioned`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `search` | path | Yes | string | faith hope | Search words or a scripture reference, URL-encoded. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 301 | Redirect to the versioned endpoint, preserving query parameters. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "searchUnversioned", "responses": { "301": { "description": "Redirect to the versioned endpoint, preserving query parameters.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form: translation or search string", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference, URL-encoded.", "in": "path", "name": "search", "required": true, "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## POST /{translation}/{search} Short form with POST Operation ID: `searchUnversionedPost`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `search` | path | Yes | string | faith hope | Search words or a scripture reference, URL-encoded. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Request body Optional. Media type: `application/json`. Schema: `#/components/schemas/SearchRequest`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 308 | Redirect preserving method, JSON body and query parameters. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "searchUnversionedPost", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": false }, "responses": { "308": { "description": "Redirect preserving method, JSON body and query parameters.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form with POST", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference, URL-encoded.", "in": "path", "name": "search", "required": true, "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## GET /v2/openapi.json Public API contract Operation ID: `openapi`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Generated OpenAPI 3.1 JSON document. | application/json | object |
Complete operation contract ```json { "operationId": "openapi", "responses": { "200": { "content": { "application/json": { "schema": { "properties": { "info": { "type": "object" }, "openapi": { "type": "string" }, "paths": { "type": "object" } }, "required": [ "openapi", "info", "paths" ], "type": "object" } } }, "description": "Generated OpenAPI 3.1 JSON document." } }, "security": [], "summary": "Public API contract", "parameters": [] } ```
## GET /v2/{translation} Search using URL parameters The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read. Operation ID: `searchTranslation`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 301 | An unrecognised translation segment is interpreted as the search string and redirected to the default translation. | — | See contract | | 304 | Not modified for an ETag conditional GET. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read.", "operationId": "searchTranslation", "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "301": { "description": "An unrecognised translation segment is interpreted as the search string and redirected to the default translation.", "headers": { "Location": { "schema": { "type": "string" } } } }, "304": { "description": "Not modified for an ETag conditional GET." }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## POST /v2/{translation} Search using URL parameters, a JSON body, or both The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters. Operation ID: `searchTranslationPost`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Request body Optional. Media type: `application/json`. Schema: `#/components/schemas/SearchRequest`. ```json { "limit": 25, "q": "faith hope", "words": "any" } ``` ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 308 | An unrecognised translation segment is interpreted as the search string; redirect preserves POST, body and query parameters. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 415 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters.", "operationId": "searchTranslationPost", "requestBody": { "content": { "application/json": { "example": { "limit": 25, "q": "faith hope", "words": "any" }, "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": false }, "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "308": { "description": "An unrecognised translation segment is interpreted as the search string; redirect preserves POST, body and query parameters.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "415": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters, a JSON body, or both", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## GET /v2/{translation}/{search} Search using URL parameters The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read. Operation ID: `search`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `search` | path | Yes | string | faith hope | Search words or a scripture reference, URL-encoded. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 304 | Not modified for an ETag conditional GET. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read.", "operationId": "search", "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "304": { "description": "Not modified for an ETag conditional GET." }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference, URL-encoded.", "in": "path", "name": "search", "required": true, "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## POST /v2/{translation}/{search} Search using URL parameters, a JSON body, or both The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters. Operation ID: `searchPost`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `search` | path | Yes | string | faith hope | Search words or a scripture reference, URL-encoded. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Request body Optional. Media type: `application/json`. Schema: `#/components/schemas/SearchRequest`. ```json { "limit": 25, "q": "faith hope", "words": "any" } ``` ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 415 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters.", "operationId": "searchPost", "requestBody": { "content": { "application/json": { "example": { "limit": 25, "q": "faith hope", "words": "any" }, "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": false }, "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "415": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters, a JSON body, or both", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference, URL-encoded.", "in": "path", "name": "search", "required": true, "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## GET /v2 Search using URL parameters The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read. At a domain root, a request without query parameters serves the public documentation page; API requests at that path use the configured API access policy. Operation ID: `searchDefault`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 304 | Not modified for an ETag conditional GET. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read. At a domain root, a request without query parameters serves the public documentation page; API requests at that path use the configured API access policy.", "operationId": "searchDefault", "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "304": { "description": "Not modified for an ETag conditional GET." }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters", "parameters": [ { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## POST /v2 Search using URL parameters, a JSON body, or both The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters. Operation ID: `searchDefaultPost`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Request body Optional. Media type: `application/json`. Schema: `#/components/schemas/SearchRequest`. ```json { "limit": 25, "q": "faith hope", "words": "any" } ``` ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 415 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters.", "operationId": "searchDefaultPost", "requestBody": { "content": { "application/json": { "example": { "limit": 25, "q": "faith hope", "words": "any" }, "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": false }, "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "415": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters, a JSON body, or both", "parameters": [ { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## Component schemas Types, required properties, nested objects, constraints and examples below are copied directly from the contract. A property omitted from a schema’s `required` array is optional, even when examples include it. ### Criteria
View full Criteria schema ```json { "properties": { "books": { "items": { "type": [ "integer", "string" ] }, "type": "array" }, "case_sensitive": { "default": false, "type": "boolean" }, "diacritics": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" }, "exclude": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "limit": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" }, "match": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" }, "offset": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" }, "proximity": { "maximum": 100, "minimum": 0, "type": [ "integer", "null" ] }, "scope": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" }, "sort": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" }, "words": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, "required": [ "words", "match", "case_sensitive", "scope", "books", "diacritics", "exclude", "proximity", "sort", "limit", "offset" ], "type": "object" } ```
### Health
View full Health schema ```json { "properties": { "status": { "enum": [ "ok", "ready" ], "type": "string" } }, "required": [ "status" ], "type": "object" } ```
### Problem RFC 9457 problem document.
View full Problem schema ```json { "description": "RFC 9457 problem document.", "properties": { "code": { "type": "string" }, "detail": { "type": "string" }, "instance": { "type": "string" }, "retry_after": { "minimum": 0, "type": "integer" }, "status": { "type": "integer" }, "title": { "type": "string" }, "type": { "format": "uri", "type": "string" } }, "required": [ "type", "title", "status", "code", "detail", "instance" ], "type": "object" } ```
### Scripture One entry per chapter, keyed {translation}_{book}_{chapter}, with compact API translation metadata and selected verses. Verse source fields are retained; static chapter editorial is excluded.
View full Scripture schema ```json { "additionalProperties": { "properties": { "abbreviation": { "type": "string" }, "book_name": { "type": "string" }, "book_nr": { "type": "integer" }, "chapter": { "type": "integer" }, "direction": { "type": "string" }, "encoding": { "type": "string" }, "lang": { "type": "string" }, "language": { "type": "string" }, "name": { "type": "string" }, "ref": { "items": { "type": "string" }, "type": "array" }, "translation": { "type": "string" }, "verses": { "items": { "$ref": "#/components/schemas/Verse" }, "type": "array" } }, "required": [ "book_nr", "chapter", "verses" ], "type": "object" }, "description": "One entry per chapter, keyed {translation}_{book}_{chapter}, with compact API translation metadata and selected verses. Verse source fields are retained; static chapter editorial is excluded.", "type": "object" } ```
### SearchMatch Reference results omit score, occurrences and terms.
View full SearchMatch schema ```json { "description": "Reference results omit score, occurrences and terms.", "properties": { "book_nr": { "type": "integer" }, "chapter": { "type": "integer" }, "occurrences": { "minimum": 0, "type": "integer" }, "reference": { "type": "string" }, "score": { "type": "number" }, "terms": { "items": { "type": "string" }, "type": "array" }, "verse": { "type": "integer" } }, "required": [ "reference", "book_nr", "chapter", "verse" ], "type": "object" } ```
### SearchQuery Reference results omit criteria, sha, pagination, cache, analysis and cost. Filters are only applied to full-text searches.
View full SearchQuery schema ```json { "description": "Reference results omit criteria, sha, pagination, cache, analysis and cost. Filters are only applied to full-text searches.", "properties": { "analysis": { "properties": { "script": { "type": "string" } }, "type": "object" }, "cache": { "properties": { "checked_at": { "type": [ "number", "null" ] }, "stale": { "type": "boolean" } }, "type": "object" }, "cost": { "properties": { "deadline_seconds": { "type": "number" }, "expensive": { "type": "boolean" }, "work_units": { "minimum": 0, "type": "integer" } }, "type": "object" }, "criteria": { "$ref": "#/components/schemas/Criteria" }, "engine_version": { "type": "integer" }, "has_more": { "type": "boolean" }, "kind": { "enum": [ "search", "reference" ], "type": "string" }, "limit": { "minimum": 1, "type": "integer" }, "offset": { "minimum": 0, "type": "integer" }, "returned": { "minimum": 0, "type": "integer" }, "sha": { "type": [ "string", "null" ] }, "text": { "type": "string" }, "total": { "minimum": 0, "type": "integer" }, "translation": { "anyOf": [ { "$ref": "#/components/schemas/Translation" }, { "type": "string" } ] } }, "required": [ "text", "kind", "translation", "engine_version", "total", "returned" ], "type": "object" } ```
### SearchRequest All fields are optional when supplied in the path/query. GET uses query parameters. POST accepts query parameters, a JSON object, or both. Path > query > body > configured defaults; null body fields preserve a lower-priority value. book and books are combined.
View full SearchRequest schema ```json { "additionalProperties": false, "description": "All fields are optional when supplied in the path/query. GET uses query parameters. POST accepts query parameters, a JSON object, or both. Path > query > body > configured defaults; null body fields preserve a lower-priority value. book and books are combined.", "properties": { "book": { "anyOf": [ { "anyOf": [ { "type": [ "string", "integer" ] }, { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" } ] }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "books": { "anyOf": [ { "anyOf": [ { "type": "string" }, { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" } ] }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "case_sensitive": { "anyOf": [ { "default": false, "type": "boolean" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "diacritics": { "anyOf": [ { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "exclude": { "anyOf": [ { "anyOf": [ { "maxLength": 100, "minLength": 1, "type": "string" }, { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" } ] }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "limit": { "anyOf": [ { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "match": { "anyOf": [ { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "offset": { "anyOf": [ { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "proximity": { "anyOf": [ { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "q": { "anyOf": [ { "maxLength": 500, "minLength": 1, "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "scope": { "anyOf": [ { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "sort": { "anyOf": [ { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "translation": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "words": { "anyOf": [ { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." } }, "type": "object" } ```
### SearchResult
View full SearchResult schema ```json { "properties": { "matches": { "items": { "$ref": "#/components/schemas/SearchMatch" }, "type": "array" }, "query": { "$ref": "#/components/schemas/SearchQuery" }, "results": { "$ref": "#/components/schemas/Scripture" } }, "required": [ "query", "results", "matches" ], "type": "object" } ```
### Translation
View full Translation schema ```json { "properties": { "abbreviation": { "type": "string" }, "direction": { "type": "string" }, "encoding": { "type": "string" }, "lang": { "type": "string" }, "language": { "type": "string" }, "translation": { "type": "string" } }, "type": "object" } ```
### Verse A source verse from the selected v2 data. Core fields are shared by v2 and v3. Optional v3 paragraph, tokens and spans are retained when present, as are other source fields and nested values.
View full Verse schema ```json { "additionalProperties": true, "description": "A source verse from the selected v2 data. Core fields are shared by v2 and v3. Optional v3 paragraph, tokens and spans are retained when present, as are other source fields and nested values.", "properties": { "chapter": { "type": "integer" }, "name": { "type": "string" }, "paragraph": { "description": "V3: true when this verse begins a paragraph; omitted when absent from the source.", "type": "boolean" }, "spans": { "description": "V3 annotations over token and word ranges, when supplied by the source.", "items": { "$ref": "#/components/schemas/VerseSpan" }, "type": "array" }, "text": { "type": "string" }, "tokens": { "description": "V3 word tokens in reading order, when supplied by the source.", "items": { "$ref": "#/components/schemas/VerseToken" }, "type": "array" }, "verse": { "type": "integer" } }, "required": [ "verse", "name", "text" ], "type": "object" } ```
### VerseSpan V3 source annotation. Token positions index the verse tokens array from zero, inclusive. Word positions count display words from one, inclusive; zero means unlocated.
View full VerseSpan schema ```json { "additionalProperties": true, "description": "V3 source annotation. Token positions index the verse tokens array from zero, inclusive. Word positions count display words from one, inclusive; zero means unlocated.", "properties": { "attrs": { "additionalProperties": { "type": "string" }, "type": "object" }, "span": { "type": "string" }, "tag": { "type": "string" }, "token_end": { "minimum": 0, "type": "integer" }, "token_start": { "minimum": 0, "type": "integer" }, "word_end": { "minimum": 0, "type": "integer" }, "word_start": { "minimum": 0, "type": "integer" } }, "required": [ "tag", "span", "token_start", "token_end", "word_start", "word_end" ], "type": "object" } ```
### VerseToken V3 word token. Word positions count whitespace-separated display words from one, inclusive; zero means unlocated. Additional source attributes are retained.
View full VerseToken schema ```json { "additionalProperties": true, "description": "V3 word token. Word positions count whitespace-separated display words from one, inclusive; zero means unlocated. Additional source attributes are retained.", "properties": { "gloss": { "type": "string" }, "lemma": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Lexical identifiers grouped by scheme, such as strong.", "type": "object" }, "morph": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Morphology codes grouped by scheme.", "type": "object" }, "morphSegmented": { "type": "boolean" }, "n": { "type": "string" }, "src": { "items": { "type": [ "integer", "string" ] }, "type": "array" }, "subType": { "type": "string" }, "token": { "type": "string" }, "type": { "type": "string" }, "variant": { "type": "boolean" }, "variantType": { "type": "string" }, "word_end": { "minimum": 0, "type": "integer" }, "word_start": { "minimum": 0, "type": "integer" }, "xlit": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Transliterations grouped by scheme.", "type": "object" } }, "required": [ "token", "word_start", "word_end" ], "type": "object" } ```
## Authentication contract ```json { "security": [], "securitySchemes": { "bearer": { "description": "Required for API data only on token-only domains. Valid tokens retain unrestricted rate access.", "scheme": "bearer", "type": "http" } } } ``` See [access and tokens](/tokens/) for public usage and token requests. --- Search v3 finds Scripture in the Bible v3 data tree. It accepts words, phrases and structured filters through GET or POST, returning both an ordered match list and the matching verses grouped by chapter. If the input resolves as a Scripture reference, it returns that passage in the same outer envelope. **Canonical route:** `https://search.getbible.net/v3/{translation}/{search}` [Live documentation](https://search.getbible.net/v3/) · [OpenAPI JSON](https://search.getbible.net/v3/openapi.json) · [Search overview](/api/search/) · [Support](https://git.vdm.dev/getBible/support) ## Quick start ```bash curl --fail-with-body --compressed --get \ 'https://search.getbible.net/v3/kjv' \ --data-urlencode 'q=faith hope' \ --data-urlencode 'limit=25' ``` The default `words=all` mode requires both units in the verse. `words=any` permits either; `words=phrase` requests their ordered phrase. No token is required for public requests within the anonymous budget. ## All request forms | Method | Path | Where the query comes from | | --- | --- | --- | | GET | `/v3/{translation}/{search}` | Search text in the path; filters in query parameters | | GET | `/v3/{translation}?q=...` | Translation in the path, search text and filters in query parameters | | GET | `/v3?q=...&translation=...` | Search text and translation in query parameters | | POST | `/v3/{translation}/{search}` | Path text; filters in query parameters and/or JSON | | POST | `/v3/{translation}` | Search text in query parameters and/or JSON | | POST | `/v3` | Translation, search text and filters in query parameters and/or JSON | POST bodies must be JSON objects sent with `Content-Type: application/json`. They are optional when the URL supplies the search. GET bodies are not read. Neither method modifies Scripture. Values have this precedence: path, then query string, then JSON body, then configured defaults. If a path contains `faith hope`, a body `q` does not replace it. Explicit `false` and `0` override a lower-priority value. A JSON `null` value is ignored, leaving the underlying/default value available. `translation` defaults to `kjv` when omitted on a route accepting it as a parameter. An explicitly supplied unknown translation returns `404`. Use an abbreviation from [the v3 translation catalogue](https://api.getbible.net/v3/translations.json). ## Every input and filter All filters are optional. These limits follow the published HTTP OpenAPI contract; local Python librarian limits are different in some cases. | Field | Values or type | Default | Notes | | --- | --- | --- | --- | | `q` | String, 1–500 characters | None | Required when text is not in the path; words or a Scripture reference | | `translation` | String abbreviation | `kjv` | Case-insensitive; overridden by a path translation | | `words` | `all`, `any`, `phrase` | `all` | Relationship among analysed query units | | `match` | `whole_word`, `substring` | `whole_word` | Substring permits a match within an indexed word | | `case_sensitive` | Boolean | `false` | URL forms accept true/false, 1/0 or yes/no, case-insensitively | | `scope` | `bible`, `old_testament`, `new_testament`, `deuterocanon` | `bible` | Restricts the search corpus | | `book` | Repeated names or numbers | All books | Repeat in query strings, or use a scalar/array in JSON | | `books` | Comma-separated names/numbers; JSON also accepts arrays | All books | Combined with `book`; at most 83 combined selections | | `diacritics` | `fold`, `exact` | `fold` | Compatibility aliases: `insensitive` → `fold`, `sensitive` → `exact` | | `exclude` | Repeated words; scalar/array in JSON | None | At most 32 terms, each 1–100 characters | | `proximity` | Integer 0–100 | None | Maximum intervening units; requires `words=all` | | `sort` | `canonical`, `relevance` | `canonical` | Use `matches` as the authoritative result order | | `limit` | Integer 1–100 | `100` | Maximum returned verses per full-text page | | `offset` | Integer 0–10000 | `0` | Number of full-text matches to skip | `book` and `exclude` are repeatable query parameters. Repeating another parameter, such as `limit=10&limit=20`, returns `400 repeated_parameter`. Unknown fields are rejected. Combine book selectors with scope: `scope=new_testament&book=John` searches only John, not the union of John and the New Testament. ## Copy-and-run search recipes ### A phrase in the New Testament ```bash curl --fail-with-body --compressed --get \ 'https://search.getbible.net/v3/kjv' \ --data-urlencode 'q=eternal life' \ --data-urlencode 'words=phrase' \ --data-urlencode 'scope=new_testament' \ --data-urlencode 'limit=25' ``` ### Several books, an exclusion and relevance order ```bash curl --fail-with-body --compressed --get \ 'https://search.getbible.net/v3/kjv' \ --data-urlencode 'q=word life' \ --data-urlencode 'book=John' \ --data-urlencode 'book=1 John' \ --data-urlencode 'exclude=darkness' \ --data-urlencode 'sort=relevance' \ --data-urlencode 'limit=20' ``` ### Near one another ```bash curl --fail-with-body --compressed --get \ 'https://search.getbible.net/v3/kjv' \ --data-urlencode 'q=faith hope' \ --data-urlencode 'words=all' \ --data-urlencode 'proximity=5' ``` ### Structured JSON request ```bash curl --fail-with-body --compressed \ --header 'Content-Type: application/json' \ --data '{"translation":"kjv","q":"faith hope","words":"all","scope":"new_testament","books":["Romans","1 Corinthians"],"sort":"relevance","limit":20,"offset":0}' \ 'https://search.getbible.net/v3' ``` ### Search a continuous script ```bash curl --fail-with-body --compressed --get \ 'https://search.getbible.net/v3/cus' \ --data-urlencode 'q=神爱世人' \ --data-urlencode 'limit=20' ``` The normal matching defaults handle the script; the caller does not need to force substring matching. Translation availability comes from the selected version's catalogue. ## How matching works `all` requires every distinct analysed unit somewhere in the same verse. `any` requires at least one. `phrase` requires ordered units at the spacing represented by the query; punctuation can occur between them. `proximity` narrows an `all` search by the number of intervening units. Alphabetic scripts use word boundaries. Continuous scripts use position-aware character units. Abjad analysis accounts for optional pointing and supported attached-particle stems. Brahmic and continuous scripts preserve combining marks that carry meaningful vowels. Mixed-script text keeps the appropriate rules for each run. The engine derives these choices from Unicode script properties rather than trusting the translation language label alone. Case-insensitive analysis uses Unicode case folding. `diacritics=fold` removes applicable accents or optional pointing and folds additional supported characters; `exact` distinguishes them. Returned Scripture text is preserved as supplied by the source. For space-delimited scripts, substring fragments normally need at least three characters. That Latin-style floor is not imposed on ordinary short units in Han, Hangul, Thai, Hebrew, Arabic or Devanagari. A mixed query still applies the floor to an applicable alphabetic run. The [librarian matching documentation](https://github.com/getbible/librarian/blob/master/docs/SEARCH.md) explains these rules and their version history. ## The response envelope Every successful response contains three members: | Member | Type | Meaning | | --- | --- | --- | | `query` | Object | Request interpretation, selected translation and counts | | `results` | Object | Chapter-grouped Scripture keyed by `{translation}_{book}_{chapter}` | | `matches` | Array | Ordered match records pointing into those chapters | ### Query metadata | Field | Available on | Meaning | | --- | --- | --- | | `text` | Both kinds | Search/reference input | | `kind` | Both | `search` or `reference` | | `translation` | Both | Compact translation object; schema also permits an identifier string fallback | | `engine_version` | Both | Search/response semantics version; use it in downstream cache invalidation | | `total` | Both | Total matching/selected verses | | `returned` | Both | Number of verses in this response | | `criteria` | Full-text | Normalized criteria applied by the engine | | `sha` | Full-text | Underlying translation content version, or null if unavailable | | `offset`, `limit` | Full-text | Effective pagination | | `has_more` | Full-text | Whether additional matching verses remain | | `cache.checked_at` | Full-text | Last source-check timestamp, or null | | `cache.stale` | Full-text | Whether retained data is marked stale | | `analysis.script` | Full-text | Analysis classification such as `alphabetic` or `continuous` | | `cost.work_units` | Full-text | Measured search work units | | `cost.deadline_seconds` | Full-text | Configured execution deadline | | `cost.expensive` | Full-text | Whether expensive-query handling applies | `query.translation` contains the source's available `translation`, `abbreviation`, `lang`, `language`, `direction` and `encoding` fields. The same compact translation fields appear in each result chapter. Fetch the static translation catalogue separately for descriptions, source terms and history. Empty results still retain query/translation metadata. ### Chapter and verse data Each entry in `results` contains the compact translation fields, `book_nr`, `book_name`, `chapter`, `name`, `ref` and `verses`. Its selected verse objects retain their source fields and nested values. The chapter name uses `name`; the translation display name uses `translation`. ### v3 verse representation Version 3 preserves optional source `paragraph`, `tokens` and `spans`, as well as other source verse fields and nested values. It does not invent metadata for verses that lack it. Each token has reading-order text and inclusive one-based display-word positions. Spans carry zero-based inclusive indexes into `tokens` and one-based inclusive display-word ranges; 0 in a display range means unlocated. Chapter-level `editorial` is deliberately omitted from search-assembled chapters, including reference-kind responses. If the app needs complete headings and paragraph ranges around a match, fetch that chapter from [Bible v3](/api/bible/v3/). Preserve the whole verse dictionary in storage or downstream responses so lexical attributes are retained. ### Match records and ordering Every match has `reference`, `book_nr`, `chapter` and `verse`. Full-text matches additionally provide numeric `score`, integer `occurrences` and a `terms` array. Reference-kind matches omit those scoring fields. `matches` determines the displayed order, especially under relevance sorting. `results` is organized for Scripture retrieval and rendering rather than ranking. Find a matched verse in its chapter using its integer verse number; do not assume its position in the selected `verses` array equals `verse - 1`. ```javascript async function searchScripture(text, offset = 0) { const parameters = new URLSearchParams({ q: text, sort: 'relevance', limit: '25', offset: String(offset) }); const response = await fetch(`https://search.getbible.net/v3/kjv?${parameters}`); const body = await response.json(); if (!response.ok) throw new Error(body.detail ?? `HTTP ${response.status}`); return body; } const page = await searchScripture('faith hope'); for (const match of page.matches) { const key = `kjv_${match.book_nr}_${match.chapter}`; const chapter = page.results[key]; const verse = chapter?.verses.find(item => item.verse === match.verse); if (verse) console.log(match.reference, verse.text, match.score); } if (page.query.kind === 'search' && page.query.has_more) { console.log('Next offset:', page.query.offset + page.query.returned); } ``` This complete example works in a modern browser console or an ES module with `fetch`. ## Reference detection is a separate result kind ```bash curl --fail-with-body --compressed \ 'https://search.getbible.net/v3/kjv/John3:16' ``` This input resolves as a reference, so `query.kind` is `reference`. Full-text criteria, pagination, source SHA, cache, analysis and cost are absent from `query`; score, occurrences and terms are absent from matches. Full-text filters are not applied to this kind, including a supplied `limit` or book restriction. Branch on `query.kind` before building pagination controls or assuming score data exists. Use [Query v3](/api/query/v3/) when the input is explicitly a Scripture reference. ## Pagination and empty results A full-text search with no matches is a successful response with `query.total = 0`, empty `results` and empty `matches`. A page beyond the final result is also empty. It is not a missing-translation error. Advance a full-text search by `offset + returned` while `has_more` is true. Keep all criteria unchanged, stay within the 10000 offset bound and avoid combining pages if the returned source `sha` changes. Namespace persisted search results by API version, translation, query, normalized criteria, source SHA and `engine_version`. The live inspected responses use engine version 5; treat the returned value as authoritative instead of hardcoding it. ## Redirects, encoding and caching Short forms such as `/v3/faith%20hope` redirect to the default translation. Unversioned aliases follow the domain's configured default endpoint. GET aliases use `301`; POST aliases use `308` to preserve method and body. Prefer an explicit canonical route when integrating. Use `curl --get --data-urlencode` or your language's URL builder for search text and filters. A literal `&` separates URL fields; percent-encode characters belonging to the search value. Plain spaces in a path should be encoded as `%20`. Public GET/HEAD data responses advertise cache lifetimes and ETags. Cache the entire URL including every filter. Conditional `If-None-Match` requests may return `304` with no body. Read actual `Cache-Control` rather than assuming a fixed lifetime. POST responses and runtime error responses are not cached. Token-only data uses `private, no-store`; tokens on an otherwise public service do not make the underlying Scripture private. ## Access and request limits Public access is metered by client address. Application and partner bearer tokens remove those public rate budgets but do not disable filter validation, pagination bounds, cost limits or concurrency controls. Request a token for `search.getbible.net` through [support](https://git.vdm.dev/getBible/support) or [email](mailto:getBible@TrueChristian.church). Set your issued value as `GETBIBLE_SEARCH_TOKEN` and use: ```bash curl --fail-with-body --compressed --get \ --header "Authorization: Bearer ${GETBIBLE_SEARCH_TOKEN:?Set GETBIBLE_SEARCH_TOKEN to your issued token}" \ 'https://search.getbible.net/v3/kjv' \ --data-urlencode 'q=faith hope' \ --data-urlencode 'limit=25' ``` The standard execution deadline is 5 seconds and the service also enforces a work budget. Corpus loading and index preparation can happen outside that execution deadline, so a cold request can take longer. `503 busy` signals capacity pressure. Respect `Retry-After`, avoid immediate retry loops and narrow repeated expensive searches. ## Error handling Errors are `application/problem+json` documents with `type`, `title`, `status`, `code`, `detail` and `instance`. Optional `retry_after` accompanies temporary failures where supplied. Branch on HTTP status/code and use the human-readable `detail` in diagnostics. | HTTP | Code | Meaning | | --- | --- | --- | | 400 | `missing_search` | No search text in path, `q` parameter or body | | 400 | `invalid_search` | Invalid text, criteria or values outside the contract | | 400 | `invalid_body` | JSON body is not a valid object of parameters | | 400 | `unknown_parameter` | Parameter is not supported | | 400 | `repeated_parameter` | A non-repeatable query parameter was repeated | | 400 | `request_limit` | Request exceeds a structural/work limit | | 401 | `unauthorized` | Credentials required by token-only access are missing or invalid | | 404 | `translation_not_found` | Translation unavailable | | 404 | `unknown_version` | API version unavailable on this endpoint | | 405 | `method_not_allowed` | Unsupported HTTP method | | 415 | `unsupported_media_type` | Non-JSON POST body | | 429 | `rate_limited` | Public client-address budget exceeded | | 503 | `busy`, `search_timeout`, `repository_unavailable`, `readiness_failed` | Temporary capacity, execution or source-read problem | The contract also describes intermediary/deployment statuses such as 413, 500, 502 and 504. Do not retry invalid 400-class requests unchanged. Retry temporary errors using the supplied `Retry-After` interval and a bounded retry policy. ## Health and API client import ```bash curl --fail-with-body 'https://search.getbible.net/healthz' curl --fail-with-body 'https://search.getbible.net/readyz' curl --fail-with-body --compressed \ 'https://search.getbible.net/v3/openapi.json' \ --output getbible-search-v3-openapi.json ``` `healthz` checks liveness; `readyz` verifies that the default Scripture is readable. Documentation and these health routes are public without a token. The server's private deployment `/probez` is not a public API endpoint. Import the OpenAPI URL or downloaded contract through Postman's Import dialog. It contains the server host, versioned routes, shared query parameters, JSON body schema and response schemas. Prefer GET for reproducible shareable tests and POST to exercise structured body values. This guide follows the [live v3 OpenAPI](https://search.getbible.net/v3/openapi.json), [live service guide](https://search.getbible.net/v3/), [runtime implementation contract](https://github.com/getbible/api/blob/main/docs/RUNTIME_ENDPOINTS.md), [librarian search semantics](https://github.com/getbible/librarian/blob/master/docs/SEARCH.md), and [compact metadata contract](https://github.com/getbible/librarian/blob/master/docs/TRANSLATION_METADATA.md). Ask for help at [GetBible support](https://git.vdm.dev/getBible/support), including the URL, status and `X-Request-ID` response header without any access token. ## Complete contract reference Open the [complete endpoint and schema reference](/api/search/v3/reference/) for every operation, parameter, response and component model in the published OpenAPI contract. --- # Search API v3: endpoint and schema reference This reference is generated from the checked-in [OpenAPI contract](https://search.getbible.net/v3/openapi.json). Return to the [integration guide](/api/search/v3/) for workflows and ready-to-run examples. Resolved request server: `https://search.getbible.net`. ## GET /healthz Liveness Operation ID: `health`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Service is online | application/json | #/components/schemas/Health |
Complete operation contract ```json { "operationId": "health", "responses": { "200": { "content": { "application/json": { "example": { "status": "ok" }, "schema": { "$ref": "#/components/schemas/Health" } } }, "description": "Service is online" } }, "security": [], "summary": "Liveness", "parameters": [] } ```
## GET /readyz Readiness: read a verse from the default translation Operation ID: `readiness`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Scripture is readable | application/json | #/components/schemas/Health | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "readiness", "responses": { "200": { "content": { "application/json": { "example": { "status": "ready" }, "schema": { "$ref": "#/components/schemas/Health" } } }, "description": "Scripture is readable" }, "503": { "$ref": "#/components/responses/Problem" } }, "security": [], "summary": "Readiness: read a verse from the default translation", "parameters": [] } ```
## GET /{segment} Short form: translation or search string Operation ID: `searchAlias`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `segment` | path | Yes | string | faith hope | — | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 301 | Redirect to the versioned endpoint, preserving query parameters. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "searchAlias", "responses": { "301": { "description": "Redirect to the versioned endpoint, preserving query parameters.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form: translation or search string", "parameters": [ { "in": "path", "name": "segment", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## POST /{segment} Short form with POST Operation ID: `searchAliasPost`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `segment` | path | Yes | string | faith hope | — | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Request body Optional. Media type: `application/json`. Schema: `#/components/schemas/SearchRequest`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 308 | Redirect preserving method, JSON body and query parameters. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "searchAliasPost", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": false }, "responses": { "308": { "description": "Redirect preserving method, JSON body and query parameters.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form with POST", "parameters": [ { "in": "path", "name": "segment", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## GET /{translation}/{search} Short form: translation or search string Operation ID: `searchUnversioned`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `search` | path | Yes | string | faith hope | Search words or a scripture reference, URL-encoded. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 301 | Redirect to the versioned endpoint, preserving query parameters. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "searchUnversioned", "responses": { "301": { "description": "Redirect to the versioned endpoint, preserving query parameters.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form: translation or search string", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference, URL-encoded.", "in": "path", "name": "search", "required": true, "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## POST /{translation}/{search} Short form with POST Operation ID: `searchUnversionedPost`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `search` | path | Yes | string | faith hope | Search words or a scripture reference, URL-encoded. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Request body Optional. Media type: `application/json`. Schema: `#/components/schemas/SearchRequest`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 308 | Redirect preserving method, JSON body and query parameters. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "operationId": "searchUnversionedPost", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": false }, "responses": { "308": { "description": "Redirect preserving method, JSON body and query parameters.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Short form with POST", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference, URL-encoded.", "in": "path", "name": "search", "required": true, "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## GET /v3/openapi.json Public API contract Operation ID: `openapi`. ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Generated OpenAPI 3.1 JSON document. | application/json | object |
Complete operation contract ```json { "operationId": "openapi", "responses": { "200": { "content": { "application/json": { "schema": { "properties": { "info": { "type": "object" }, "openapi": { "type": "string" }, "paths": { "type": "object" } }, "required": [ "openapi", "info", "paths" ], "type": "object" } } }, "description": "Generated OpenAPI 3.1 JSON document." } }, "security": [], "summary": "Public API contract", "parameters": [] } ```
## GET /v3/{translation} Search using URL parameters The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read. Operation ID: `searchTranslation`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 301 | An unrecognised translation segment is interpreted as the search string and redirected to the default translation. | — | See contract | | 304 | Not modified for an ETag conditional GET. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read.", "operationId": "searchTranslation", "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "301": { "description": "An unrecognised translation segment is interpreted as the search string and redirected to the default translation.", "headers": { "Location": { "schema": { "type": "string" } } } }, "304": { "description": "Not modified for an ETag conditional GET." }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## POST /v3/{translation} Search using URL parameters, a JSON body, or both The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters. Operation ID: `searchTranslationPost`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Request body Optional. Media type: `application/json`. Schema: `#/components/schemas/SearchRequest`. ```json { "limit": 25, "q": "faith hope", "words": "any" } ``` ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 308 | An unrecognised translation segment is interpreted as the search string; redirect preserves POST, body and query parameters. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 415 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters.", "operationId": "searchTranslationPost", "requestBody": { "content": { "application/json": { "example": { "limit": 25, "q": "faith hope", "words": "any" }, "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": false }, "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "308": { "description": "An unrecognised translation segment is interpreted as the search string; redirect preserves POST, body and query parameters.", "headers": { "Location": { "schema": { "type": "string" } } } }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "415": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters, a JSON body, or both", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## GET /v3/{translation}/{search} Search using URL parameters The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read. Operation ID: `search`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `search` | path | Yes | string | faith hope | Search words or a scripture reference, URL-encoded. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 304 | Not modified for an ETag conditional GET. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read.", "operationId": "search", "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "304": { "description": "Not modified for an ETag conditional GET." }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference, URL-encoded.", "in": "path", "name": "search", "required": true, "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## POST /v3/{translation}/{search} Search using URL parameters, a JSON body, or both The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters. Operation ID: `searchPost`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `translation` | path | Yes | string | kjv | Translation abbreviation; case-insensitive. | | `search` | path | Yes | string | faith hope | Search words or a scripture reference, URL-encoded. | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Request body Optional. Media type: `application/json`. Schema: `#/components/schemas/SearchRequest`. ```json { "limit": 25, "q": "faith hope", "words": "any" } ``` ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 415 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters.", "operationId": "searchPost", "requestBody": { "content": { "application/json": { "example": { "limit": 25, "q": "faith hope", "words": "any" }, "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": false }, "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "415": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters, a JSON body, or both", "parameters": [ { "description": "Translation abbreviation; case-insensitive.", "in": "path", "name": "translation", "required": true, "schema": { "type": "string" } }, { "description": "Search words or a scripture reference, URL-encoded.", "in": "path", "name": "search", "required": true, "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## GET /v3 Search using URL parameters The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read. At a domain root, a request without query parameters serves the public documentation page; API requests at that path use the configured API access policy. Operation ID: `searchDefault`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 304 | Not modified for an ETag conditional GET. | — | See contract | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The path wins over query parameters. Only book and exclude may repeat. Filters override configured defaults; scripture references return scripture without applying full-text filters. GET bodies are not read. At a domain root, a request without query parameters serves the public documentation page; API requests at that path use the configured API access policy.", "operationId": "searchDefault", "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "304": { "description": "Not modified for an ETag conditional GET." }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters", "parameters": [ { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## POST /v3 Search using URL parameters, a JSON body, or both The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters. Operation ID: `searchDefaultPost`. | Parameter | In | Required | Type | Example / default | Description | | --- | --- | --- | --- | --- | --- | | `q` | query | No | string | faith hope | Search words or a scripture reference; ignored when the search is supplied in the path. | | `translation` | query | No | string | kjv | Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation. | | `words` | query | No | string | all | — | | `match` | query | No | string | whole_word | — | | `case_sensitive` | query | No | boolean | false | Accepts true/false, 1/0 or yes/no (case-insensitive). | | `scope` | query | No | string | bible | — | | `book` | query | No | array | 1 | Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections. | | `books` | query | No | string | John | Comma-separated book names or numbers; combined with repeated book values. | | `diacritics` | query | No | string | fold | fold/exact; compatibility aliases insensitive/sensitive are also accepted. | | `exclude` | query | No | array | darkness | Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each. | | `proximity` | query | No | integer | 1 | Intervening words, 0 to 100; requires words=all. | | `sort` | query | No | string | canonical | — | | `limit` | query | No | integer | 100 | — | | `offset` | query | No | integer | 0 | — | ### Request body Optional. Media type: `application/json`. Schema: `#/components/schemas/SearchRequest`. ```json { "limit": 25, "q": "faith hope", "words": "any" } ``` ### Responses | Status | Description | Media type | Schema | | --- | --- | --- | --- | | 200 | Search result, or scripture when the text is a reference. | application/json | #/components/schemas/SearchResult | | 400 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 401 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 404 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 405 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 413 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 415 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 429 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 500 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 502 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 503 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem | | 504 | RFC 9457 error. Existing access policies apply to API data requests. | application/problem+json | #/components/schemas/Problem |
Complete operation contract ```json { "description": "The same search implementation as GET. Path > query parameters > JSON body > configured defaults. A body is optional when q is provided in the URL. Scripture references return scripture without applying full-text filters.", "operationId": "searchDefaultPost", "requestBody": { "content": { "application/json": { "example": { "limit": 25, "q": "faith hope", "words": "any" }, "schema": { "$ref": "#/components/schemas/SearchRequest" } } }, "required": false }, "responses": { "200": { "$ref": "#/components/responses/SearchResult" }, "400": { "$ref": "#/components/responses/Problem" }, "401": { "$ref": "#/components/responses/Problem" }, "404": { "$ref": "#/components/responses/Problem" }, "405": { "$ref": "#/components/responses/Problem" }, "413": { "$ref": "#/components/responses/Problem" }, "415": { "$ref": "#/components/responses/Problem" }, "429": { "$ref": "#/components/responses/Problem" }, "500": { "$ref": "#/components/responses/Problem" }, "502": { "$ref": "#/components/responses/Problem" }, "503": { "$ref": "#/components/responses/Problem" }, "504": { "$ref": "#/components/responses/Problem" } }, "summary": "Search using URL parameters, a JSON body, or both", "parameters": [ { "description": "Search words or a scripture reference; ignored when the search is supplied in the path.", "in": "query", "name": "q", "schema": { "maxLength": 500, "minLength": 1, "type": "string" } }, { "description": "Translation abbreviation (case-insensitive); defaults to kjv and is overridden by a path translation.", "in": "query", "name": "translation", "schema": { "type": "string" } }, { "in": "query", "name": "words", "schema": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, { "in": "query", "name": "match", "schema": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" } }, { "description": "Accepts true/false, 1/0 or yes/no (case-insensitive).", "in": "query", "name": "case_sensitive", "schema": { "default": false, "type": "boolean" } }, { "in": "query", "name": "scope", "schema": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" } }, { "description": "Repeat book=Genesis&book=2 to select books; combined with books. At most 83 combined selections.", "explode": true, "in": "query", "name": "book", "schema": { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" }, "style": "form" }, { "description": "Comma-separated book names or numbers; combined with repeated book values.", "in": "query", "name": "books", "schema": { "description": "Comma-separated book names or numbers.", "type": "string" } }, { "description": "fold/exact; compatibility aliases insensitive/sensitive are also accepted.", "in": "query", "name": "diacritics", "schema": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" } }, { "description": "Repeat exclude=word to exclude multiple terms; at most 32 terms of 100 characters each.", "explode": true, "in": "query", "name": "exclude", "schema": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "style": "form" }, { "description": "Intervening words, 0 to 100; requires words=all.", "in": "query", "name": "proximity", "schema": { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" } }, { "in": "query", "name": "sort", "schema": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" } }, { "in": "query", "name": "limit", "schema": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" } }, { "in": "query", "name": "offset", "schema": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" } } ] } ```
## Component schemas Types, required properties, nested objects, constraints and examples below are copied directly from the contract. A property omitted from a schema’s `required` array is optional, even when examples include it. ### Criteria
View full Criteria schema ```json { "properties": { "books": { "items": { "type": [ "integer", "string" ] }, "type": "array" }, "case_sensitive": { "default": false, "type": "boolean" }, "diacritics": { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" }, "exclude": { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" }, "limit": { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" }, "match": { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" }, "offset": { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" }, "proximity": { "maximum": 100, "minimum": 0, "type": [ "integer", "null" ] }, "scope": { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" }, "sort": { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" }, "words": { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" } }, "required": [ "words", "match", "case_sensitive", "scope", "books", "diacritics", "exclude", "proximity", "sort", "limit", "offset" ], "type": "object" } ```
### Health
View full Health schema ```json { "properties": { "status": { "enum": [ "ok", "ready" ], "type": "string" } }, "required": [ "status" ], "type": "object" } ```
### Problem RFC 9457 problem document.
View full Problem schema ```json { "description": "RFC 9457 problem document.", "properties": { "code": { "type": "string" }, "detail": { "type": "string" }, "instance": { "type": "string" }, "retry_after": { "minimum": 0, "type": "integer" }, "status": { "type": "integer" }, "title": { "type": "string" }, "type": { "format": "uri", "type": "string" } }, "required": [ "type", "title", "status", "code", "detail", "instance" ], "type": "object" } ```
### Scripture One entry per chapter, keyed {translation}_{book}_{chapter}, with compact API translation metadata and selected verses. Verse source fields are retained; static chapter editorial is excluded.
View full Scripture schema ```json { "additionalProperties": { "properties": { "abbreviation": { "type": "string" }, "book_name": { "type": "string" }, "book_nr": { "type": "integer" }, "chapter": { "type": "integer" }, "direction": { "type": "string" }, "encoding": { "type": "string" }, "lang": { "type": "string" }, "language": { "type": "string" }, "name": { "type": "string" }, "ref": { "items": { "type": "string" }, "type": "array" }, "translation": { "type": "string" }, "verses": { "items": { "$ref": "#/components/schemas/Verse" }, "type": "array" } }, "required": [ "book_nr", "chapter", "verses" ], "type": "object" }, "description": "One entry per chapter, keyed {translation}_{book}_{chapter}, with compact API translation metadata and selected verses. Verse source fields are retained; static chapter editorial is excluded.", "type": "object" } ```
### SearchMatch Reference results omit score, occurrences and terms.
View full SearchMatch schema ```json { "description": "Reference results omit score, occurrences and terms.", "properties": { "book_nr": { "type": "integer" }, "chapter": { "type": "integer" }, "occurrences": { "minimum": 0, "type": "integer" }, "reference": { "type": "string" }, "score": { "type": "number" }, "terms": { "items": { "type": "string" }, "type": "array" }, "verse": { "type": "integer" } }, "required": [ "reference", "book_nr", "chapter", "verse" ], "type": "object" } ```
### SearchQuery Reference results omit criteria, sha, pagination, cache, analysis and cost. Filters are only applied to full-text searches.
View full SearchQuery schema ```json { "description": "Reference results omit criteria, sha, pagination, cache, analysis and cost. Filters are only applied to full-text searches.", "properties": { "analysis": { "properties": { "script": { "type": "string" } }, "type": "object" }, "cache": { "properties": { "checked_at": { "type": [ "number", "null" ] }, "stale": { "type": "boolean" } }, "type": "object" }, "cost": { "properties": { "deadline_seconds": { "type": "number" }, "expensive": { "type": "boolean" }, "work_units": { "minimum": 0, "type": "integer" } }, "type": "object" }, "criteria": { "$ref": "#/components/schemas/Criteria" }, "engine_version": { "type": "integer" }, "has_more": { "type": "boolean" }, "kind": { "enum": [ "search", "reference" ], "type": "string" }, "limit": { "minimum": 1, "type": "integer" }, "offset": { "minimum": 0, "type": "integer" }, "returned": { "minimum": 0, "type": "integer" }, "sha": { "type": [ "string", "null" ] }, "text": { "type": "string" }, "total": { "minimum": 0, "type": "integer" }, "translation": { "anyOf": [ { "$ref": "#/components/schemas/Translation" }, { "type": "string" } ] } }, "required": [ "text", "kind", "translation", "engine_version", "total", "returned" ], "type": "object" } ```
### SearchRequest All fields are optional when supplied in the path/query. GET uses query parameters. POST accepts query parameters, a JSON object, or both. Path > query > body > configured defaults; null body fields preserve a lower-priority value. book and books are combined.
View full SearchRequest schema ```json { "additionalProperties": false, "description": "All fields are optional when supplied in the path/query. GET uses query parameters. POST accepts query parameters, a JSON object, or both. Path > query > body > configured defaults; null body fields preserve a lower-priority value. book and books are combined.", "properties": { "book": { "anyOf": [ { "anyOf": [ { "type": [ "string", "integer" ] }, { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" } ] }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "books": { "anyOf": [ { "anyOf": [ { "type": "string" }, { "items": { "type": [ "string", "integer" ] }, "maxItems": 83, "type": "array" } ] }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "case_sensitive": { "anyOf": [ { "default": false, "type": "boolean" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "diacritics": { "anyOf": [ { "default": "fold", "enum": [ "fold", "exact", "insensitive", "sensitive" ], "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "exclude": { "anyOf": [ { "anyOf": [ { "maxLength": 100, "minLength": 1, "type": "string" }, { "items": { "maxLength": 100, "minLength": 1, "type": "string" }, "maxItems": 32, "type": "array" } ] }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "limit": { "anyOf": [ { "default": 100, "maximum": 100, "minimum": 1, "type": "integer" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "match": { "anyOf": [ { "default": "whole_word", "enum": [ "whole_word", "substring" ], "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "offset": { "anyOf": [ { "default": 0, "maximum": 10000, "minimum": 0, "type": "integer" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "proximity": { "anyOf": [ { "description": "Requires words=all.", "maximum": 100, "minimum": 0, "type": "integer" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "q": { "anyOf": [ { "maxLength": 500, "minLength": 1, "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "scope": { "anyOf": [ { "default": "bible", "enum": [ "bible", "old_testament", "new_testament", "deuterocanon" ], "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "sort": { "anyOf": [ { "default": "canonical", "enum": [ "canonical", "relevance" ], "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "translation": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." }, "words": { "anyOf": [ { "default": "all", "enum": [ "all", "any", "phrase" ], "type": "string" }, { "type": "null" } ], "description": "Null leaves the lower-priority value unchanged." } }, "type": "object" } ```
### SearchResult
View full SearchResult schema ```json { "properties": { "matches": { "items": { "$ref": "#/components/schemas/SearchMatch" }, "type": "array" }, "query": { "$ref": "#/components/schemas/SearchQuery" }, "results": { "$ref": "#/components/schemas/Scripture" } }, "required": [ "query", "results", "matches" ], "type": "object" } ```
### Translation
View full Translation schema ```json { "properties": { "abbreviation": { "type": "string" }, "direction": { "type": "string" }, "encoding": { "type": "string" }, "lang": { "type": "string" }, "language": { "type": "string" }, "translation": { "type": "string" } }, "type": "object" } ```
### Verse A source verse from the selected v3 data. Core fields are shared by v2 and v3. Optional v3 paragraph, tokens and spans are retained when present, as are other source fields and nested values.
View full Verse schema ```json { "additionalProperties": true, "description": "A source verse from the selected v3 data. Core fields are shared by v2 and v3. Optional v3 paragraph, tokens and spans are retained when present, as are other source fields and nested values.", "properties": { "chapter": { "type": "integer" }, "name": { "type": "string" }, "paragraph": { "description": "V3: true when this verse begins a paragraph; omitted when absent from the source.", "type": "boolean" }, "spans": { "description": "V3 annotations over token and word ranges, when supplied by the source.", "items": { "$ref": "#/components/schemas/VerseSpan" }, "type": "array" }, "text": { "type": "string" }, "tokens": { "description": "V3 word tokens in reading order, when supplied by the source.", "items": { "$ref": "#/components/schemas/VerseToken" }, "type": "array" }, "verse": { "type": "integer" } }, "required": [ "verse", "name", "text" ], "type": "object" } ```
### VerseSpan V3 source annotation. Token positions index the verse tokens array from zero, inclusive. Word positions count display words from one, inclusive; zero means unlocated.
View full VerseSpan schema ```json { "additionalProperties": true, "description": "V3 source annotation. Token positions index the verse tokens array from zero, inclusive. Word positions count display words from one, inclusive; zero means unlocated.", "properties": { "attrs": { "additionalProperties": { "type": "string" }, "type": "object" }, "span": { "type": "string" }, "tag": { "type": "string" }, "token_end": { "minimum": 0, "type": "integer" }, "token_start": { "minimum": 0, "type": "integer" }, "word_end": { "minimum": 0, "type": "integer" }, "word_start": { "minimum": 0, "type": "integer" } }, "required": [ "tag", "span", "token_start", "token_end", "word_start", "word_end" ], "type": "object" } ```
### VerseToken V3 word token. Word positions count whitespace-separated display words from one, inclusive; zero means unlocated. Additional source attributes are retained.
View full VerseToken schema ```json { "additionalProperties": true, "description": "V3 word token. Word positions count whitespace-separated display words from one, inclusive; zero means unlocated. Additional source attributes are retained.", "properties": { "gloss": { "type": "string" }, "lemma": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Lexical identifiers grouped by scheme, such as strong.", "type": "object" }, "morph": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Morphology codes grouped by scheme.", "type": "object" }, "morphSegmented": { "type": "boolean" }, "n": { "type": "string" }, "src": { "items": { "type": [ "integer", "string" ] }, "type": "array" }, "subType": { "type": "string" }, "token": { "type": "string" }, "type": { "type": "string" }, "variant": { "type": "boolean" }, "variantType": { "type": "string" }, "word_end": { "minimum": 0, "type": "integer" }, "word_start": { "minimum": 0, "type": "integer" }, "xlit": { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "description": "Transliterations grouped by scheme.", "type": "object" } }, "required": [ "token", "word_start", "word_end" ], "type": "object" } ```
## Authentication contract ```json { "security": [], "securitySchemes": { "bearer": { "description": "Required for API data only on token-only domains. Valid tokens retain unrestricted rate access.", "scheme": "bearer", "type": "http" } } } ``` See [access and tokens](/tokens/) for public usage and token requests. --- # Help bring Scripture to more people Get Bible grows through developers, testers, translators, churches and people who care about making the Bible accessible. You can help at the layer that fits your skills. ## Choose a way to help | Contribution | A useful first step | | --- | --- | | Build an integration | Fetch a passage with the [Bible API](/api/bible/) and connect it to an application you use | | Test the next app | Follow the [Get Bible app guide](/project/app/), run a development build and report reproducible issues | | Improve documentation | Use the Source link on any documentation page and propose a clear example, correction or explanation | | Develop a tool | Choose a [project](/project/), read its contribution and build instructions, and discuss your proposed change | | Improve study data | Explore the [builders](/project/builders/) and their input formats, provenance and verification rules | | Support operation and development | Visit [donations](/donate/) or contact the team about contributing resources | ## Discuss work before a large change Use the [support desk](https://git.vdm.dev/getBible/support) to discuss a project question or proposed direction. Link the relevant repository, describe what you want to achieve and explain which API or application it affects. This helps align work and avoid duplication. For code contributions, follow the target repository’s instructions, open a branch, test your changes and submit a pull request with a clear explanation of the behavior you changed. ## Make bug reports reproducible Include the project, release or commit, operating system, relevant API version, exact reproduction steps, expected result and actual result. For an API problem, include the request URL, HTTP status and a small sanitized response where useful. Never include a bearer token, password, personal bookmark backup or private user data in a public report. Report sensitive details privately to [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). ## Test the Get Bible app The app is still under development and uses API v2 today. Test installation, navigation, reading, search, offline behavior where supported, accessibility and the platforms you can run. The move to v3 and the integration of dictionaries and commentaries are intended next steps. See the [app guide](/project/app/) for its actual current capabilities and development setup. ## Keep Scripture accessible When you build with the APIs, preserve translation identity, text direction and relevant content metadata. Make interfaces work with keyboards, screen readers and small screens. Cache responsibly, respect rate-limit responses, and check the licensing and attribution of each work you distribute. Get Bible is a project of [trueChristian.church](https://trueChristian.church). For collaboration and other enquiries, email [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). --- # Support the mission Help Get Bible make Scripture accessible in more applications, communities and places. Donations support the continuing work of the project. ## Make a donation Use the bank details on this page when available. If bank details are not displayed, email [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church?subject=Supporting%20Get%20Bible) to request the current donation information directly from the team. You can use the same address to discuss a donation or ask how your support can help. Do not send banking passwords, card details or other credentials by email. ## Support through your skills You can also contribute code, testing, documentation, translation expertise or operational help. Visit [Get involved](/contribute/) to find a starting point, or explore the [projects](/project/) to see where your experience fits. ## Our affiliation Get Bible is a project of [trueChristian.church](https://trueChristian.church). Read [our mission](/about/) to understand what we are building and why. For public questions about the APIs, tools or applications, use the [Get Bible support desk](https://git.vdm.dev/getBible/support). --- # GetBible for AI applications Connect an AI application to **https://mcp.getbible.net/** using **Streamable HTTP**. Public access is free and requires no account or token. A single connection gives the application structured tools for scripture, reference lookup, full-text search, dictionaries, commentaries and public Bible topics. GetBible MCP is a read-only bridge to the [GetBible APIs](/api/). It retrieves published source material and keeps its provenance, native data and content rights. The same open-source Python package can run locally over stdio or be embedded in your own server. [Source repository](https://github.com/getbible/mcp) · [Python package](https://pypi.org/project/getbible-mcp/) · [Public support](https://git.vdm.dev/getBible/support). ## Connection details | Setting | Value | | --- | --- | | Connection name | GetBible | | Remote URL | `https://mcp.getbible.net/` | | Transport | Streamable HTTP | | Public authentication | No authentication | | Default Bible, query and search version | `v3` | | Other Bible, query and search version | Select `api_version: "v2"` explicitly | | Dictionaries, commentaries and bookmarks | `v1` | | Local command | `getbible-mcp --transport stdio` | | Python requirement | Python 3.11 or later | | Software license | GPL-2.0-or-later; content licenses remain separate | Use the remote URL exactly. The official service places the MCP protocol at the domain root, so adding `/mcp`, `/v2` or `/v3` creates a different URL. Upstream API versions belong in tool arguments. An MCP URL accepts protocol requests; it is not a REST path for a Bible reference. [Connection reference](https://github.com/getbible/mcp/blob/main/docs/CLIENTS.md). ## Connect in ChatGPT developer mode 1. Open ChatGPT **Settings → Security and login** and enable **Developer mode**. 2. Open **Plugins**, select the **plus** button, and create an MCP connection named **GetBible**. A useful description is “Read and search Bible translations, dictionaries, commentaries and public topics.” 3. Enter `https://mcp.getbible.net/`, select the public HTTP connection method, and choose **No Authentication**. 4. Create the connection and inspect the discovered tools. 5. Start a new conversation, open the tools or plus menu, and enable your GetBible connection. 6. Try: “Use GetBible to retrieve John 3:16–19 in the King James Version. Cite the returned source.” Developer mode availability depends on your account and workspace policy. After the server adds or changes tools, refresh the development connection and start a new conversation. These steps create a development connection; the repository's prepared plugin package does not establish approval in a public plugin directory. [Official OpenAI connection guide](https://developers.openai.com/plugins/deploy/connect-chatgpt) · [Developer mode documentation](https://developers.openai.com/api/docs/guides/developer-mode). The public ChatGPT connection uses no authentication. A GetBible administrator-issued bearer token is not an OAuth sign-in or a ChatGPT API-key login. Use optional tokens only in clients whose secure authentication settings support the header specified by the administrators. [Access and tokens](/tokens/). ## Useful things to ask - “Use GetBible to find the available Afrikaans translations, then show me Psalm 23 in the translation I choose.” - “Find verses containing faith and hope in Romans and First Corinthians, with references and links to their sources.” - “Retrieve John 1:1 using API v3. If its actual token data contains Strong's identifiers, look those up in a compatible dictionary and preserve the source attribution.” - “Show me which commentary modules cover John 3. Read the selected module's comments that include verse 16, including comments spanning several verses.” - “Find public topics connected to John 3 and retrieve the associated verses in KJV.” - “Help me design an application using GetBible, including translation rights, version selection and the cache refresh policy.” Specify the translation, source module and API version when they matter. A model should report an unavailable reference or missing commentary coverage instead of silently substituting another passage. Commentary is its author's interpretation; dictionary definitions and Bible quotations should remain distinguishable from the AI's explanation. ## What the connection covers | Service argument | Versions | Content | Website guide | | --- | --- | --- | --- | | `api` | `v2`, `v3` | Translation catalogs, books, chapters, complete scopes, indexes and checksums | [Bible API](/api/bible/) | | `query` | `v2`, `v3` | Individual, ranged and grouped Bible references | [Query API](/api/query/) | | `search` | `v2`, `v3` | Full-text and reference search, filters, ranking, pagination and read-only POST | [Search API](/api/search/) | | `dictionaries` | `v1` | Module discovery, indexes, entries, lexical links, provenance and checksums | [Dictionaries](/api/dictionaries/) | | `commentaries` | `v1` | Module discovery, coverage, introductions, comments and checksums | [Commentaries](/api/commentaries/) | | `bookmarks` | `v1` | Public topics, verse coordinates, localized names and checksums | [Bookmarks](/api/bookmarks/) | There are nine versioned OpenAPI contracts behind these six service names. The generic tools expose the complete packaged contracts, while convenience tools simplify common tasks. The data is not flattened to a lowest common denominator: v3 tokens, spans, paragraphs and additional native fields remain available. Package releases and upstream API versions are independent. ## Tools GetBible exposes the following 13 tools. Read the connection's discovered schemas before generating calls for exact parameter types, defaults and validation. Both Streamable HTTP and local stdio provide the same tool capabilities. [Tool implementation](https://github.com/getbible/mcp/blob/main/src/getbible_mcp/server.py). | Tool | Purpose and inputs | | --- | --- | | `discover_apis` | List contracts, source URLs and resource URIs. Optional `service` and `api_version` narrow discovery. | | `describe_api_operation` | Require `service` and `api_version`; omit `operation_id` to list operations, or supply it for exact inputs and response schemas. | | `call_api_operation` | Require `service`, `api_version`, `operation_id`; send named path/query inputs in `parameters` and a documented search POST object in `body`. | | `list_translations` | Retrieve the selected version's catalog, including language and publisher metadata. `api_version` defaults to `v3`. | | `list_books` | Discover numbers, localized names and hashes. Defaults to `translation: "kjv"` and `api_version: "v3"`. | | `list_chapters` | Discover chapter identifiers and hashes for a required `translation` and positive integer `book`. | | `get_scripture` | Read a chapter, book or translation with before/after hash consistency checks. Provide `book` and `chapter` for a chapter; omit `chapter` for a book; omit both for a translation. | | `query_verses` | Resolve `references` of 1–512 characters. Translation defaults to KJV; explicit versions prevent accidental mixing. | | `search_verses` | Search 1–500 characters of text with typed filters, pagination and version selection. | | `search_dictionary_entries` | Find entry identifiers in a freshly fetched dictionary index. Required `dictionary` and `query`; `match` is `exact`, `prefix` or `contains`; `limit` is 1–100, default 20; `offset` starts at 0. | | `get_hash` | Read a scope's Bible SHA-1. `kind` is `translation`, `book` or `chapter`; provide the coordinates required by that scope. | | `get_hash_manifest` | Read bulk hashes. `kind` is `all_translations`, `translation` or `book`; provide applicable translation/book inputs. | | `check_for_updates` | Compare 1–100 saved scope records. Each item carries its own `api_version`, coordinates and actual `current_hash`; the result describes required invalidation. | All these tools are read-only and idempotent. Search POST submits a lookup; it does not publish content. MCP cannot edit a Bible, upload a translation or change a user's personal bookmarks. Generic operations accept declared contract routes, rather than arbitrary destination URLs. ### Search filters | Argument | Supported values or bounds | | --- | --- | | `words` | `all` (default), `any`, `phrase` | | `match` | `whole_word` (default), `substring` | | `case_sensitive` | Boolean, default `false` | | `diacritics` | `fold` (default), `exact`, `insensitive`, `sensitive` | | `scope` | `bible` (default), `old_testament`, `new_testament`, `deuterocanon` | | `book` | Array of book numbers or names; at most 83 items | | `books` | Comma-separated book selection | | `exclude` | Array of excluded terms; at most 32 items | | `proximity` | Integer 0–100; requires `words: "all"` | | `sort` | `canonical` (default), `relevance` | | `limit` | Integer 1–100, default 100 | | `offset` | Integer 0–10,000, default 0 | A search recognized as a Bible reference may follow reference lookup behavior instead of ordinary full-text filters. Inspect the native response and its pagination. Do not assume that an empty or truncated page represents the entire dataset. ## Copyable tool examples These objects describe a tool and its arguments for an MCP client or Inspector. They are not complete JSON-RPC requests. Your client discovers the protocol and supplies the appropriate request envelope. ### Retrieve a passage ```json { "tool": "query_verses", "arguments": { "translation": "kjv", "references": "John 3:16-19; 1 John 3:16-19,22", "api_version": "v3" } } ``` ### Retrieve a chapter with its checksum ```json { "tool": "get_scripture", "arguments": { "translation": "kjv", "book": 43, "chapter": 3, "api_version": "v3" } } ``` ### Search within selected books ```json { "tool": "search_verses", "arguments": { "search": "faith hope", "translation": "kjv", "api_version": "v3", "words": "any", "book": [45, 46], "sort": "relevance", "limit": 25, "offset": 0 } } ``` Preserve the native `query`, `results` and `matches` envelope. For full-text pages, inspect `query.has_more` and retain the same filters while increasing the offset by the chosen page size. ### Inspect and call a complete API operation ```json { "tool": "describe_api_operation", "arguments": { "service": "search", "api_version": "v3", "operation_id": "searchTranslationPost" } } ``` ```json { "tool": "call_api_operation", "arguments": { "service": "search", "api_version": "v3", "operation_id": "searchTranslationPost", "parameters": {"translation": "kjv"}, "body": {"q": "faith hope", "words": "all", "proximity": 10, "limit": 25} } } ``` Operation identifiers are scoped to a service and version. Preserve the returned `input_name` and JSON types. Repeated query values are arrays; a colliding path/query parameter uses the plain path name and `query.` prefix for the query input. For search POST, a query parameter overrides the body value and a path value overrides both. POST results use `no-store`. [More source examples](https://github.com/getbible/mcp/blob/main/site/v2/examples.md). ## Dictionaries: discover, match, retrieve Start with `call_api_operation` using `service: "dictionaries"`, `api_version: "v1"`, `operation_id: "listDictionaries"`. Choose an actual returned `dictionaries[].id` by source, language and purpose. Read `getDictionaryMetadata` with that ID before presenting definitions; retain the module's attribution, license, distribution notes and provenance. For a discovered `strongsgreek` module and an actual Strong's token `G3056`, these calls locate and retrieve the entry: ```json { "tool": "search_dictionary_entries", "arguments": { "dictionary": "strongsgreek", "query": "G3056", "match": "exact", "limit": 20, "offset": 0 } } ``` ```json { "tool": "call_api_operation", "arguments": { "service": "dictionaries", "api_version": "v1", "operation_id": "getDictionaryEntry", "parameters": {"dictionary": "strongsgreek", "entry": "G3056"} } } ``` Pass the exact identifier returned by the index. An entry filename cannot safely be guessed from a headword; several definitions can share a key and use occurrence suffixes such as `--2`. The search helper matches headwords, IDs and aliases, not the full text of definitions. Text matching ignores case and combining accents, while identifier matching preserves exact case. Follow `next_offset` with unchanged inputs until no further relevant results remain. For integrations that need a complete dictionary index, `getDictionaryIndex` through `call_api_operation` returns the selected module's full index. Account for its size when processing it in your application. Prefer `search_dictionary_entries` for individual word lookups, and do not claim no match after seeing only a truncated index. There is no static dictionary `?q=` route, and `search_verses` searches scripture rather than dictionary definitions. Preserve native Strong's tokens, including Hebrew `H0` prefixes such as `H0430`. An English word alone does not establish its original-language lemma. Use the passage's actual token data, retain ambiguous identifiers, and never invent annotations missing from the source. Optional `see_also` and `backlinks` fields describe directed links within a module. Fetch relevant linked entries by their supplied IDs, retain link direction, and stop cycles with a visited set. These links are not automatically proof of synonymy or etymology. Scripture `references` are separate: resolve their canonical `ref` through `query_verses` in the selected Bible version and translation. [Study workflow source](https://github.com/getbible/mcp/blob/main/docs/STUDY_WORKFLOWS.md). ## Commentaries: check coverage first Use `listCommentaries`, choose a returned module ID, and read `getCommentaryMetadata`. Then call `getCommentaryBooks` to discover the actual book and chapter coverage. Do not assume every module covers all Bible books or continuous chapters. If the discovered `mhc` module includes book 43, chapter 3: ```json { "tool": "call_api_operation", "arguments": { "service": "commentaries", "api_version": "v1", "operation_id": "getCommentaryChapter", "parameters": {"commentary": "mhc", "book": 43, "chapter": 3} } } ``` To select comments on verse 16, include every entry whose `verses` array contains 16; if that array is absent, compare `verse`. A range anchored at verse 14 may cover verse 16. Preserve multiple matching comments and their original text, ranges, `osis` and references. A discovered chapter 0 is a book introduction. Verse 0 within a chapter is introductory content. Keep both as context without renumbering them. Cross-chapter comments may occur in each affected chapter; avoid repeating the same quotation while retaining the full coverage. Fetch Bible text separately with `query_verses` and cite the commentary module and the returned `source.url`. ## Public topics and bookmarks ```json { "tool": "call_api_operation", "arguments": { "service": "bookmarks", "api_version": "v1", "operation_id": "getTopics" } } ``` ```json { "tool": "call_api_operation", "arguments": { "service": "bookmarks", "api_version": "v1", "operation_id": "getChapter", "parameters": {"book": 43, "chapter": 3} } } ``` The bookmark dataset supplies topics and verse coordinates, not scripture text. Resolve selected coordinates through the Bible or query API in the reader's chosen translation. These are public associations; the MCP does not read or write a person's private bookmarks. ## Run the Python package locally The Python distribution is named `getbible-mcp`; its import package is `getbible_mcp`. Use Python 3.11 or later. An isolated environment gives the MCP client an explicit executable and keeps dependencies separate from system Python. ```bash python3 -m venv .venv .venv/bin/python -m pip install --upgrade pip .venv/bin/python -m pip install getbible-mcp .venv/bin/getbible-mcp --version .venv/bin/getbible-mcp --transport stdio ``` This installs the published package and its compatible dependencies. For production applications, record the tested release in your dependency lockfile and review [package releases](https://pypi.org/project/getbible-mcp/#history) before updating. Running the stdio command directly waits for protocol input; it is normally launched by an MCP host. For a per-user executable managed by pipx: ```bash pipx install getbible-mcp command -v getbible-mcp ``` In a client using the conventional `mcpServers` configuration, a PATH-resolved executable looks like this: ```json { "mcpServers": { "getbible": { "command": "getbible-mcp", "args": ["--transport", "stdio"] } } } ``` If a desktop host cannot resolve that command, use the absolute executable path returned by `command -v` or by `realpath .venv/bin/getbible-mcp` for a virtual environment. The host's working directory and PATH may differ from your terminal. Let it launch the installed command directly. Standard output is reserved for MCP messages; diagnostics belong on standard error. Local stdio still reads the configured upstream GetBible services. It does not download a full offline Bible automatically. Ordinary Python applications that want scripture without an MCP host can use the [Librarian](/project/librarian/) or call the REST APIs. ## Call the remote MCP from Python Installing `getbible-mcp` also installs its supported official Python MCP SDK. This example uses the SDK's `Client` interface and delegates discovery, protocol metadata and transport handling to the library. ```bash python3 -m venv .venv .venv/bin/python -m pip install getbible-mcp ``` Save the following as `query_getbible.py` and run `.venv/bin/python query_getbible.py`: ```python import asyncio import json from mcp import Client from mcp.client.streamable_http import streamable_http_client async def main() -> None: async with Client( streamable_http_client("https://mcp.getbible.net/"), cache=None ) as client: result = await client.call_tool( "query_verses", { "translation": "kjv", "references": "John 3:16-19", "api_version": "v3", }, ) if result.is_error: raise RuntimeError("GetBible returned an MCP tool error; inspect the result in your client.") if result.structured_content is None: raise RuntimeError("GetBible returned no structured result.") print(json.dumps(result.structured_content, ensure_ascii=False, indent=2)) if __name__ == "__main__": asyncio.run(main()) ``` An HTTP 200 response alone does not establish a successful tool lookup: check the MCP error flag. Preserve the structured result's native `data`, `source` and `cache` fields. Applications should also handle transport exceptions and rate limits. [Python connection example](https://github.com/getbible/mcp/blob/main/docs/CLIENTS.md). ## Host or embed your own MCP server The package can expose Streamable HTTP locally: ```bash .venv/bin/getbible-mcp --transport streamable-http ``` With default settings, this listens at `http://127.0.0.1:3100/mcp`. This is the package's local default, distinct from the official remote root endpoint. Supply that exact URL to a local Inspector. Your application owns HTTPS termination, process management and public hosting. For direct Python embedding, save this as `serve_getbible.py` after installing the package: ```python import uvicorn from getbible_mcp import create_app app = create_app(path="/mcp") if __name__ == "__main__": uvicorn.run(app, host="127.0.0.1", port=3100) ``` Run it with `.venv/bin/python serve_getbible.py`. `create_app` returns an ASGI application; `create_runtime` additionally exposes the server, upstream client and resolved settings. Importing the package creates no default client or network request. If mounting the app inside another ASGI application, the parent must enter `child.router.lifespan_context(child)` during its own lifespan so startup and HTTP-client cleanup run correctly. [Architecture and embedding](https://github.com/getbible/mcp/blob/main/docs/ARCHITECTURE.md). ### Trusted upstream configuration | Environment variable | Default upstream | | --- | --- | | `GETBIBLE_API_V2_BASE` | `https://api.getbible.net/v2` | | `GETBIBLE_API_V3_BASE` | `https://api.getbible.net/v3` | | `GETBIBLE_QUERY_V2_BASE` | `https://query.getbible.net/v2` | | `GETBIBLE_QUERY_V3_BASE` | `https://query.getbible.net/v3` | | `GETBIBLE_SEARCH_V2_BASE` | `https://search.getbible.net/v2` | | `GETBIBLE_SEARCH_V3_BASE` | `https://search.getbible.net/v3` | | `GETBIBLE_DICTIONARIES_BASE` | `https://dictionaries.getbible.net/v1` | | `GETBIBLE_COMMENTARIES_BASE` | `https://commentaries.getbible.net/v1` | | `GETBIBLE_BOOKMARKS_BASE` | `https://bookmarks.getbible.net/v1` | Mirror URLs must implement the corresponding versioned contract and end in its version path. These are trusted operator settings; a tool caller cannot redirect requests to a different host. Other controls include `GETBIBLE_MCP_BIND_HOST` (default `127.0.0.1`), `GETBIBLE_MCP_BIND_PORT` (3100), `GETBIBLE_MCP_REQUEST_TIMEOUT` (20 seconds), `GETBIBLE_MCP_MAX_RESPONSE_BYTES` (33,554,432 bytes), and `GETBIBLE_MCP_MAX_PARALLEL_HASH_CHECKS` (10). Configure host and origin allowlists for a custom public deployment with `GETBIBLE_MCP_ALLOWED_HOSTS` and `GETBIBLE_MCP_ALLOWED_ORIGINS`. These memory, timeout and security settings do not change upstream access quotas. [Configuration reference](https://github.com/getbible/mcp/blob/main/docs/OPERATIONS.md). ## Discovery resources and integration prompt | MCP resource or prompt | Purpose | | --- | --- | | `getbible://docs/api` | Complete integration guidance | | `getbible://docs/cache-policy` | Expiry, hashes and synchronization | | `getbible://docs/usage-policy` | Public access, limits and content rights | | `getbible://docs/study-workflows` | Dictionary and commentary procedures | | `getbible://openapi/{service}/{version}` | A complete bundled OpenAPI document | | `design_getbible_integration` | Prompt for planning an integration | For example, `getbible://openapi/search/v3` identifies the search v3 contract. These are MCP resource identifiers, read through the connected client rather than a normal web browser. The website's corresponding REST guides link to the upstream OpenAPI JSON documents as well. ## Freshness and content integrity The MCP does not keep an upstream result cache and recommends using query and search responses directly. If your application caches an eligible response, its key must include service, version, operation and every effective input, including translation, filters and page offset. Honor `Cache-Control`, `Age`, response dates and `Expires`. A shorter remaining lifetime wins. `no-store` prohibits persistence; `no-cache` requires revalidation. Never retain content beyond **30 days** without refreshing it. An unchanged checksum does not restart that lifetime. Bible `.sha` files use SHA-1. Dictionary and commentary `hashes.json` manifests and bookmark `checksums.json` use SHA-256. Compare the checksum belonging to the exact scope or document path. A changed translation invalidates its cached books and chapters; a changed book invalidates its chapters. Fetch replacements into temporary storage and replace the old record atomically. `get_scripture` checks the scope hash before and after retrieving JSON, retrying once if publication changes during the read. This consistency check is separate from verifying downloaded bytes and from publisher identity. Query results do not carry an invented chapter-hash envelope. Search `query.sha` describes the source translation, not the result payload. [Complete cache policy](https://github.com/getbible/mcp/blob/main/site/v2/cache-policy.md). ## Test a connection Use MCP Inspector to discover and call tools with the actual transport: ```bash npx @modelcontextprotocol/inspector@latest ``` Select Streamable HTTP and enter `https://mcp.getbible.net/`. For an installed local package: ```bash npx @modelcontextprotocol/inspector@latest \ .venv/bin/getbible-mcp --transport stdio ``` Discover tools, call `discover_apis`, inspect an operation schema, query a known passage, and verify errors for invalid inputs. The repository includes a bounded, explicit endpoint probe for contributors: ```bash git clone https://github.com/getbible/mcp.git getbible-mcp cd getbible-mcp python3 -m venv .venv .venv/bin/python -m pip install -r requirements-dev.txt .venv/bin/python -m pip install --no-deps -e . .venv/bin/python scripts/check_endpoint.py .venv/bin/python scripts/check_endpoint.py --upstreams ``` The optional upstream check performs representative read-only requests across all nine contracts. It is not a full production load test. Use `--expect-version` only when checking a known deployment target. A browser GET may wait on a protocol event stream, and `/healthz` only identifies the running package; actual MCP calls establish whether lookups work. ## Troubleshooting | Symptom | What to check | | --- | --- | | Connection fails at `/mcp` or `/v3` | The official URL is `https://mcp.getbible.net/`. Remove added path segments. | | Browser request hangs | Use an MCP client or Inspector; the endpoint is a protocol service and may stream. | | A documented tool is missing | Refresh the connection's tools and metadata, confirm the tool is enabled in your client, then start a new conversation. | | HTTP 429 | Honor `Retry-After`, back off and reduce concurrency. See [access policy](/tokens/). | | HTTP 200 but no useful data | Inspect MCP `isError` and the structured error; transport success does not mean the upstream lookup succeeded. | | Invalid or unresolved reference | Correct the reference or translation. No fallback passage should be substituted. | | Dictionary term not found | Discover the right source/language, search its index, retain exact IDs and check all relevant pages. There is no definition-text search endpoint. | | Commentary misses a requested verse | Inspect actual coverage and every entry's `verses` array, including ranges anchored at earlier verses. | | Local command not found | Configure the absolute installed executable path in the MCP host and confirm Python 3.11+. | | Local protocol output is malformed | Keep application logs on stderr and stdout exclusively for MCP messages. | | Embedded application fails at startup | Run the child ASGI lifespan from the parent application. | | Whole module or translation is too large | Prefer chapters or individual entries and respect the configured response-size limit. | For public help with any GetBible project, use the [single support desk](https://git.vdm.dev/getBible/support). For credentials or private questions, email [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). Preserve translation and module licenses when displaying or redistributing content; the MCP software license does not relicense those materials. --- # Tools with a shared purpose Explore the libraries, applications, integrations and builders that bring Get Bible into everyday use. Some are deployed applications, some are developer utilities, and some are projects you can help test and advance. ## Start at the right layer | You want to… | Start with | | --- | --- | | Work with Bible data in Python | [Librarian](/project/librarian/) | | Embed Scripture in a website | [JavaScript loader](/project/loader/) | | Add Bible reading to Joomla | [Joomla package, component and plugin](/project/joomla/) | | Run a Telegram Bible experience | [Robot](/project/robot/) | | Help build the cross-platform app | [Get Bible app](/project/app/) | | Explore an existing desktop client | [Desktop](/project/desktop/) | | Explore the web reader project | [Web app](/project/app-getbible-life/) | | Work with local SWORD modules | [GetBibleSword](/project/getbiblesword/), [SWORD extension](/project/sword/), [Scripture](/project/scripture/) | | Understand how API data is produced | [API builders](/project/builders/) | | Connect an AI application | [MCP documentation](/mcp/) | ## The next Get Bible app The [Get Bible app](/project/app/) is under development. It uses API v2 today, with v3 and study-resource integration planned as future work. The ambition is to bring it to app stores and desktops. Help by building it, testing the current experience and contributing to the next stage. The existing desktop and web projects remain separately documented. Their maturity, build process and feature set are described in their own guides; they are not interchangeable releases of the developing app. ## Reuse and contribute Each project guide links to its repository and explains its installation, configuration, use and requirements. Follow the license and contribution instructions of the specific project. When working with Bible or study content, also preserve the rights and attribution information of the underlying work. All public questions go to the [central support desk](https://git.vdm.dev/getBible/support). To help with development, testing or documentation, see [Get involved](/contribute/). --- # GetBible App — help build the native reader The GetBible App is the cross-platform Flutter project for Android, iOS, web, Windows, macOS, and Linux. It brings the GetBible reader experience into native controls with local Scripture caching and study data. [Repository](https://github.com/getbible/app) · [Support](https://git.vdm.dev/getBible/support) · [All projects](/project/) **Under development.** The app currently uses Bible API v2. Store publication, complete feature parity, and physical-device verification are still ahead. Bible API v3, dictionaries, commentaries, and broader study integration are future priorities, not released features. Developers and testers can help move the project toward those goals. ## Supported targets | Target | Development/test command | Distribution output | |---|---|---| | Android | `flutter run -d android` | APK or Play Store AAB | | iOS/iPadOS | `flutter run -d ios` | Xcode archive/App Store package | | Web | `flutter run -d chrome` | Static files in `build/web` | | Windows | `flutter run -d windows` | Windows runner bundle | | macOS | `flutter run -d macos` | macOS application bundle | | Linux | `flutter run -d linux` | Linux runner bundle | ## Requirements - Flutter stable 3.44.6 or newer - Dart 3.12.2 or newer - Android Studio/SDK for Android builds - macOS with Xcode for iOS builds ## Start developing ```bash git clone https://github.com/getbible/app.git cd app flutter doctor -v flutter pub get flutter run ``` The application ID and iOS bundle ID are `life.getbible.mobile`. No API key is required for the public GetBible API. ## Test the application The fastest interactive test is the web target: ```bash flutter pub get flutter run -d chrome ``` For Android, enable developer mode/USB debugging or start an emulator, then run `flutter devices` followed by `flutter run`. GitHub Actions also publishes two downloadable artifacts after a successful `main` build: - `getBible-live-debug-apk` for installation on an Android test device. - `getBible-live-web`, containing the compiled static web application. Open the successful workflow run’s **Artifacts** section to download them. Web files must be served by an HTTP server; opening `index.html` directly is not supported. A permanent GitHub Pages preview can be enabled later after the repository is public and Pages is configured to deploy from GitHub Actions. **pub.dev is not an application testing service.** It is Dart and Flutter’s public package registry. This application is not intended to be published there as a reusable package. Test builds belong in GitHub Actions artifacts, GitHub Pages, TestFlight, Play Console internal testing, or locally attached Flutter devices. ## Quality checks ```bash dart format --output=none --set-exit-if-changed . flutter analyze flutter test flutter build apk --debug ``` CI runs the same checks and uploads an unsigned debug APK plus a compiled web build. Consult [testing](https://github.com/getbible/app/blob/HEAD/docs/TESTING.md) before merging reader, storage, backup, or cache changes. ## Release builds Android: ```bash flutter build apk --release flutter build appbundle --release ``` iOS, on macOS: ```bash flutter build ios --release --no-codesign ``` Signing keys and provisioning profiles must never be committed. Complete instructions are in [deployment and distribution](https://github.com/getbible/app/blob/HEAD/docs/DEPLOYMENT.md). ## Architecture The code is divided into domain models/contracts, data adapters, application state, services, and presentation. SQLite is accessed through Drift's executor; network responses are parsed into strongly typed immutable models. Opened chapters are cached, their SHA endpoints are checked, and usable cached Scripture remains available when verification cannot reach the network. ```text lib/ application/ lifecycle and reader state core/ errors, JSON validation, starter groups data/api/ GetBible API v2 client data/database/ local SQLite schema and platform executors data/repositories/ cache and persistence implementations domain/models/ versioned data contracts domain/repositories/abstract persistence contracts presentation/ native Flutter reader UI services/ backup, search, Markdown ``` See [architecture](https://github.com/getbible/app/blob/HEAD/docs/ARCHITECTURE.md) and [data contracts](https://github.com/getbible/app/blob/HEAD/docs/DATA_AND_BACKUPS.md). ## Privacy Notes, markings, preferences, cached Scripture, and reading position are stored locally. The app has no accounts, advertising, analytics, or tracking. Network traffic is limited to resources required for Scripture and daily-passage retrieval. See [privacy policy draft](https://github.com/getbible/app/blob/HEAD/docs/PRIVACY.md). ## Branding All platform launchers, favicons, splash artwork, window icons, and in-app identity use the approved GetBible artwork in `assets/branding/`. CI validates a committed checksum manifest so generated Flutter template icons cannot silently return. The source artwork must be replaced only with explicitly approved GetBible assets. ## Documentation index - [Agent operating guide](https://github.com/getbible/app/blob/HEAD/AGENTS.md) - [Architecture](https://github.com/getbible/app/blob/HEAD/docs/ARCHITECTURE.md) - [API and cache workflow](https://github.com/getbible/app/blob/HEAD/docs/API_AND_CACHE.md) - [Data and backup compatibility](https://github.com/getbible/app/blob/HEAD/docs/DATA_AND_BACKUPS.md) - [Feature-parity ledger](https://github.com/getbible/app/blob/HEAD/docs/FEATURE_PARITY.md) - [Web-to-Flutter parity contract](https://github.com/getbible/app/blob/HEAD/docs/WEB_FLUTTER_PARITY.md) - [Source-backed parity audit (July 2026)](https://github.com/getbible/app/blob/HEAD/docs/PARITY_AUDIT_2026-07.md) - [Brand assets](https://github.com/getbible/app/blob/HEAD/docs/BRANDING.md) - [Testing and QA](https://github.com/getbible/app/blob/HEAD/docs/TESTING.md) - [Deployment and distribution](https://github.com/getbible/app/blob/HEAD/docs/DEPLOYMENT.md) - [Release checklist](https://github.com/getbible/app/blob/HEAD/docs/RELEASE_CHECKLIST.md) - [Privacy policy draft](https://github.com/getbible/app/blob/HEAD/docs/PRIVACY.md) ## License The existing repository license is retained in [LICENSE](https://github.com/getbible/app/blob/HEAD/LICENSE). Scripture translations remain subject to the license and copyright metadata returned by GetBible API v2; the application license does not relicense translation content. ## Feature-parity ledger Status meanings: **Implemented** exists in source; **Partial** needs remaining UX/integration work; **Pending verification** requires platform/device confirmation. | Area | Status | Implementation / remaining gate | |---|---|---| | Typed API v2 and dynamic indexes | Implemented | `GetBibleApiClient`, `CachedBibleRepository` | | SQLite notes/markings/preferences/cache | Implemented | `LocalDatabase` and SQL repositories | | SHA verification and offline chapter fallback | Implemented | Three freshness states shown by reader | | Native line/paragraph reader | Implemented | `ReaderScreen`; no WebView | | Translation/book/chapter selection | Implemented | Dynamic selectors | | Last passage persistence | Implemented | Exact verse restoration/centering needs expanded widget integration | | Swipe and cross-book navigation | Implemented core | Shared cross-book turn operation, horizontal swipe, Alt+arrow shortcuts, arrows/mobile row, and tested deliberate double-boundary intent; device gesture QA remains | | Deep links/shareable links | Partial | Parser exists; GoRouter/platform association needs integration tests | | RTL and appearance modes | Implemented | Device selection behavior still requires QA | | Contextual selection toolbar | Partial | Verse-number and native selected-text menus expose the active group, searchable compact all-group palette, note/removal actions, and preserve native copy controls; exact overlay-positioning widget tests remain | | Whole/text markings and overlap rules | Implemented core | Whole-verse recolor/removal, selected-range marking/removal, overlap rendering, active group memory, searchable Study card grid, per-marking open/delete, and add/edit/recolor/delete group UI exist; full journey tests and backup UI remain | | Inline notes | Implemented core | Add/edit/delete editor opens under its verse and saved note folds inline; keyboard-shortcut and full widget journey tests remain | | Search modes and isolate execution | Partial | Full filter UI, total-result count, isolate search, and progressive 20-result rendering exist; cooperative corpus parsing, match highlighting, seven-second arrival emphasis, and cancellation tests remain | | Website-compatible backups | Implemented core | Model validation/merge exists; native file picker/share UI remains | | Markdown generation | Implemented core | Native copy/share/save UI remains | | Complete website localization | Partial | All 69 compact website locale packs are mirrored and contract-tested; Flutter runtime message loading and full widget adoption remain | | Approved GetBible branding | Implemented | Supplied artwork is installed for Android, iOS, macOS, Windows, Linux, web, splash, and the reader header; CI verifies exact hashes | | Accessibility | Partial | Safe area, semantics, scaling foundations; full focus/screen-reader audit remains | | CI | Implemented | Format, analyze, tests, Android debug artifact | | Signed store distribution | External | Requires Apple/Google credentials and store review | This ledger is intentionally candid. “Ready for distribution” means every Partial row applicable to mobile is completed, automated checks pass, release artifacts build, and the manual QA matrix is signed off. ## GetBible API and cache workflow Base URL: `https://api.getbible.net/v2`. | Resource | Endpoint | Cache behavior | |---|---|---| | Translations | `/translations.json` | Refresh after seven days; changed translation SHA invalidates subordinate indexes/corpus. | | Books | `/{translation}/books.json` | Dynamic; changed book SHA invalidates that book. | | Chapters | `/{translation}/{book}/chapters.json` | Dynamic; changed chapter SHA invalidates only that chapter. | | Chapter | `/{translation}/{book}/{chapter}.json` | Cached after opening. | | Chapter SHA | `/{translation}/{book}/{chapter}.sha` | Checked before using a network-verified cached chapter. | | Full translation | `/{translation}.json` | Download only for deliberate search/offline workflows; bind cache to translation SHA. | Freshness states are `fresh`, `cachedVerified`, and `cachedUnverified`. A failed network/hash check must not erase a valid cached chapter. Malformed cached JSON is discarded. Storage bookkeeping failure must not hide usable Scripture already fetched or verified. Chapter activation uses the MCP consistency sequence: read the chapter SHA, download and fully parse the chapter, then read the SHA again. If the source rotated, retry once from the new SHA. Only a payload bracketed by identical hashes is activated. SQLite's single-row upsert is the atomic activation point; the previous row remains the last-known-good value on any preceding failure. API responses must remain dynamically discovered; never hard-code available translations, book names, chapter counts, or verse counts. Timeouts, non-2xx responses, malformed UTF-8/JSON, and empty resources are typed failures. ## Support and source documentation For questions about this project, installation, unexpected output, or contributing, use the [single GetBible support desk](https://git.vdm.dev/getBible/support). Include the project, installed release or commit, operating system, relevant API version, and a minimal reproduction. General enquiries can be sent to [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). This guide follows the [repository README](https://github.com/getbible/app/blob/HEAD/README.md) and [FEATURE PARITY](https://github.com/getbible/app/blob/HEAD/docs/FEATURE_PARITY.md), [API AND CACHE](https://github.com/getbible/app/blob/HEAD/docs/API_AND_CACHE.md). Scripture and study resources retain their own source licences; a software licence does not relicense the texts. --- # getBible.Life — browser Bible reader Read the Bible in a browser, create notes and markings, search translations locally, and export passages as Markdown. The live reader is [app.getbible.life](https://app.getbible.life/). [Repository](https://github.com/getbible/app.getbible.life) · [Support](https://git.vdm.dev/getBible/support) · [All projects](/project/) This React and TypeScript application currently consumes GetBible API v2. It is the behavior and data-contract reference for the native [GetBible App](/project/app/) under development. Its deployment workflow belongs to its own repository; the documentation website is a separate GitHub Pages project. A production-ready, browser-native Bible reader built with React 19, Next.js/Vinext, TypeScript, and the public [GetBible API v2](https://api.getbible.net/v2/translations.json). ## Features - Every translation, language, book, chapter, and verse is discovered from the API; no Bible structure is hard-coded. - Shareable URLs and browser back/forward navigation. - Canonical passage paths such as `/KJV/Ephesians/5`, including direct-link reloads and automatic conversion of restored/query-based passages to friendly URLs. - Previous/next paging across book boundaries, `Alt` + arrow keyboard navigation, and mobile swipe navigation. - Deliberate continuous reading: a second mouse-wheel or vertical touch-drag gesture at a boundary opens the adjacent chapter, preventing accidental paging. - Minimal full-page reading with a compact header and collapsible passage navigation. - Selectable light and dark reading palettes, including pure black, warm brown, charcoal, and midnight themes, plus adjustable scripture size, RTL support, and accessible controls. - Persistent markings: click a verse number to mark a whole verse, or select a word or phrase to mark only that text. - Custom marking colors and category names, with marking groups listed first and the selected group's color retained as the next marking default. - Portable JSON backup and merge-import for markings, with duplicate prevention and safe bulk deletion. - Long-term verse notes with Bible-order navigation; backups include notes, markings, and custom color groups. - Verse notes and whole-verse markings follow the canonical book/chapter/verse across translations; selected word and phrase markings remain translation-specific. - The visible reading position is remembered down to the verse and restored on the next visit. - First-time readers open the daily Scripture in King James Version; clicking `getBible.Life` returns to that day’s cached verse in KJV. - Full-screen-width reading by default, optional page width, nine selectable reading fonts, edge-to-edge mobile reading, and touch-sized controls. - A glasses button opens the current chapter as Markdown with an H1 chapter heading, valid ordered-list verses, Copy and Download `.md` actions, and the translation’s full name plus copyright/license notice in the footer. - A muted desktop-only end-of-chapter footer links the current passage to `getbible.life` and displays the dynamically current Vast Development Method copyright year. - The browser favicon is the replaceable 96×96 `public/favicon.png` asset. - Translation-wide local search with all-word, any-word, phrase, partial/exact word, case, testament, and book filters. The whole translation is downloaded once, cached against its upstream hash, and searched with Unicode-aware segmentation. - Search results lock the underlying reader scroll and highlight every matching word using the active appearance palette. - Opening a search result centers its verse and temporarily emphasizes the verse and matched words for seven seconds. - Search is non-blocking and incremental: each edit restarts an ordered scan, the first 20 matches appear immediately, and further groups load as the result list is scrolled. - Appearance can follow the operating system automatically or be switched manually; the selected light and dark palettes are preserved independently. - Browser Cache Storage for fast repeat visits and offline fallback. - Every opened chapter is checked against its `.sha` endpoint. Changed chapters are replaced immediately. - Translation, book, and chapter indexes refresh weekly. Changed upstream hashes invalidate only the affected cache branch. - The current translation license is displayed with the text. - Clickable translation credits with complete API metadata, licensing, source details, and version history. - Persistent reader layout switch between one verse per line and a continuous paragraph. - Sixty searchable starter marking groups with a compact large-list color picker and editable deployment colors. - Language-aware translation sorting with a CLDR-backed fallback when an API language name is absent. - Maintenance and CrossWire synchronization information available from the site footer. - The complete reader interface follows the selected Bible translation's language. Locale packs cover all 69 language identifiers currently exposed by the GetBible API, switch document direction for RTL languages, and preserve project names, scripture, API book names, and user-created study labels verbatim. ## API architecture | Resource | Endpoint | | --- | --- | | Translations | `/v2/translations.json` | | Translation books | `/v2/{translation}/books.json` | | Book chapters | `/v2/{translation}/{book}/chapters.json` | | Chapter | `/v2/{translation}/{book}/{chapter}.json` | | Chapter hash | `/v2/{translation}/{book}/{chapter}.sha` | The API's index resources contain child hashes. GetBible does not currently expose `.sha` files for `translations.json`, `books.json`, or `chapters.json`, so those indexes are refreshed weekly and their embedded hashes are compared. Individual chapters do expose `.sha` files and are verified whenever opened. ## Requirements - Node.js 22.13 or newer - npm 10 or newer ## Development ```bash git clone https://github.com/getbible/app.getbible.life.git cd app.getbible.life npm ci npm run dev ``` Open the address printed by the development server. ## Quality checks ```bash npm run lint npm test ``` `npm test` runs the TypeScript unit tests, builds the production Worker, validates the artifact contract, and verifies the rendered HTML. ## Deploy your own reader Deployment is for maintainers of a reader installation. Configure and authenticate your own Cloudflare account and review the repository's deployment settings before running this command from your checkout: ```bash npm run deploy ``` The deployment script runs all tests, requires Wrangler authentication, and deploys the verified Worker and static assets to Cloudflare. This command belongs to the reader repository; it does not deploy the GetBible documentation website. ## Cache behavior The application stores JSON responses in the browser Cache Storage API. Timestamps, SHA metadata, marking colors, saved markings, verse notes, daily Scripture, whole-translation search data, and the last visible verse are stored in durable browser storage, so annotations remain private to the current browser and device. The app requests persistent-storage protection when the browser supports it. If the API is temporarily unavailable, a previously cached chapter remains readable and is marked as saved rather than verified. **Clear all local data** requires confirmation and removes every locally stored reader item, including search indexes. ## Deployment marking groups Edit `config/reader.ts` to choose the initial marking names and colors for a deployment. Browser-customized color lists are preserved across deployments; the configured list is used for new installations or after local site data is cleared. The Markings drawer provides bounded scrolling and search when the configured list grows. ## Interface localization English source messages live in `lib/i18n.ts`; generated, lazily loaded language packs live in `public/locales/`. The active interface locale is derived from the selected translation's API `lang` value—there is no separate locale preference to become out of sync with the Bible selection. Missing individual messages fall back to English, and historical or low-resource language identifiers without reliable machine-translation support use the complete English pack. Keeping packs as static per-language files avoids adding every language to the initial JavaScript bundle. To refresh locale coverage after adding or changing an English UI message: ```bash npm run i18n:generate npm run typecheck npm run test:unit ``` The generator reads the live GetBible translation inventory, protects interpolation tokens and project names, and writes deterministic JSON locale data. Generated wording should be reviewed by native speakers before release. Never put scripture, API-provided book names, translation metadata content, or user-created marking names through the UI translator. ## License Application code is released under the [GNU General Public License v3.0](https://github.com/getbible/app.getbible.life/blob/HEAD/LICENSE) and is maintained by Llewellyn van der Merwe of Vast Development Method. Bible translations retain their own upstream licenses, which the reader displays from each translation's API metadata. ## Contributing and continuous integration GitHub Actions validates every push and pull request with locked dependency installation, linting, TypeScript checking, unit tests, a production build, and rendered-route tests. See [CONTRIBUTING.md](https://github.com/getbible/app.getbible.life/blob/HEAD/CONTRIBUTING.md) for the local workflow and maintenance guidelines. ## Support and source documentation For questions about this project, installation, unexpected output, or contributing, use the [single GetBible support desk](https://git.vdm.dev/getBible/support). Include the project, installed release or commit, operating system, relevant API version, and a minimal reproduction. General enquiries can be sent to [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). This guide follows the [repository README](https://github.com/getbible/app.getbible.life/blob/HEAD/README.md). Scripture and study resources retain their own source licences; a software licence does not relicense the texts. --- # The builders behind the APIs GetBible's study and bookmark APIs are generated documents. Their builders turn source material into validated, versioned JSON trees, publish those files to dedicated repositories, and generate the OpenAPI contracts alongside the data. Applications consume the files without running a builder. | Builder | Source | Published output | API guide | | --- | --- | --- | --- | | [Study Builder v1](https://github.com/getbible/v1_study_builder) | Approved CrossWire SWORD commentary and dictionary modules | [Commentaries](https://github.com/getbible/commentaries) and [dictionaries](https://github.com/getbible/dictionaries), under `v1/` | [Commentaries](/api/commentaries/), [Dictionaries](/api/dictionaries/) | | [Bookmark Builder v1](https://github.com/getbible/v1_bookmark_builder) | Reviewed topic, verse-link, and locale source files | [Bookmarks](https://github.com/getbible/bookmarks), under `v1/` | [Bookmarks](/api/bookmarks/) | ## Study Builder v1 Study Builder converts licensed, policy-approved CrossWire commentary and dictionary resources into plain-text JSON. A separate, pinned [getbiblesword](/project/getbiblesword/) executable extracts the SWORD modules; Python validates the extraction contract, normalizes the content, resolves scripture references, and writes the public documents. The builder uses the [Librarian](/project/librarian/) reference engine and Bible API v2 translation structure at build time. Numeric book, chapter, and verse coordinates come from the API rather than a separate hardcoded Bible shape. Module metadata records the selected versification, translation shape, naming language, and reference-resolution tables. ### What the builder guarantees - The extraction stream is independently checked for version, record order, counts, byte lengths, hashes, and successful completion. - Public content is plain text, with paragraph structure and structured scripture references. - Commentary text shared across verse ranges is stored once per chapter, with explicit verse coverage. - Dictionary IDs are deterministic; duplicate definitions remain available as separate entries. - Every document is checked against its published JSON Schema before writing. - `hashes.json` describes every other generated document and the builder-owned paths. - Unchanged module content rebuilds to identical bytes. - Failed individual modules are reported; previously verified output can be retained while other valid modules publish. - The default maximum individual document size is 95 MiB. - The builder owns only the version directories in downstream repositories. ### Build locally Python 3.12 is used by the production workflow. The published extractor supports Linux x86-64 and ARM64; its asset, digest, version, and contract are pinned in the repository manifest. ```bash git clone https://github.com/getbible/v1_study_builder.git cd v1_study_builder python3.12 -m venv .venv source .venv/bin/activate python -m pip install -e '.[dev]' study-builder engine install study-builder engine verify study-builder catalog study-builder build --resource all ``` The extractor is downloaded from a pinned public release and verified by SHA-256. It does not require a GitHub token. A deliberately selected local executable must still report the pinned version and contract. Build one commentary for development: ```bash study-builder build --resource commentaries --module Clarke --refresh python scripts/validate_build.py --resource commentaries --module Clarke ``` A limited module selection cannot publish with `--push`. Production publication uses a full resource selection so that a partial selection cannot accidentally replace a complete catalog. Run the repository checks: ```bash python -m ruff check src tests scripts python -m ruff format --check src tests scripts python -m pytest ``` ### Caching and offline builds The builder caches the CrossWire catalog, source packages, extractor, and Bible shape. Online builds check the Bible API hash and refresh cached structure when it changes. No scripture text is included in the study output. `--offline` uses verified cached inputs only. It cannot be combined with `--refresh`; missing inputs fail the build rather than silently initiating a download. `--dry-run` previews approved work without downloading source packages or installing the extractor. ### Automated publication The production workflow is scheduled for 04:12 UTC on the first day of each month and can also be run manually. Manual controls select the resource, refresh behavior, and publication. Publication uses the repository's signing identity and SSH deployment credentials. If the required publication secrets are incomplete, the study workflow still builds locally and preserves output and reports without pushing. A full publication command is: ```bash study-builder build --resource all --pull --push ``` Each output tree includes `build.json`, `build-report.json`, `hashes.json`, `openapi.json`, and its JSON Schemas. Read the build report to distinguish newly rebuilt modules from retained output. Compilation status is separate from a later publication failure. For operational details, read [build recovery](https://github.com/getbible/v1_study_builder/blob/main/docs/build-recovery.md) and [target repository responsibilities](https://github.com/getbible/v1_study_builder/blob/main/docs/target-repositories.md). Serving the generated trees is a separate deployment concern. ## Bookmark Builder v1 The bookmark builder is both the custodian of the reviewed topic catalog and the program that publishes it. Its source files contain metadata, translated topic names, and translation-independent verse coordinates. They do not contain scripture text. | Source file | Purpose | | --- | --- | | `data/topics.json` | Stable IDs, English names, colors, aliases, and default flags | | `data/links/{topic}.json` | Sorted verse-coordinate triples for one topic | | `data/locales/{locale}.json` | Topic-name translations for one locale | The original collection grew from Brother Jaco van der Merwe's mission work and personal evangelism in Namibia. He gathered verses by subject to answer questions from scripture, and his family continues to expand the catalog. ### Build and validate locally The builder requires Python 3.12 or newer and uses the standard library. Git is required for repository workflows. ```bash git clone https://github.com/getbible/v1_bookmark_builder.git cd v1_bookmark_builder python3 src/builder.py validate python3 src/builder.py build --output v1 python3 src/builder.py build --output v1 --check ``` Run CI-equivalent checks in a virtual environment: ```bash python3 -m venv .venv source .venv/bin/activate python -m pip install -r requirements-dev.txt bash scripts/run-checks.sh ``` ### Commands and source editing | Command | Purpose | | --- | --- | | `validate` | Validate every source file and report catalog counts | | `normalize` | Rewrite already-valid sources into canonical formatting | | `build --output v1` | Generate the complete static tree atomically | | `build --output v1 --check` | Check whether existing output matches a fresh build | | `import-bundle --check` | Validate a robot contribution bundle without applying it | | `import-bundle` | Apply a valid contribution bundle to the source files | Validation failures return exit code 1 with the file and violated rule on standard error. Normalization is formatting, not a repair mechanism for invalid data. The [data guide](https://github.com/getbible/v1_bookmark_builder/blob/main/docs/DATA.md) explains which files are involved in adding, renaming, translating, or deleting topics. Changes are reviewed through GitHub. Deleting a topic removes it from the next published tree; git history is the record of earlier content. ### Output and determinism Every build produces discovery, topic summaries, full topic documents, aggregate catalogs, reverse verse indexes, locale documents, checksums, and OpenAPI 3.1.1. All canonical books and chapters have reverse-index files, even when their association maps are empty. `index.json.checksum` hashes the exact `all.json` bytes, and `catalog_version` advances when that content changes. `checksums.json` hashes every other generated file, including the OpenAPI description. Documentation changes therefore publish even if the catalog version remains unchanged. The output is built beside the target and swapped in atomically. Identical input produces identical output. `build --check` detects stale or missing documents, including the generated specification. ### Automated publication and contributions The production workflow runs after pushes to `main` or `master`, and through manual dispatch. It uses Python 3.13, validates and builds the source, then pushes a signed change to the generated `getbible/bookmarks` repository only when output differs. `run.sh` wraps source validation, building, and downstream git publication. Repository secrets supply the signing and deployment identity; the downstream repository and branch have optional overrides. These are builder publication credentials, not API consumer tokens. The API itself has no write or authentication endpoint. A human contribution uses a branch and pull request; an authorized application can prepare source changes through GitHub. See [contributing](https://github.com/getbible/v1_bookmark_builder/blob/main/docs/CONTRIBUTING.md), [publishing](https://github.com/getbible/v1_bookmark_builder/blob/main/docs/PUBLISHING.md), and [CLI reference](https://github.com/getbible/v1_bookmark_builder/blob/main/docs/CLI.md). ## Support and source of truth All public questions, reports, and requests can go to the [shared GetBible support desk](https://git.vdm.dev/getBible/support). The generated OpenAPI document beside each API is the machine-readable contract for that tree. The builder source documents describe how the data is validated and published. Module-specific licenses and provenance travel with study metadata; the bookmark builder and catalog use Apache License 2.0. ## Sources - [Study Builder source and contracts](https://github.com/getbible/v1_study_builder) - [Study production workflow](https://github.com/getbible/v1_study_builder/blob/main/.github/workflows/build.yml) - [Bookmark Builder source and catalog history](https://github.com/getbible/v1_bookmark_builder) - [Bookmark production workflow](https://github.com/getbible/v1_bookmark_builder/blob/main/.github/workflows/build.yml) - [Bookmark OpenAPI guide](https://github.com/getbible/v1_bookmark_builder/blob/main/docs/OPENAPI.md) ## Bible v2 builder The [v2 builder](https://github.com/getbible/v2_builder) creates the static Scripture tree used by [Bible API v2](/api/bible/v2/). It reads configured CrossWire SWORD modules and produces whole-translation, book and chapter JSON documents. The build adds discovery indexes, change checksums and a generated OpenAPI 3.1 description. Two outputs serve different purposes: | Output | Default folder | Contents | | --- | --- | --- | | Scripture tree | `repo/v2_scripture` | Translation/book/chapter JSON, indexes, OpenAPI and checksums | | Public hash companion | `repo/v2` | Hashes, JSON/text indexes and OpenAPI without the full Scripture documents | Every JSON file has a `.sha` sibling. The build's final checksum pass creates or corrects missing/mismatched checksums and removes orphaned hashes. Indexes are available as JSON and tab-separated `.txt`. The reserved names `translations`, `books`, `chapters`, `checksum` and `openapi` are never treated as translation IDs. Start by inspecting the repository and its command options: ```bash git clone https://github.com/getbible/v2_builder.git cd v2_builder bash ./run.sh --help ``` Follow the [repository installation instructions](https://github.com/getbible/v2_builder#installation) before a complete build. Its implementation uses Python, PySword and shell helpers. `--bconf` selects the module-to-abbreviation map, `--api` chooses the output locations, `--hashonly` hashes existing data, and `--pull`/`--push` enable configured repository publication. A full catalogue build is substantially larger than fetching an API chapter; use the published API when you only need to consume Scripture. The project asks maintainers of distributed copies to refresh at least weekly, retain checksum handling and preserve the connection between source text and published hashes. Full Scripture repositories must follow the [builder's publication guidelines](https://github.com/getbible/v2_builder#guidelines); the hash companion is intended for public change verification. Report a public deployment through the central [GetBible support desk](https://git.vdm.dev/getBible/support). [Source repository](https://github.com/getbible/v2_builder) · [Build workflow](https://github.com/getbible/v2_builder/actions/workflows/build.yml) · [v2 API guide](/api/bible/v2/) · [OpenAPI JSON](https://api.getbible.net/v2/openapi.json) ## Bible v3 builder The [v3 builder](https://github.com/getbible/v3_builder) generates [Bible API v3](/api/bible/v3/) using the official SWORD engine through the separately released [GetBibleSWORD executable](/project/getbiblesword/). C++ handles native extraction; Python validates the extraction contract and produces compact Scripture JSON. The pipeline downloads approved modules, extracts one transient NDJSON contract per module, validates its framing and integrity, converts the data, writes indexes and hashes, generates OpenAPI and publishes configured output repositories. Temporary module archives, SWORD installations and extraction streams are discarded after the attempt. Those extraction internals are not copied into the public reading API. Version 3 preserves the core chapter/verse fields and adds source-derived `tokens`, `spans`, paragraph starts, introductions, book titles and chapter `editorial`. The same chapter editorial data is emitted in whole-translation, book and standalone chapter representations. Known book numbers remain stable; new source identities receive deterministic extension numbers. Books containing only titles or introductory material can be retained. ### Local validation build The current native pipeline requires Python 3.12 or later and Linux x86-64 or ARM64 for its published GetBibleSWORD executable. ```bash git clone https://github.com/getbible/v3_builder.git cd v3_builder python3 -m venv .venv source .venv/bin/activate python -m pip install -r requirements.txt -r requirements-dev.txt python scripts/install_getbiblesword.py export GETBIBLESWORD_BIN="$PWD/.tools/getbiblesword" python src/builder.py --test ``` The native installer follows the checked-in release policy, resolves an exact stable release for the build, checks its release asset and records provenance. `--test` builds representative modules; `python src/builder.py` builds the configured catalogue. Publication credentials and repository destinations are separate configuration, so local validation does not require a contributor to publish data. | Option | Purpose | | --- | --- | | `--getbiblesword` | Native executable path or command | | `--bconf` | Requested module-to-abbreviation mapping | | `--publication-policy` | Explicit source publication approval manifest | | `--api-base-url` | Public host plus one version segment recorded in index URLs | | `--contracts` | Temporary validated extraction-contract directory | | `--sword-root` | Explicit temporary SWORD installation | | `--hash-only` | Rebuild hashes for existing output | | `--dry` | Inspect the configured build plan without executing it | The generated OpenAPI embeds its schemas and uses version-prefixed paths without assuming a host. Its schema source is checked in under [`schema/`](https://github.com/getbible/v3_builder/tree/master/schema). Every JSON resource has a hash companion. Scripture publication completes before the derived hash repository is published, and oversized output or failed extraction stops publication. ### Contributing and checking changes ```bash # Deterministic unit tests python -m pytest tests/ -v # Native integration after installing the executable python -m pytest tests_integration/ -v --run-integration ``` The repository provides unit/integration CI, a native smoke workflow, full-catalogue validation, preview builds and a fresh KJV inspection workflow. Changes to emitted data belong with matching schema updates and conformance checks. New translation publication requires source rights review and explicit approval in the publication policy; the software licence does not relicense module content. [Source repository](https://github.com/getbible/v3_builder) · [Native pipeline](https://github.com/getbible/v3_builder/blob/master/docs/getbiblesword-pipeline.md) · [Output contract](https://github.com/getbible/v3_builder/blob/master/docs/static-output.md) · [Publication policy](https://github.com/getbible/v3_builder/blob/master/docs/publication-policy.md) · [v3 API guide](/api/bible/v3/) · [OpenAPI JSON](https://api.getbible.net/v3/openapi.json) --- # Desktop — the GetBible website as a desktop application A configurable C++ desktop shell opens the GetBible web reader through the operating system's native web engine. It packages the existing website for Linux, macOS, and Windows while preserving cookies and local storage. [Repository](https://github.com/getbible/desktop) · [Support](https://git.vdm.dev/getBible/support) · [All projects](/project/) This desktop shell and the native Flutter [GetBible App](/project/app/) are separate projects. The shell follows the capabilities and API version of its configured website; the default website is [app.getbible.life](https://app.getbible.life/), which currently uses Bible API v2. Build and Store packaging support do not imply that an application is already listed in every Store. A configurable C++ shell that turns an HTTPS website into a focused Linux, macOS, and Windows desktop application. It uses the operating system's native web engine through [CHOC](https://github.com/Tracktion/choc), preserves cookies and local storage, displays a branded offline page, disables the browser context menu, and prevents top-level navigation outside configured origins. ## Default GetBible profile Without overrides, the repository builds: ```text Name: getBible.Life Application URL: https://app.getbible.life/ Homepage: https://app.getbible.life/ Allowed origin: https://app.getbible.life Application ID: live.getbible.app Executable: getbible-life Snap name: getbible-life ``` The default floating three-dot menu is disabled so it cannot cover controls owned by the website. Public support for this application is provided through the [GetBible support desk](https://git.vdm.dev/getBible/support). ## Features - Configurable name, domain, allowed origins, version, descriptions, support information, offline messages, window size, icons, and Store identities. - JSON configuration with repository variable and secret overrides. - Persistent native WebView cookies, local storage, and login state. - Branded embedded offline, About, and Support pages. - Top-level navigation restricted to configured HTTPS origins. - Right-click, middle-click, auxiliary buttons, and keyboard context menus disabled. - JavaScript and user-agent application detection for website-specific layouts. - Linux portable archive and Snap packaging. - Windows MSIX packaging with optional certificate signing. - macOS DMG packaging with optional Developer ID signing and notarization. - Automatic builds on every push to `main`. - Tag-driven GitHub Releases with all packages and SHA-256 checksums. - Optional Snap Store publication after the GitHub Release succeeds. ## Repository layout ```text config/app.json Default application configuration config/app.schema.json Configuration schema branding/ Default and custom source icons src/ C++ desktop shell scripts/ Local build and packaging commands tools/ Configuration and metadata generator tests/ Generator tests docs/ Integration and distribution guides .github/workflows/build.yml Main-branch multi-platform builds .github/workflows/release.yml Tag-driven release and Snap publication ``` Generated metadata is written under `generated/` and should not be edited manually. ## Linux quick start First obtain the source. The Linux, macOS, Windows, configuration, and validation commands below run from this checkout: ```bash git clone https://github.com/getbible/desktop.git cd desktop ``` ```bash sudo apt update sudo apt install --yes \ build-essential cmake git libgtk-3-dev libwebkit2gtk-4.1-dev \ pkg-config python3 python3-pil chmod +x scripts/*.sh ./scripts/build-linux.sh ./build/getbible-life ``` The bootstrap script fetches the pinned upstream CHOC revision. Repository maintainers can use `scripts/register-submodule.sh` when intentionally changing how their checkout records that dependency; ordinary builds do not require a repository commit. ## macOS Run on macOS with Xcode Command Line Tools, CMake, Git, Python 3, and Pillow: ```bash chmod +x scripts/*.sh ./scripts/build-macos.sh open ./build-macos/getbible-life.app ./scripts/package-macos.sh ``` See [macOS distribution](https://github.com/getbible/desktop/blob/HEAD/docs/MACOS_DISTRIBUTION.md). ## Windows Run from PowerShell on Windows with Visual Studio 2022 C++ tools, CMake, Git, Python 3, Pillow, and the Windows SDK: ```powershell python -m pip install --requirement tools/requirements.txt ./scripts/build-windows.ps1 ./scripts/package-windows.ps1 ``` See [Windows distribution](https://github.com/getbible/desktop/blob/HEAD/docs/WINDOWS_STORE.md). ## Configure another website Copy the default configuration and supply another icon: ```bash mkdir -p config/sites branding/sites cp config/app.json config/sites/example.json read -r -p 'Path to your PNG icon: ' WEBAPP_SOURCE_ICON cp -- "$WEBAPP_SOURCE_ICON" branding/sites/example.png ``` Minimal profile: ```json { "app": { "name": "Example Portal", "slug": "example-portal", "id": "com.example.portal", "version": "1.0.0", "url": "https://portal.example.com/", "homepage_url": "https://portal.example.com/", "allowed_origins": ["https://portal.example.com"] }, "window": { "show_app_menu": false }, "branding": { "icon": "branding/sites/example.png" }, "snap": { "name": "example-portal" }, "windows": { "identity_name": "com.example.portal", "publisher": "CN=Example Publisher", "publisher_display_name": "Example Publisher" } } ``` Build it: ```bash WEBAPP_CONFIG_FILE=config/sites/example.json ./scripts/build-linux.sh ``` See [configuration](https://github.com/getbible/desktop/blob/HEAD/docs/CONFIGURATION.md). ## Application detection Every page receives: ```javascript window.WebAppDesktop ``` The default profile also exposes: ```javascript window.GetBibleApp ``` Example: ```javascript if (window.WebAppDesktop?.isApp) { document.querySelector('.browser-only')?.remove(); } ``` The document root receives `webapp-desktop-app` and a configurable application-specific class. Linux also appends `GetBibleLifeDesktop/` to WebKitGTK's normal user agent. These markers control presentation only; they are not authentication credentials. See [website integration](https://github.com/getbible/desktop/blob/HEAD/docs/APP_INTEGRATION.md). ## About and Support The embedded overlay menu is disabled by default. A website can add controls where they fit its own layout: ```javascript document.querySelector('#desktop-about')?.addEventListener('click', () => { window.location.assign(window.WebAppDesktop.aboutURL); }); document.querySelector('#desktop-support')?.addEventListener('click', () => { window.location.assign(window.WebAppDesktop.supportURL); }); ``` The internal destinations are `webapp://app/about` and `webapp://app/support`. ## Automatic builds Every push to `main` runs **Build all desktop targets** and produces downloadable workflow artifacts for: - Linux `.tar.gz`; - Linux `.snap`; - Windows `.msix`; - macOS `.dmg`. Repository configuration and signing values are optional. The default GetBible profile is used when none are supplied. ## Releases and distribution Users can obtain available packages from the [release page](https://github.com/getbible/desktop/releases). Publishing a new release is a repository-maintainer action: after the intended commit passes the main-branch checks, a new matching semantic-version tag triggers the release workflow. Follow the repository's [automated release procedure](https://github.com/getbible/desktop/blob/HEAD/docs/AUTOMATED_RELEASES.md) when managing your own distribution. **Build and publish release** then: 1. builds all four packages; 2. creates `SHA256SUMS`; 3. creates the GitHub Release and uploads all packages; 4. attempts Snap Store publication only afterward. When `SNAPCRAFT_STORE_CREDENTIALS` is absent, the final Store job fails clearly, but the GitHub Release and downloadable packages remain available. See [automated releases](https://github.com/getbible/desktop/blob/HEAD/docs/AUTOMATED_RELEASES.md) and [Snap Store distribution](https://github.com/getbible/desktop/blob/HEAD/docs/SNAP_STORE.md). ## Validation ```bash chmod +x scripts/*.sh ./scripts/validate.sh ``` ## Distribution channels - Linux: GitHub Release archive or Snap Store. - Windows: signed MSIX and Microsoft Store. - macOS: signed/notarized DMG or a separately prepared Mac App Store submission. The Snap Store distributes Linux packages only. ## License The template is GPL-3.0-or-later. CHOC is distributed separately under its ISC license. ## Application configuration The template resolves application settings in this order, with later sources overriding earlier sources: 1. Built-in GetBible defaults. 2. `config/app.json` or the file selected by `WEBAPP_CONFIG_FILE`. 3. The optional `WEBAPP_CONFIG_JSON` secret. 4. Individual `WEBAPP_*` environment variables. Run the generator directly: ```bash python3 tools/configure_app.py \ --root . \ --config config/app.json \ --output generated ``` Or use: ```bash ./scripts/configure-app.sh ``` ### Core application fields ```json { "app": { "name": "getBible.Life", "slug": "getbible-life", "id": "live.getbible.app", "version": "1.0.0", "url": "https://app.getbible.life/", "homepage_url": "https://app.getbible.life/", "allowed_origins": ["https://app.getbible.life"], "summary": "Short Store summary", "description": "Long Store description", "about": "About-page text", "user_agent_product": "GetBibleLifeDesktop", "javascript_object": "GetBibleApp", "html_class": "getbible-life-desktop-app" } } ``` `app.url`, `app.homepage_url`, and every allowed origin must use HTTPS. The origin of `app.url` is automatically added to the allowed list. ### Window and embedded menu ```json { "window": { "width": 1200, "height": 800, "minimum_width": 720, "minimum_height": 520, "show_app_menu": false } } ``` The floating three-dot menu is disabled by default because it can cover website controls. Enable it only when the website intentionally reserves space for it. About and Support pages remain available at `webapp://app/about` and `webapp://app/support` even when the menu is disabled. ### Offline and support content The `offline` object controls the embedded reconnect page. The `support` object controls the generated support page and Store contact metadata. A support URL opens in the application only when its origin is included in `app.allowed_origins`; otherwise it is displayed as information without allowing an external website to replace the application. ### Branding `branding.icon` may point to a PNG or to a text file containing raw base64 PNG data. `WEBAPP_ICON_BASE64` takes priority in CI. The generator produces: - Linux PNG sizes; - Windows ICO and MSIX tile images; - macOS ICNS; - an embedded PNG header used by offline, About, and Support pages. ### Platform metadata The `snap`, `windows`, and `macos` objects control Store identity and package settings. Store identity values should be chosen before the first public publication because changing them later may create a different application identity. Windows `publisher` must equal the subject of the signing certificate. The application ID and Snap name must satisfy the naming requirements of their target Stores. ### Using another configuration file ```bash WEBAPP_CONFIG_FILE=config/sites/example.json ./scripts/build-linux.sh ``` Windows PowerShell: ```powershell ./scripts/build-windows.ps1 -ConfigFile config/sites/example.json ``` macOS: ```bash WEBAPP_CONFIG_FILE=config/sites/example.json ./scripts/package-macos.sh ``` ### Generated files Do not edit files under `generated/` manually. They are regenerated from configuration and branding before builds. The generator also refreshes `snap/snapcraft.yaml` and `snap/gui/` so the Snap metadata always matches the selected profile. ## Website integration The desktop shell exposes a stable application identity before the website's normal scripts execute. ### JavaScript identity Every page receives: ```javascript window.WebAppDesktop ``` The configured alias is also created. For the default profile: ```javascript window.GetBibleApp ``` Example: ```javascript if (window.WebAppDesktop?.isApp === true) { document.documentElement.classList.add('running-in-desktop-shell'); console.log(window.WebAppDesktop.version); console.log(window.WebAppDesktop.platform); } ``` The object includes the application name, slug, version, platform, application URL, About URL, and Support URL. It is frozen and installed as a non-writable property. The document root also receives: ```html ``` CSS example: ```css html.webapp-desktop-app .browser-only { display: none !important; } html:not(.webapp-desktop-app) .desktop-only { display: none !important; } ``` ### Server-side detection On Linux, the native WebKit user agent retains its normal value and appends: ```text GetBibleLifeDesktop/1.0.0 ``` PHP example: ```php { window.location.assign(window.WebAppDesktop.aboutURL); }); document.querySelector('#desktop-support')?.addEventListener('click', () => { window.location.assign(window.WebAppDesktop.supportURL); }); ``` The built-in floating menu is disabled in the default profile to avoid covering website controls. ### Navigation restrictions Top-level pages may load only from `app.allowed_origins` or the internal `webapp://app/` pages. Attempts to open unrelated websites are cancelled and return to the configured application URL. Subresources required by the allowed website, such as images, APIs, fonts, or authentication resources, are not subjected to the top-level origin restriction. Configure the website's own Content Security Policy and CORS rules normally. Right-click, middle-click, auxiliary mouse buttons, the context-menu key, and `Shift+F10` are blocked. Normal left-click interaction remains available. ## Support and source documentation For questions about this project, installation, unexpected output, or contributing, use the [single GetBible support desk](https://git.vdm.dev/getBible/support). Include the project, installed release or commit, operating system, relevant API version, and a minimal reproduction. General enquiries can be sent to [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). This guide follows the [repository README](https://github.com/getbible/desktop/blob/HEAD/README.md) and [CONFIGURATION](https://github.com/getbible/desktop/blob/HEAD/docs/CONFIGURATION.md), [APP INTEGRATION](https://github.com/getbible/desktop/blob/HEAD/docs/APP_INTEGRATION.md). Scripture and study resources retain their own source licences; a software licence does not relicense the texts. --- # getBibleSword — native SWORD extraction Export installed CrossWire SWORD modules through a deterministic NDJSON stream. The C++ engine provides a command-line tool and a stable C ABI for downstream builders, native applications, and the PHP extension. [Repository](https://github.com/getbible/getbiblesword) · [Support](https://git.vdm.dev/getBible/support) · [All projects](/project/) Engineering preview: the repository identifies the `0.3.x` series as pre-stable. It exports native SWORD data; GetBible HTTP API formatting belongs to downstream builders. Its NDJSON contract `getbiblesword.ndjson/v1`, C ABI `1`, and product release are independently versioned. `getBibleSword` is a GPL-2.0-only C++ extraction engine built directly on the official CrossWire SWORD engine. It provides both the standalone `getbiblesword` CLI and the stable `libgetbiblesword.so.1` C ABI. It exports every SWORD module family through deterministic NDJSON: Biblical texts, commentaries, dictionaries, lexicons, general books, daily devotionals, maps, images and other generic resources. SWORD's official interpretation is kept alongside the exact source bytes; rendered text never replaces source data. ## Status The current `0.3.x` line is an engineering preview. Its all-driver conformance suite, independent validator and byte-for-byte artifact round trip are complete. The final maintainer review of the public contract and classification policy is still required before the project is declared stable `1.0.0`. The software release and output contract have separate versions: | Item | Current value | Meaning | |---|---|---| | Product release | `0.3.0` | Version of the executable, shared library and release archive | | Native ABI | `1` / `libgetbiblesword.so.1` | Stable C calling boundary for native and PHP extensions | | NDJSON contract | `getbiblesword.ndjson/v1` | Compatibility identifier consumers must check | | Contract version | `1` | Numeric value in each stream header | | JSON Schema | `schema/v1/contract.schema.json` | Record-shape schema for contract v1 | There is no contract or schema v2 yet. A future incompatible format would use a new identifier and schema directory rather than silently changing v1. ## Download Linux release archives are published for `x86_64` and `arm64`, with a separate SHA-256 file for each archive. This example downloads and verifies the current version for the host architecture: ```sh version="$(curl -fsSL https://raw.githubusercontent.com/getbible/getbiblesword/main/VERSION)" case "$(uname -m)" in x86_64) architecture=x86_64 ;; aarch64|arm64) architecture=arm64 ;; *) printf 'Unsupported architecture: %s\n' "$(uname -m)" >&2; exit 1 ;; esac archive="getbiblesword-${version}-linux-${architecture}.tar.gz" base="https://github.com/getbible/getbiblesword/releases/download/v${version}" curl -fLO "${base}/${archive}" curl -fLO "${base}/${archive}.sha256" sha256sum --check "${archive}.sha256" tar -xzf "$archive" ``` The archive uses a `/usr` install prefix. Extract it into a staging directory or install it with the package/deployment method appropriate for the target system. ## Build Dependencies are C and C++20 compilers, CMake 3.25+, Ninja and pkg-config. Official builds use the pinned CrossWire SWORD 1.9.0 PIC static archive. ```sh git clone https://github.com/getbible/getbiblesword.git cd getbiblesword ./scripts/build-sword.sh "$PWD/.local/sword" PKG_CONFIG_PATH="$PWD/.local/sword/lib/pkgconfig" cmake --preset dev PKG_CONFIG_PATH="$PWD/.local/sword/lib/pkgconfig" \ cmake --build --preset dev --parallel ctest --preset dev ``` `GETBIBLESWORD_SWORD_PROVIDER=BUNDLED` is the default and refuses anything except the pinned static SWORD 1.9.0 engine. Distribution maintainers can explicitly set `-DGETBIBLESWORD_SWORD_PROVIDER=SYSTEM` to use a system SWORD 1.9.0 or newer. ## Quick start An explicit SWORD installation root is required. This prevents ambient host module discovery from changing otherwise identical output. ```sh getbiblesword list --sword-path /usr/share/sword getbiblesword extract \ --sword-path /usr/share/sword \ --module KJV \ --output kjv.ndjson getbiblesword-v1 validate kjv.ndjson ``` Reconstruct the captured configuration and module files only when that is the intended operation: ```sh getbiblesword-v1 reassemble kjv.ndjson reconstructed-kjv ``` `extract` refuses to overwrite an existing output file unless `--force` is given. NDJSON is written to standard output when `--output` is omitted. Operational errors go to standard error; extraction warnings and failures also remain in the stream as contract diagnostics. ## Downstream integration Existing Builder integrations should retain `getbiblesword` as a subprocess boundary: 1. run `list` or `extract` with an explicit SWORD root; 2. independently validate the completed stream; 3. require the v1 contract, consecutive sequence numbers, a valid footer digest and `success: true`; 4. transform validated records in a separate application-specific adapter; and 5. use decoded `base64` bytes as authoritative, not the optional `utf8`, rendered or stripped convenience views. See the [downstream integration guide](https://github.com/getbible/getbiblesword/blob/HEAD/docs/downstream-integration.md) for the record map and Bash, Python, Node/TypeScript and PHP examples. AI tools and agents can start with [llms.txt](https://github.com/getbible/getbiblesword/blob/HEAD/llms.txt), [AGENTS.md](https://github.com/getbible/getbiblesword/blob/HEAD/AGENTS.md) and the [AI integration guide](https://github.com/getbible/getbiblesword/blob/HEAD/docs/ai-integration.md), which includes MCP-style tool descriptors without introducing an MCP server. ## Native C ABI `libgetbiblesword.so.1` exposes the same deterministic `list` and `extract` operations through synchronous byte callbacks. No SWORD or C++ type crosses the public interface, and no exception can escape an exported function. ```c #include #include #include static gbs_write_result write_stdout( const uint8_t *data, size_t size, void *context ) { (void)context; return fwrite(data, 1U, size, stdout) == size ? GBS_WRITE_CONTINUE : GBS_WRITE_ERROR; } int main(void) { gbs_error error = GBS_ERROR_INITIALIZER; gbs_extract_options_v1 options = GBS_EXTRACT_OPTIONS_V1_INITIALIZER; options.sword_path = "/usr/share/sword"; options.module_name = "KJV"; return gbs_extract_module_v1( &options, write_stdout, NULL, &error ) == GBS_STATUS_OK ? 0 : 1; } ``` Use `pkg-config --cflags --libs getbiblesword` or CMake target `getBibleSword::getBibleSword`. The complete callback, ownership, status, concurrency and ABI-versioning rules are in the [C ABI v1 guide](https://github.com/getbible/getbiblesword/blob/HEAD/docs/c-api-v1.md). The shared library is the foundation for the planned native Zend extension; this repository remains PHP-independent. ## Documentation | Document | Purpose | |---|---| | [Documentation index](https://github.com/getbible/getbiblesword/blob/HEAD/docs/README.md) | Reading paths for users, integrators, maintainers and agents | | [Downstream integration](https://github.com/getbible/getbiblesword/blob/HEAD/docs/downstream-integration.md) | Safe consumption patterns and language examples | | [C ABI v1](https://github.com/getbible/getbiblesword/blob/HEAD/docs/c-api-v1.md) | Native functions, callbacks, statuses, packaging and ABI governance | | [PHP extension roadmap](https://github.com/getbible/getbiblesword/blob/HEAD/docs/php-extension-roadmap.md) | Zend/PIE package boundary, phases and acceptance gates | | [Contract v1](https://github.com/getbible/getbiblesword/blob/HEAD/docs/contract-v1.md) | Normative NDJSON semantics, ordering and hashing | | [JSON Schema](https://github.com/getbible/getbiblesword/blob/HEAD/schema/v1/contract.schema.json) | Machine-readable record shapes | | [Independent validator](https://github.com/getbible/getbiblesword/blob/HEAD/docs/validator-v1.md) | Full-stream validation and safe artifact reconstruction | | [Conformance corpus](https://github.com/getbible/getbiblesword/blob/HEAD/docs/conformance-corpus.md) | Coverage of all concrete SWORD 1.9.0 drivers | | [Architecture](https://github.com/getbible/getbiblesword/blob/HEAD/docs/architecture.md) | Component and trust boundaries | | [Threat model](https://github.com/getbible/getbiblesword/blob/HEAD/docs/threat-model.md) | Security controls and residual risks | | [Milestone 1](https://github.com/getbible/getbiblesword/blob/HEAD/docs/milestone-1.md) | Acceptance criteria and remaining stable-v1 gate | ## Scope This repository does not generate the GetBible API shape, Builder templates, Study Builder repositories or an MCP service. Those are downstream consumers that must work from validated NDJSON rather than private extractor internals. ## License Copyright (C) 2026 Llewellyn van der Merwe and contributors. Licensed under the GNU General Public License version 2 only. See [LICENSE](https://github.com/getbible/getbiblesword/blob/HEAD/LICENSE). ## Support and source documentation For questions about this project, installation, unexpected output, or contributing, use the [single GetBible support desk](https://git.vdm.dev/getBible/support). Include the project, installed release or commit, operating system, relevant API version, and a minimal reproduction. General enquiries can be sent to [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). This guide follows the [repository README](https://github.com/getbible/getbiblesword/blob/HEAD/README.md). Scripture and study resources retain their own source licences; a software licence does not relicense the texts. --- # Joomla — put the Bible on your website GetBible for Joomla lets a church, ministry, community, or developer host a Bible reading and study experience inside an existing Joomla site. The component provides Scripture browsing, search, notes, tags, and a visitor linker system. A separate Loader plugin adds Scripture references to ordinary site content. [Support](https://git.vdm.dev/getBible/support) · [Live Joomla reader](https://getbible.life/) · [All projects](/project/) ## Choose the right integration | Project | Role | Repository | |---|---|---| | Joomla package | Installs the matching component together with related modules and a Loader plugin | [joomla-pkg](https://github.com/getbible/joomla-pkg) | | Joomla component | Full Bible application and administrator management | [joomla-component](https://github.com/getbible/joomla-component) | | Joomla Scripture Loader | Adds the JavaScript reference loader to Joomla pages | [joomla-scripture-loader](https://github.com/getbible/joomla-scripture-loader) | | Standalone JavaScript Loader | Adds inline Scripture, tooltips, or modals to any website | [Loader guide](/project/loader/) | The package contains the component, Daily Light module, Daily Scripture module, and system Loader plugin. The Loader is useful when you only need to display verses within content; the component provides the full reader and study experience. ## Match your Joomla version The repositories maintain different release lines. The package source reviewed for this guide identifies `5.0.16` for Joomla 5.0 through 5.4. The component's current default source identifies `6.0.16` and uses the `6.x` update channel. These are not interchangeable installation targets. | Source | Version/channel documented in source | What to verify | |---|---|---| | Package | `5.0.16`, Joomla 5 | Select the package intended for your installed Joomla version | | Component | `6.0.16`, `6.x` update channel | Check the release manifest and Joomla compatibility before installation | | Scripture Loader | `3.1.0`; current manifest targets Joomla 5 | Use a build compatible with your Joomla release rather than relying on older broad README claims | Download a compatible installable archive from the appropriate repository. The Joomla package archive includes bundled extension ZIP files; a component archive and a package archive have different purposes. A test installation and a current site/database backup are useful before changing any established site. ## Install the package or component 1. Download the package or component release that matches your Joomla version. 2. Sign into Joomla's administrator interface with extension-install permission. 3. Open **System → Install → Extensions** and upload the installable ZIP. 4. Open the Get Bible component from the administrator component menu. 5. Review the component options, select the default translation, and configure any required repository access for your installation. 6. Create a Joomla menu item for the Get Bible application's reader view. 7. Open that menu item on the public site and verify translation selection, chapter navigation, and the features you enable. The installer provisions the component's database tables. Updates are distributed through the release channel declared in the selected extension manifest. Keep the installed component and package on compatible release lines. The source includes a `show_install_button` option intended for initial translation setup. Enable it only when that installation action is needed, complete the translation setup, and then return the site to its intended reader presentation. ## Administrator features The component manifest exposes administrator views for: - Linkers, which identify reader sessions. - Notes and tagged verses. - Tags. - Prompts and stored OpenAI responses. - Translations, books, chapters, and verses. - The main GetBible dashboard. The reader's linker system uses a GUID rather than requiring each visitor to create a Joomla login. This lets a visitor retain study notes and verse associations and supports sharing a study session. A linker belongs to that installation's feature model; it is not a public Bible API token. For site owners, Joomla permissions still control administrative access. Review the component's access configuration and avoid giving ordinary site visitors access to administrator views or service credentials. ## Useful reader settings These settings are present in the component's configuration and reader menu metadata. | Setting | Purpose | |---|---| | `default_translation` | Initial translation; source default is `kjv` | | `show_install_button` | Expose translation installation during initial setup | | `show_getbible_logo` | Show the GetBible brand | | `show_getbible_link` | Show the project link | | `show_hash_validation` | Show hash-validation information | | `show_api_link` | Show the API link | | `verse_per_line` | Choose a verse-per-line reader layout | | `previous_next_navigation` | Control adjacent-passage navigation | | Reader menu/card settings | Choose tabs, icons, positions, and card presentation | | `enable_open_ai` | Enable optional OpenAI functionality; default is disabled | Many reader-menu settings can inherit the component default. Set site-wide behavior in component options and override individual menu items only when the page needs a different presentation. ## VDM access tokens The component includes an optional password field named `gitea_token`, displayed as **VDM Access Token**. Its documented purpose is obtaining updates from VDM. 1. Sign into the VDM account you use for this integration. 2. Open [VDM application and access-token settings](https://git.vdm.dev/user/settings/applications). 3. Create the token required for the repository access your installation needs. 4. Save it in the GetBible component's VDM Access Token field. 5. Verify the update or repository action from Joomla. The field's current source does not prescribe an exact scope selection. If the required access is unclear, use the [support desk](https://git.vdm.dev/getBible/support) before expanding permissions. Keep the token in administrator configuration; do not paste it into a public issue, article, script tag, or browser console. This VDM token is separate from normal public GetBible API access. It is also separate from an OpenAI API key or a Telegram bot token. See the [API overview](/api/) for the endpoint contracts. ## Optional OpenAI integration The component can send Scripture-based prompts to OpenAI when the site administrator enables the feature and supplies the appropriate server-side API credentials. The component exposes prompt management, stored responses, model configuration, and generation settings. This optional integration is disabled by default. It is not required to read Scripture, browse the public Bible APIs, or use the Loader. Use the current [OpenAI API documentation](https://platform.openai.com/docs/) for the account and API setup; configure only settings supported by your installed component release. A list of model names in an older component release does not establish their present availability. Treat generated responses as a separate application feature from the source Bible text. Keep the source translation, its attribution, and its licensing visible in the reader. For the GetBible MCP integration, including connecting tools to ChatGPT, use the separate [MCP guide](/mcp/). ## Install the Joomla Scripture Loader The system plugin adds the JavaScript Loader to Joomla's page header. 1. Download a compatible plugin archive from [joomla-scripture-loader](https://github.com/getbible/joomla-scripture-loader). 2. Install it through Joomla's extension installer. 3. Open Joomla's plugin manager and enable the GetBible Loader system plugin. 4. Edit an article or other content area in HTML/source mode. 5. Add the `getBible` class to an element containing a Scripture reference. ```html
John 3:16-19
``` The editor and Joomla text filters must preserve the class and `data-*` attributes. If the markup disappears on save, inspect the editor's allowed-HTML settings and the appropriate Joomla text-filter policy. Use `tooltip` or `modal` for a compact reference that opens the passage on interaction: ```html

The passage is 1 John 3:16-19.

``` The full [Loader guide](/project/loader/) documents the attributes, current Query v2 dependency, local cache, display adapters, and loading behavior. When the Joomla plugin supplies the bundle, avoid inserting a second copy manually. ## Scripture sources and version compatibility GetBible's public data services evolve independently from Joomla extension releases. Read the chosen extension's source and release notes before changing endpoints or assuming new response fields are supported. Availability of Bible API v3, dictionaries, or commentaries on the platform does not automatically add those services to an older Joomla component. The live [getbible.life](https://getbible.life/) site remains a Bible reading site. Project documentation, API references, and integration guides belong on [getbible.net](https://getbible.net/). ## Troubleshooting | Problem | Next check | |---|---| | Extension fails to install | Confirm the package type, release channel, Joomla version, and installer error | | Reader page is missing | Check that the Get Bible reader menu item is published and accessible | | Translation data is unavailable | Check installation status, selected translation, outbound API access, and the component's configuration | | Update access fails | Verify the VDM token and its intended access without posting the token publicly | | Loader shows only a reference | Verify that the plugin is enabled and the saved HTML retains `getBible` and its attributes | | Loader links open documentation | Set `data-bible-url="https://getbible.life/"` or your own compatible reader base | | OpenAI features fail | Check the optional feature's enabled state and server-side configuration for the installed release | All public support goes to the [GetBible support desk](https://git.vdm.dev/getBible/support). Include the Joomla version, extension version, PHP version, affected page, and steps to reproduce. General enquiries: [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). ## Source documentation and contribution - [Joomla package README](https://github.com/getbible/joomla-pkg/blob/HEAD/README.md) and [package manifest](https://github.com/getbible/joomla-pkg/blob/HEAD/pkg_getbible.xml). - [Component README](https://github.com/getbible/joomla-component/blob/HEAD/README.md), [extension manifest](https://github.com/getbible/joomla-component/blob/HEAD/getbible.xml), and [configuration](https://github.com/getbible/joomla-component/blob/HEAD/admin/config.xml). - [Reader menu configuration](https://github.com/getbible/joomla-component/blob/HEAD/site/tmpl/app/default.xml). - [Loader plugin README](https://github.com/getbible/joomla-scripture-loader/blob/HEAD/README.md) and [plugin manifest](https://github.com/getbible/joomla-scripture-loader/blob/HEAD/getbibleloader.xml). The extensions are built with Joomla Component Builder. Contributions must respect the generated structure and be made in the appropriate source/build process so regeneration preserves the work. The Joomla extensions use GPL licensing; individual Bible translations retain their own copyright and distribution terms. --- # Librarian — Python Scripture library Resolve Bible references, retrieve chapters and verses, and search translations from Python. Librarian powers GetBible services and also works in standalone scripts or against a local API-compatible mirror. [Repository](https://github.com/getbible/librarian) · [Support](https://git.vdm.dev/getBible/support) · [All projects](/project/) The Python package name is `getbible`; the project repository is `librarian`. Package versions and Bible API versions are separate. The source reviewed here documents API v2 as its default; do not assume changing a package major version automatically selects Bible API v3. Select a release whose documented data contract matches your deployment. GetBible Librarian is the Python library used to resolve scripture references, retrieve verses, and perform Unicode-aware searches against GetBible API translations. It supports standalone scripts as well as threaded and multi-process API services. - Primary project home: - GitHub deployment and releases: - GetBible API v2: - PyPI: ## Installation ```bash python -m pip install getbible ``` Python 3.10 or newer is required. Version 3.0 narrows translation metadata in reference and search responses to six API fields. See the [field contract and migration](https://github.com/getbible/librarian/blob/HEAD/docs/TRANSLATION_METADATA.md) before upgrading from 2.x. This source prepares `3.0.0`; pin `getbible==3.0.0` after that version has been published. ## Retrieve scripture ```python import json from getbible import GetBible bible = GetBible() selection = bible.select("Genesis 1:1-3;John 3:16", "kjv") print(json.dumps(selection, ensure_ascii=False, indent=2)) encoded = bible.scripture("Psalm 23:1-6", "kjv") print(encoded) ``` `select()` returns the established chapter-keyed dictionary. `scripture()` returns the same structure encoded as JSON. Each chapter includes only these translation fields: `translation`, `abbreviation`, `lang`, `language`, `direction`, and `encoding`, as present in the source. Book/chapter metadata, `ref`, and `verses` keep their existing structure. ## Search scripture ```python import json from getbible import GetBible, SearchBible, SearchLimits bible = GetBible( search_limits=SearchLimits( max_work_units=50_000_000, max_response_bytes=4 * 1024 * 1024, deadline_seconds=5.0, ) ) criteria = SearchBible( words="all", match="whole_word", case_sensitive=False, scope="new_testament", books=("John", "1 John"), exclude=("darkness",), sort="canonical", limit=20, offset=0, ) response = bible.search("word life", "kjv", criteria) print(json.dumps(response, ensure_ascii=False, indent=2)) ``` Search responses contain three top-level objects: - `query`: normalized criteria, translation metadata, exact total, pagination, SHA, cache state, and deterministic search cost. - `results`: the same grouped scripture object format returned by `select()`. - `matches`: ordered per-verse match metadata, including score, occurrences, and matched terms. `query.translation` contains the same six translation fields used by chapter results. Full translation history and other supplemental metadata can be retrieved separately from the existing [translation catalogue](https://api.getbible.net/v2/translations.json). This keeps existing scripture templates reusable. With relevance sorting, `matches` is the authoritative cross-chapter order. Matching is derived from the text, not chosen by the caller. Librarian classifies every run of a verse and of a query by the writing system it is actually in, and applies that system's rules, so a bare query string works in every translation the API publishes: ```python bible.search("神爱世人", "cus") # Chinese, nothing delimits a word bible.search("사랑", "korean") # Korean, inside an inflected word bible.search("בראשית", "modernhebrew") # unpointed, reaches pointed text bible.search("λογος", "moderngreek") # unaccented, reaches accented text ``` There is no match mode to select and no script to detect. Applications carrying a helper that inspects the query and switches to `substring` should delete it. See [Scripture search](https://github.com/getbible/librarian/blob/HEAD/docs/SEARCH.md) for the matching policy, the response contract, and the 1.x migration. Search criteria may also be supplied as a JSON-decoded dictionary: ```python response = bible.search( "faith hope", "kjv", { "words": "phrase", "scope": "bible", "limit": 50, "offset": 0, }, ) ``` ## Cache behavior Reference retrieval keeps the lightweight chapter request path. Search downloads the selected full translation once, verifies it against `/v2/{translation}.sha`, and builds a compact in-memory postings index. By default, full translations are cached under the operating system's user cache directory and checked every seven days. Configure a shared service cache explicitly: ```python from datetime import timedelta from getbible import GetBible bible = GetBible( cache_dir="/var/cache/getbible", cache_ttl=timedelta(days=7), strict_freshness=False, require_checksums=True, ) ``` Remote production checksums are required. Full corpora and their independent books indexes are completely validated before immutable, content-addressed payloads are atomically committed. A last-known-good translation remains available during temporary repository or newly published integrity failures unless `strict_freshness=True`. Production caches are bounded by default. A service can warm its expected translation without issuing an artificial query and can expose cache counters to its internal metrics system: ```python bible = GetBible( cache_dir="/var/cache/getbible", search_corpus_limit=4, translation_cache_limit=4, ) bible.warm_translation("kjv") cache_state = bible.cache_info() ``` Atomically updated local mirrors can coordinate application response caches and worker-local invalidation with `source_operation()` and `transition_source()`. See [Cache validation and retention](https://github.com/getbible/librarian/blob/HEAD/docs/CACHING.md). Call `bible.close()` during worker shutdown, or use `GetBible` as a context manager in short-lived scripts. ## Documentation - [Usage and reference retrieval](https://github.com/getbible/librarian/blob/HEAD/docs/USAGE.md) - [Search criteria and response contract](https://github.com/getbible/librarian/blob/HEAD/docs/SEARCH.md) - [Translation metadata and the 3.0 migration](https://github.com/getbible/librarian/blob/HEAD/docs/TRANSLATION_METADATA.md) - [Cache validation and retention](https://github.com/getbible/librarian/blob/HEAD/docs/CACHING.md) - [Architecture](https://github.com/getbible/librarian/blob/HEAD/docs/ARCHITECTURE.md) - [Multi-process operations](https://github.com/getbible/librarian/blob/HEAD/docs/OPERATIONS.md) - [Development and releases](https://github.com/getbible/librarian/blob/HEAD/docs/RELEASING.md) - [AI and repository guidance](https://github.com/getbible/librarian/blob/HEAD/AGENTS.md) ## Source installation The primary project home remains on VDM Gitea: ```bash git clone https://git.vdm.dev/getBible/librarian.git cd librarian python -m venv .venv .venv/bin/python -m pip install -e . ``` The GitHub deployment mirror can also be cloned: ```bash git clone https://github.com/getbible/librarian.git cd librarian python -m venv .venv .venv/bin/python -m pip install -e . ``` ## Development ```bash ./scripts/run_release_gate.sh ``` This creates or reuses `.venv`, installs every development tool, and runs the local deterministic release gate. GitHub's manually dispatchable **CI** workflow is the authoritative Python 3.10–3.14 check. Live API tests remain separate and intentionally opt-in: ```bash ./scripts/run_release_gate.sh --live ``` See the [security and reliability release gate](https://github.com/getbible/librarian/blob/HEAD/docs/RELEASE_GATE.md) for manual commands, expected diagnostics, and GitHub workflow instructions. ## License GetBible Librarian is licensed under the GNU General Public License v2.0 or later. See [LICENSE](https://github.com/getbible/librarian/blob/HEAD/LICENSE). ## Usage and reference retrieval ### Client construction ```python from datetime import timedelta from getbible import GetBible, SearchLimits bible = GetBible( repo_path="https://api.getbible.net", version="v2", cache_ttl=timedelta(days=7), request_timeout=(3.05, 60.0), request_retries=3, cache_dir="/var/cache/getbible", strict_freshness=False, reference_cache_limit=5000, books_cache_limit=64, chapter_cache_limit=2048, search_corpus_limit=4, translation_cache_limit=4, cache_ttl_jitter=0.1, require_checksums=True, search_limits=SearchLimits(), ) ``` All constructor arguments are optional. The defaults use GetBible API v2 and the operating system's user cache directory. Checksums are required automatically for HTTP/HTTPS repositories and optional for local repositories; pass `require_checksums=True` for a production local mirror. In long-running applications, construct a long-lived client rather than one client per call. The client is safe for concurrent threads, and each process receives fork-safe HTTP sessions. The cache limits are per process. Set a limit to `0` to disable that in-memory cache or to `None` for unbounded retention. Unbounded full translations or search corpora are not recommended in long-running applications. Close network sessions during orderly shutdown: ```python bible.close() ``` Short-lived scripts may instead use `with GetBible() as bible:`. ### Select verses as a dictionary ```python from getbible import GetBible bible = GetBible() selection = bible.select("Genesis 1:1-3;John 3:16", "kjv") ``` Multiple references are separated with semicolons. Verse lists and ranges are supported: ```python selection = bible.select("John 3:16,18-21;Romans 8:1-4", "kjv") ``` The return value is grouped by translation, book number, and chapter: ```text kjv_43_3 kjv_45_8 ``` Each grouped object contains translation metadata, book and chapter metadata, the input references that contributed to the group, and an ordered `verses` list. Starting with 3.0, the only translation fields are `translation`, `abbreviation`, `lang`, `language`, `direction`, and `encoding`, copied as present in the source. The remaining chapter fields are `book_nr`, `book_name`, `chapter`, `name`, `ref`, and `verses`. The translation name is `translation`; `name` remains the chapter name. Valid empty optional metadata stays empty, and omitted optional metadata stays absent. History and other supplemental translation metadata are available separately from the existing [API translation catalogue](https://api.getbible.net/v2/translations.json). See [Translation metadata and the 3.0 migration](https://github.com/getbible/librarian/blob/HEAD/docs/TRANSLATION_METADATA.md) for the complete field contract and upgrade guidance. Direct references and references served after explicit cache warming follow the same contract. ### Select verses as JSON ```python encoded = bible.scripture("Psalm 23:1-6", "kjv") ``` `scripture()` calls `select()` and encodes the result with Unicode characters preserved. ### Validate input ```python reference_is_valid = bible.valid_reference("1 John 3:16", "kjv") translation_is_valid = bible.valid_translation("kjv") ``` `valid_reference()` verifies that the book alias and reference syntax can be resolved. The final chapter and verse existence check occurs during `select()`. `valid_translation()` checks the configured repository's `books.json` resource and caches the result for the configured cache interval. ### Resolve references directly ```python from getbible import GetBibleReference references = GetBibleReference() resolved = references.ref("First John 3:16,19-21", "kjv") print(resolved.book) print(resolved.chapter) print(resolved.verses) ``` Reference cache keys include the translation code. Frequently used entries are retained with a bounded least-recently-used policy. ### Resolve book numbers directly ```python from getbible import GetBibleBookNumber books = GetBibleBookNumber() number = books.number("1 John", "kjv") print(number) ``` The book resolver uses bundled Unicode-normalized alias tries. It tries the requested translation, KJV aliases, and then configured fallback translations. ### Local API-compatible repository The same client can read API v2-compatible files from disk. A string path or a `pathlib.Path` can be used: ```python from pathlib import Path from getbible import GetBible bible = GetBible(repo_path=Path("/srv/getbible-data"), version="v2") selection = bible.select("Genesis 1:1", "kjv") ``` Switching back to the remote API changes only `repo_path`: ```python bible = GetBible(repo_path="https://api.getbible.net", version="v2") ``` Local paths and HTTP(S) URLs use the same API-compatible layout and return the same scripture and search JSON contracts. Deterministic tests serve the local fixture repository over HTTP and compare both modes directly. Expected paths include: ```text /srv/getbible-data/v2/kjv/books.json /srv/getbible-data/v2/kjv/1/1.json /srv/getbible-data/v2/kjv.json /srv/getbible-data/v2/kjv.sha ``` The `.sha` resource is optional for local fixtures and required for remote repositories. Production local mirrors should opt into the same enforcement. ### Errors - Invalid reference syntax raises `ValueError`. - Missing translations and chapters preserve the existing `FileNotFoundError` contract. - Repository transport failures raise `RepositoryError`. - Invalid JSON raises `RepositoryResponseError`. - Checksum or structural failures raise `CacheIntegrityError`. - Invalid search criteria raise `SearchValidationError`. ## Scripture search ### The short version Pass a query string. Librarian works out how to read it. ```python from getbible import GetBible bible = GetBible() bible.search("faith hope", "kjv") bible.search("神爱世人", "cus") # Chinese, no spaces to tokenize bible.search("사랑", "korean") # Korean, inside an inflected word bible.search("בראשית", "modernhebrew") # unpointed, reaches pointed text bible.search("λογος", "moderngreek") # unaccented, reaches accented text ``` There is no match mode to choose, no script to detect, and no per-language branch to write. If you are carrying code that inspects a query and picks `match="substring"`, delete it — see [Migrating from 1.x](#migrating-from-1-x). The criteria that remain exist to *narrow* a search — a testament, a book, an exclusion. They do not tell the engine how to read a script. ### How matching is decided Librarian classifies every run of text by the writing system it is actually in, and applies that system's rules. The same rules run over the corpus at index time and over your query at request time, so a query can only match what the same analysis produced from the verse. | Family | Scripts | How a searchable unit is found | |---|---|---| | Alphabetic | Latin, Cyrillic, Greek, Armenian, Georgian, Coptic, Cherokee | Words between spaces. Accents fold. | | Continuous | Han, Hiragana, Katakana, Hangul, Thai, Lao, Khmer, Myanmar, Tibetan | Overlapping character n-grams with positions. | | Abjad | Hebrew, Arabic, Syriac, Thaana, Samaritan | Words between spaces. Vowel pointing folds. A word behind an attached particle is also reachable by its stem. | | Brahmic | Devanagari, Bengali, Tamil, Telugu, Kannada, Malayalam, Sinhala | Words between spaces. Combining marks are **kept** — they carry vowels. | Classification is by Unicode property, not by a hand-maintained range table and not by the translation's declared language tag. That matters because the tag is not always sufficient: the API carries `zh` with no script subtag for one Chinese translation, and blank language names for several others. A translation added to the API later is classified from its text, with no code change here. The response reports the decision so you never have to infer it: ```python bible.search("神", "cus")["query"]["analysis"] # {'script': 'continuous'} ``` #### Mixed scripts A verse or a query may hold more than one writing system. Each run keeps its own rules: ```python bible.search("Jesus 耶稣", "multi") # 'jesus' is matched as a whole Latin word; '耶稣' as a Han run ``` This is why the 1.x helper had to go. It flipped the *whole* query to substring as soon as it saw one Han character, so `all` started matching inside `small` and `shall`. #### Why whole-word and substring agree in continuous scripts Nothing in Han, kana, Hangul or Thai delimits a word, so there is no boundary for the two modes to disagree about. Both resolve the same way and both are exact. A caller cannot get this wrong by choosing either. A run of *n* characters is verified through its *n−1* overlapping bigrams: if bigram *i* sits at position *p+i* for every *i*, the run occurs at *p*. Positions settle it, so no verse text is rescanned and there are no false positives to filter. `神造` does not match `神神创造神` — the characters are present, the run is not. ### Criteria `SearchBible` and plain dictionaries use the same field names. Every field is optional. | Field | Values | Default | |---|---|---| | `words` | `all`, `any`, `phrase` | `all` | | `match` | `whole_word`, `substring` | `whole_word` | | `case_sensitive` | Boolean | `false` | | `scope` | `bible`, `old_testament`, `new_testament`, `deuterocanon` | `bible` | | `books` | Book names or numbers | Empty | | `diacritics` | `fold`, `exact` | `fold` | | `exclude` | Words that must not occur | Empty | | `proximity` | 0–100 intervening units | `null` | | `sort` | `canonical`, `relevance` | `canonical` | | `limit` | 1–1000 | `100` | | `offset` | Non-negative integer | `0` | ```python from getbible import GetBible, SearchBible bible = GetBible() response = bible.search( "word life", "kjv", SearchBible( words="all", scope="new_testament", books=("John", "1 John"), exclude=("darkness",), sort="relevance", limit=20, ), ) ``` `books` intersects with `scope`: `scope="new_testament"` with `books=("John",)` searches only John. Criteria may also be a JSON-decoded dictionary: ```python bible.search("faith hope", "kjv", {"words": "phrase", "limit": 50}) ``` #### Word modes - **`all`** (default): every distinct unit must occur in the verse. - **`any`**: at least one unit must occur. - **`phrase`**: units must occur in order at the spacing the query used. Punctuation between them is allowed. Because a continuous run occupies one position per character and a word occupies one, a phrase that crosses scripts is handled by the same arithmetic. #### Whole-word and substring `whole_word` matches complete units. `substring` also matches inside a word, so `great` reaches `greatest`. In continuous scripts the two are identical, as described above. Substring terms in **space-delimited** scripts must be at least `min_substring_length` characters (3 by default). A one- or two-letter Latin fragment matches a large share of any vocabulary and is a scan rather than a word. The floor does not apply to Han, Hangul, Thai, Hebrew, Arabic or Devanagari, where two characters are an ordinary word that the index answers exactly. In a mixed query the floor still applies to the Latin run alone. #### Case and diacritics Case-insensitive matching uses Unicode `casefold()`, which also unifies Greek final and medial sigma (ς/σ) and expands the iota subscript. Both sides of a search pass through the same rule, so the forms meet. `diacritics="fold"` is the default. It removes combining marks and folds precomposed letters that Unicode decomposition cannot reach — `đ`, `ø`, `ł`, `ħ`, `æ`, `þ` and peers. That is what lets `Duc Chua Troi` reach `Ðức Chúa Trời`, `λογος` reach `λόγος`, and `בראשית` reach `בְּרֵאשִׁית`. Folding is applied only where marks are accents or optional pointing. Brahmic and continuous scripts keep their marks, because there the marks carry vowels and removing them changes the word. `diacritics="exact"` turns folding off and distinguishes pointed from unpointed text. The 1.x spellings `sensitive` and `insensitive` are still accepted and map to `exact` and `fold`. Original verse text is never modified in the response. #### Exclusions and proximity `exclude` removes any verse containing one of the supplied words, analysed the same way as the query. `proximity` works with `words="all"` and permits that many intervening units. ### Response contract `results` is the same chapter-keyed object `select()` returns, so existing scripture templates keep working. `matches` is the authoritative order when sorting by relevance. In 3.0, `query.translation` contains only `translation`, `abbreviation`, `lang`, `language`, `direction`, and `encoding`, as present in the validated source. Those same translation fields appear at the top level of each chapter under `results`. No history, description, license data, or other supplemental translation metadata is included, even when the search returns no matches. Existing source values, accepted empty values, and omitted optional fields are preserved. Full translation details can be fetched separately from the [API translation catalogue](https://api.getbible.net/v2/translations.json). See the [3.0 migration](https://github.com/getbible/librarian/blob/HEAD/docs/TRANSLATION_METADATA.md#upgrade-from-2x). ```text query text criteria engine_version translation translation abbreviation lang language direction encoding sha total offset limit returned has_more cache checked_at stale analysis script ← how this translation was read cost work_units deadline_seconds expensive results __ translation, book and chapter metadata ref verses matches reference, book_nr, chapter, verse score, occurrences, terms ``` `engine_version` is `5`. It moves whenever matching or search-response semantics change, so a downstream result cache can be invalidated without waiting for a translation SHA to change. Version 3.0 increments it from `4` because translation metadata is slimmer, even though matching is unchanged. **Key your response cache on it.** `SearchBible.expensive` is available before a translation is loaded and is the right signal for budgeting expensive searches. Diacritic folding is no longer part of it: folding happens once during index construction and costs nothing per request. ### Performance and sharing Corpora live in a registry keyed by repository, translation and source SHA, and are shared by every `GetBible` in the process. Two clients — or a client per request — reach the same parsed verses and the same analysed index, so a service pays the parse-and-analyse cost once per translation version rather than once per object. ```python bible.warm_translation("cus") # build before traffic; returns the analysis report ``` An index build is bounded by `SearchLimits.index_build_seconds` (120 s default), not by the requesting call's `deadline_seconds`. A build serves every later request, so it must not be abandoned because one caller's request clock ran out. Concurrent first requests wait on one build rather than each starting their own. A search still refuses an unusable work budget before any index is built. ### Migrating from 1.x The following describes the matching changes introduced in 2.0. Upgrading to 3.0 also requires the [translation metadata migration](https://github.com/getbible/librarian/blob/HEAD/docs/TRANSLATION_METADATA.md#upgrade-from-2x). #### Delete the match-mode selection ```python # 1.x — remove this from getbible import requires_substring_matching if options.match == "whole_word" and requires_substring_matching(query): options = replace(options, match="substring") ``` `requires_substring_matching()` now returns `False` for every query. It remains exported so existing imports keep working and the branch above becomes a no-op without an immediate code change — but delete it. Leaving it in place is harmless; leaving *substring* forced on is not, because it loosens Latin terms in a mixed query. #### Behaviour that changes | | 1.x | 2.0 | |---|---|---| | Continuous scripts under default criteria | returned nothing | return the verses | | `diacritics` default | `sensitive` | `fold` | | Substring floor | all scripts | space-delimited scripts only | | `engine_version` | `2` | `4` | | Abjad with attached particle | missed | reachable by stem | Default searches return **more** than they did. If your application asserted a 1.x total, re-derive it. Invalidate any cached search results — `engine_version` is there to key that on. #### API that changed shape - `cache_info()["indexes"]` entries report `fold_diacritics` (boolean) instead of `diacritics` (string). - `warm_translation()` takes `diacritics="fold"` by default and returns an `analysis` block. - 2.0 changed `SEARCH_ENGINE_VERSION` to `4`; 3.0 changes it to `5` for the slimmer translation metadata contract. - `getbible.search` is a package. Every public name still imports from `getbible` and from `getbible.search`; the internal `_Matcher` class is gone. The 2.0 matching changes preserved `select()`, `scripture()`, and the `results` structure. Version 3.0 preserves their chapter/verse structure while removing supplemental translation metadata as documented above. ## Cache validation and retention Librarian uses separate strategies for lightweight reference retrieval and full-translation search. ### Result contract versioning Librarian 3.0 projects reference and search translation metadata to the six API fields described in [Translation metadata](https://github.com/getbible/librarian/blob/HEAD/docs/TRANSLATION_METADATA.md). Complete source payloads remain subject to the same validation and checksum rules; existing verified source caches can be reused. Application-owned response caches are a separate concern. Invalidate old reference responses or include the library response version in their keys. Include `SEARCH_ENGINE_VERSION` (now `5`, previously `4`) in search response keys. Neither a source SHA nor a source-generation namespace changes solely because the library's response contract changes. The same projection applies when reference chapters come from `warm_query()` or `reload_translation()`, so warming cannot reintroduce supplemental translation metadata. ### Chapter cache `select()` requests only the required chapter. The parsed chapter is retained in memory with direct verse lookup by verse number. Before retaining a chapter, Librarian retrieves and validates its SHA endpoint, downloads the JSON, validates the exact checksum, and validates every required chapter and verse field. After the configured interval, an unchanged SHA only updates freshness. Remote production repositories must publish the checksum; checksum-free local fixtures remain supported. No cache-maintenance background thread is created. ### Full-translation search cache The first search for a translation follows this sequence: 1. Acquire the in-process translation lock. 2. Acquire a cross-process file lock for the translation. 3. Read and validate an existing disk entry when present. 4. Retrieve `/v2/{translation}.sha`. 5. Retrieve and independently validate `/v2/{translation}/books.json`. 6. Download `/v2/{translation}.json` only when needed. 7. Calculate SHA-1 over the received bytes and compare it with the published SHA. 8. Validate every book, chapter, verse, numeric range, unique identifier, text ceiling, and the exact books-index correspondence. 9. Write the validated JSON as an immutable `objects/{sha}.json` payload. 10. Atomically commit versioned metadata that points at that content-addressed payload. 11. Build the immutable in-memory corpus and default postings index. When the source SHA is unchanged, Librarian updates only freshness state and retains the existing corpus and every already-built index. It does not reread and decode the full disk JSON or rebuild postings merely because the freshness interval elapsed. The published GetBible `.sha` value is the raw SHA-1 of the corresponding JSON bytes. HTTP/HTTPS repositories require it by default. Set `require_checksums=False` only for a controlled compatibility source; set `require_checksums=True` to enforce the production rule for a local mirror. ### Refresh interval The default interval is seven days: ```python from datetime import timedelta from getbible import GetBible bible = GetBible(cache_ttl=timedelta(days=7)) ``` Freshness is checked lazily on the next relevant request. There is no timer and no worker wake-up cycle. By default, each process deterministically shortens individual translation refresh intervals by up to 10 percent. This `cache_ttl_jitter` spreads source checks across many workers while never serving an entry beyond the configured TTL. Use `cache_ttl_jitter=0` for exact intervals. ### Cache directory Resolution order: 1. The `cache_dir` constructor argument. 2. `GETBIBLE_CACHE_DIR`. 3. `XDG_CACHE_HOME/getbible`. 4. `~/.cache/getbible`. For a multi-process application, configure one writable cache directory shared by all processes: ```python bible = GetBible(cache_dir="/var/cache/getbible") ``` The cache namespace includes a hash of the repository URL or path and its API version, preventing custom repositories from colliding with official API data. ### Cross-process safety `filelock` coordinates initial downloads and commits. Immutable payloads and metadata are written to temporary files, flushed, atomically moved into place, and followed by a directory `fsync`. Metadata is the commit point. A process crash can leave an unreferenced immutable object, but cannot make a partially validated object current. Metadata includes a validation-version marker so a future validator upgrade forces complete revalidation. Each process maintains its own in-memory corpus and indexes. The shared disk cache prevents every worker from downloading the full translation independently. Process-local caches use bounded least-recently-used retention. The defaults retain four translation snapshots and four search corpora per worker; chapter, book-list, and parsed-reference caches have separate limits. Eviction removes a lookup entry but never mutates an immutable corpus already borrowed by an active request. ### Last-known-good behavior When a verified disk translation exists and the source becomes temporarily unavailable, Librarian serves the cached translation and reports: ```text query.cache.stale = true ``` The original SHA remains in the response. This makes availability and source state explicit to the application. Use strict freshness when stale responses are not acceptable: ```python bible = GetBible(strict_freshness=True) ``` In strict mode, repository failures propagate instead of serving the older translation. Checksum, nested validation, and books-index mismatches never replace the last-known-good translation. Unless strict freshness is enabled, a validated last-known-good corpus remains available and is marked stale when a newly published upstream payload fails integrity validation. ### Source generations The repository URL/path plus API version produces a stable namespace. A versioned `source-generation.json` manifest records the active immutable mirror revision. `transition_source()` takes the cross-process writer barrier, runs the configured response-cache purge callback exactly once, commits the manifest, and invalidates worker-local books, chapters, full translations, indexes, and negative translation entries. A purge failure leaves the old generation committed. Use `source_operation()` to keep the generation stable while an application performs an external response-cache lookup, Librarian call, and response-cache write: ```python with bible.source_operation() as source: key = f"{source.cache_namespace}:{canonical_request_key}" response = response_cache.get(key) if response is None: response = bible.search(query, translation, criteria) response_cache.set(key, response) ``` The reader/transition barrier spans threads and Linux worker processes. A worker that observes a generation committed by another worker invalidates its process-local caches before serving that generation. Translation metadata also records the source generation; an older disk snapshot becomes immediately due for source revalidation, even when its ordinary cache TTL has not elapsed. ### Local repositories When `repo_path` is a directory rather than a URL, the full translation is validated and held in memory exactly as for a remote repository, but no copy is written under the cache directory: the source file already sits on the same disk, so a duplicate would buy nothing. The metadata file still records the validated SHA, the books-index checksum and the freshness timestamp, so processes share freshness state and a changed source is noticed at the next freshness check. A source file whose bytes no longer match the recorded SHA is simply re-read and re-validated. Remote repositories keep the content-addressed on-disk copy, which is what makes last-known-good fallback possible when the source is unreachable. ### Rotation Each translation metadata file points to one current content-addressed payload. Older unreferenced objects may be removed during controlled cache maintenance after all workers have observed the new generation. Lock and barrier files contain no scripture data. Use `GetBible.cache_info()` to observe current sizes, configured limits, evictions, source checks, downloads, stale fallbacks, loaded SHA values, and built index variants without exposing Scripture payloads. ### Resident cache controls (2.1) A freshness TTL is an interval before the next source verification. It is not an instruction to discard immutable data. After the interval elapses, the next request rechecks the source and retains the same corpus and built indexes when the SHA is unchanged. Requests do not extend the interval. Changed source revisions can be published immediately with `transition_source(revision)`; there is no need to wait for TTL expiration. ```python from datetime import timedelta from getbible import GetBible bible = GetBible( cache_ttl=timedelta(days=30), cache_ttl_jitter=0, chapter_cache_limit=100_000, chapter_cache_bytes=512 * 1024**2, search_corpus_limit=100, translation_cache_limit=100, translation_cache_bytes=512 * 1024**2, shared_corpus_limit=100, shared_corpus_bytes=1024**3, ) ``` These example limits illustrate the API; they are not measured requirements for a complete translation collection. Set count and byte bounds appropriate to the application. The library retains its existing conservative defaults unless explicitly configured. A byte or count limit takes precedence over residency: least-recently-used entries can be evicted before their TTL when a bound is reached. A single oversized request may execute without retaining its result in a cache. No new background thread, eager translation download, or periodic rebuild is introduced by construction. | Parameter | Scope | `None` | `0` | | --- | --- | --- | --- | | `chapter_cache_limit` | Chapters retained by this client | No count limit | No retention | | `chapter_cache_bytes` | Estimated bytes in those chapters | No byte limit | No retention | | `translation_cache_limit` | Full validated snapshots in this client | No count limit | No retention | | `translation_cache_bytes` | Estimated bytes in those snapshots | No byte limit | No retention | | `search_corpus_limit` | This client's retained corpus references | No count limit | No client retention | | `shared_corpus_limit` | Process-wide strong corpus registry | Constructor leaves registry unchanged | No registry retention | | `shared_corpus_bytes` | Process-wide registry and this client's corpus references | No byte limit when explicitly configured | No retention | For shared settings, configure one policy for the process. A later explicit shared-registry configuration applies to the same process-wide registry. Changing the registry does not forcibly invalidate immutable objects already borrowed by another client or active request. A weak lookup table allows those objects to be reused without parsing and indexing the same SHA again, while not preventing their release once all borrowers let go. This weak table is bounded by the number of objects that are actually alive, not by historical request keys. In-flight data and other clients' references can exceed the registry's retained-byte limit; these are not operating-system memory limits. Reconfiguration validates every argument before applying any changes. Omitted arguments remain unchanged, and existing objects and freshness timestamps are preserved when capacity grows: ```python state = bible.configure_cache( cache_ttl=timedelta(days=7), cache_ttl_jitter=0, chapter_cache_limit=200_000, shared_corpus_limit=150, ) ``` `configure_cache(shared_corpus_limit=None)` is invalid: unlike the constructor's "leave unchanged" default, a registry resize requires a non-negative integer. To leave the setting unchanged, omit it. Set all retention bounds deliberately rather than removing both count and byte limits from a client cache. ### Explicit query and search lifecycle ```python # The normal lazy path fetches only the requested chapter: bible.select("John 3:16", "kjv") # Optional targeted prewarming uses that same chapter path: bible.warm_query("kjv", references=["John 3:16", "Genesis 1:1"]) # Explicitly warm all query chapters from a validated full snapshot. # This does not build a search corpus or index: query_state = bible.warm_query("kjv") # Existing search warm-up builds the selected analysed search view: search_state = bible.warm_translation("kjv") # Drop resident views, keeping cached source bytes and source repository files: bible.drop_translation("kjv") # Force source verification and rebuild either or both views: bible.reload_translation("kjv", target="both") ``` `warm_query` returns both the amount loaded and the amount still retained. They may differ when the selected count/byte capacity cannot hold all chapters. `references` must be a sequence of strings, not a comma-separated string. `reload_translation` accepts `search`, `query`, or `both`, plus optional query references. Source bytes are verified before the current views are discarded; configured last-known-good fallback is reported as stale. Existing repository failure and strict-freshness rules apply. Explicit drop/reload/reconfiguration excludes active source readers during its administrative operation. Calls are intended for administration, not for every request. They affect this client's resident views and the process registry; independent clients or worker processes must each receive their own operation. `transition_source` remains the shared revision/invalidation mechanism. `drop_translation(code, disk=True)` additionally deletes that translation's Librarian-owned metadata and referenced downloaded cache object. It never deletes repository source files or another translation's cache objects. It does not revoke the source generation or cancel an immutable response already held by application code. ### Memory measurements `cache_info()` returns JSON-safe metadata, including: - `ttl_seconds` and `freshness_policy`; - `query_translations[code]`: retained chapter count, estimated bytes, and how many chapters are due for lazy revalidation; - `search_corpora.translations[code]`: SHA, verification time, stale state, verse count, built index policies, and estimated bytes; - `translation_cache.translations[code]`: snapshot size estimates and state; - `translation_cache.source_generation` and the existing `source` manifest; - `shared_registry`: retained entries/bytes, bounds, hits, misses, evictions and active corpus-build locks. The measurement label is `estimated_python_objects_not_rss`. These values count reachable Python data structures and native array buffers, not interpreter heaps, memory fragmentation, process RSS, or peak temporary allocations. Shared objects can appear in more than one category or worker estimate, so those values must not be summed and presented as actual physical memory consumption. Byte sizing is calculated during insertion/index construction and reused for warm requests; it does not walk an entire translation for every query or chart. An active request, a cold build, or old/new generations overlapping in application code require additional headroom beyond retained cache limits. ## Multi-process operations Librarian is designed to be held as a long-lived dependency in each process of an application. Retrieval and search are independent capabilities; an application that serves both under load often runs them in separate processes so search CPU and memory cannot starve retrieval, and the library supports either arrangement. ### Client lifetime Create one client during application initialization or once per worker. Do not construct a new client for every call. ```python from getbible import GetBible, SearchLimits bible = GetBible( cache_dir="/var/cache/getbible", require_checksums=True, search_limits=SearchLimits(deadline_seconds=5.0), ) def execute_scripture_query(reference: str, translation: str) -> dict: return bible.select(reference, translation) def execute_search_query(query: str, translation: str, criteria: dict) -> dict: return bible.search(query, translation, criteria) ``` The example functions are framework-neutral. They illustrate Librarian calls only; what surrounds them belongs to the application. ### Worker processes Each worker has its own in-memory chapter cache, corpus objects, and postings indexes. Workers share the disk translation cache through process locks and atomic replacement. Configure the cache directory so every worker identity can read and write it. Do not place it inside an ephemeral per-request directory. ### Pre-fork servers Librarian detects process changes and does not reuse an HTTP session created by the parent process. This makes the client safe when an application server preloads the module before forking workers. To share as much read-only memory as the operating system permits, a deployment may warm its most-used translation and default index before forking: ```python from getbible import GetBible bible = GetBible(cache_dir="/var/cache/getbible") bible.warm_translation("kjv") ``` Whether preloading is beneficial depends on the server, worker lifecycle, and available memory. Benchmark both preloaded and per-worker warm-up configurations. ### Threads Repository sessions are thread-local. Normal cache reads are concurrent. Missing corpus and index construction is coordinated so only one thread performs the expensive work in a process. ### Warm-up The first search for a translation includes disk or network loading, JSON parsing, corpus construction, and index construction. Warm the expected translation before marking a newly started worker ready when startup latency matters. Do not warm every case and diacritic variant unless production traffic requires them; each variant consumes additional memory. `warm_translation()` accepts `case_sensitive` and `diacritics` when a non-default index is known to be common. It returns an `analysis` block reporting how the translation was read, which is worth recording once per deployment: ```python bible.warm_translation("kjv", case_sensitive=True, diacritics="exact") ``` ### Shared corpora Parsed translations and their analysed indexes live in a registry shared by every `GetBible` in the process, keyed by repository, translation and source SHA. A service that constructs a client per request, or holds several clients for different configurations, pays the parse-and-analyse cost once per translation version rather than once per object. Keying on the SHA is what makes this safe: when a translation changes upstream, the new SHA produces a new entry instead of silently reusing stale verses. The superseded entry is evicted by ordinary LRU pressure. Sharing is per process. Pre-fork workers each hold their own registry unless the parent warmed the translation before forking, in which case the pages are shared copy-on-write — see [Pre-fork servers](#pre-fork-servers). ### Index build window Index construction is bounded by `SearchLimits.index_build_seconds` (120 seconds by default), which is deliberately separate from the per-request `deadline_seconds`. A build serves every later request, so it must not be abandoned because one caller's request clock ran out. Under 1.x a build charged to a request deadline could time out, cache nothing, and leave the next request repeating the same work and failing the same way — a stall the service could not recover from on its own. Concurrent first requests now wait on a single build. Raise `index_build_seconds` only if a very large translation genuinely needs longer on your hardware; warming before traffic is the better answer. A request whose work budget cannot cover the corpus is still refused before any index build starts. ### Bounded memory Every growing process-local cache is bounded by default: | Cache | Constructor argument | Default entries | |---|---|---:| | Parsed references | `reference_cache_limit` | 5,000 | | Translation book lists | `books_cache_limit` | 64 | | Retrieved chapters | `chapter_cache_limit` | 2,048 | | Full search corpora and indexes | `search_corpus_limit` | 4 | | Validated translation snapshots | `translation_cache_limit` | 4 | These limits apply to each process, not to the whole application. Size process memory for the largest translations and index variants actually used. Use `0` to disable retention or `None` for an unbounded cache. Avoid `None` for full translations and corpora when many translations are in play. For a retrieval-only process, set `search_corpus_limit=0` and `translation_cache_limit=0`. For a search-only process, set `reference_cache_limit=0` and `chapter_cache_limit=0`, then choose small corpus and translation limits based on measured RSS. Processes can read the same repository but should never share a writable cache directory. ### Pagination limits The library restricts a page to 1,000 matches. An application may impose a smaller maximum. Exact totals are reported independently of the returned page. ### Deadlines `SearchBible.expensive` is deliberately corpus-independent, so an application can classify a search before it runs: ```python criteria = SearchBible.from_value(filters) if criteria.expensive: ... # budget it however the application sees fit response = bible.search(query, translation, criteria) ``` The default cooperative Librarian deadline is 5 seconds. An application that wraps a call in a timeout of its own should set that timeout above the Librarian deadline, leaving time to translate a typed failure into whatever it reports to its callers. Repository connect/read timeouts govern source refresh separately. A timeout imposed from outside the process does not stop Python work: it abandons the caller but does not itself cancel matching. ### Timeouts and retries Defaults: - Connect timeout: 3.05 seconds. - Read timeout: 60 seconds. - Retries: 3 for GET requests. - Retry statuses: 429, 500, 502, 503, and 504. Override these through `GetBible()` when the hosting environment requires different limits. ### Monitoring An application should record: - call duration for retrieval and for search; - translation, criteria mode, and page size; - cache `stale` state; - repository and checksum failures; - process memory after each newly loaded translation/index mode; - search totals and response sizes; - rejected criteria. `cache_info()` provides JSON-safe sizes, limits, hit/miss/eviction counters, loaded translation SHA values, stale flags, and currently built index variants. It deliberately excludes verse text, source paths, and search terms: ```python state = bible.cache_info() metrics.gauge("librarian.search_corpora", state["search_corpora"]["size"]) metrics.counter("librarian.search_evictions", state["search_corpora"]["evictions"]) ``` Read these counters periodically or at shutdown. Do not call `cache_info()` on every call solely for logging. ### Shutdown Call `bible.close()` from the application's shutdown hook after calling threads have stopped. It closes every HTTP session created by that process. Short-lived scripts can use `GetBible` as a context manager. `cache_info()` never contains verse text or search terms, so it can be logged freely; what an application logs about its own callers is its own decision. ### Benchmarking ```bash python benchmarks/search_benchmark.py \ --translation kjv \ --query "faith hope" \ --iterations 10000 \ --workers 1 \ --cache-dir /var/cache/getbible ``` The benchmark reports initial warm-up time, exact match total, average warm latency, and queries per second. Use process-level load testing against the actual API service to validate worker count, network stack, serialization, and response compression. ## Translation metadata and the 3.0 migration ### Response field contract Librarian 3.0 deliberately limits translation metadata in reference and search results to the fields used by API v2 chapter responses, such as [Genesis 1 in the KJV](https://api.getbible.net/v2/kjv/1/1.json). | Field | Meaning | KJV value | |---|---|---| | `translation` | Full translation name | `King James Version` | | `abbreviation` | API translation identifier | `kjv` | | `lang` | Short language code supplied by the API | `en` | | `language` | Full language label supplied by the API | `English` | | `direction` | Text direction | `LTR` | | `encoding` | Text encoding label | `UTF-8` | The KJV translation metadata is: ```json { "translation": "King James Version", "abbreviation": "kjv", "lang": "en", "language": "English", "direction": "LTR", "encoding": "UTF-8" } ``` These are the only allowed translation keys. The projection preserves source values without renaming fields, shortening language labels, normalizing their contents, or inventing defaults. Existing source validation still applies: optional fields omitted by a valid source remain absent, and accepted empty values remain empty. A translation name is always `translation`; the chapter's `name` still means its chapter name. ### Where the projection applies | Public result | Translation metadata location | |---|---| | `select(reference, translation)` | Top level of each chapter under its existing chapter key | | `scripture(reference, translation)` | The same chapter objects, encoded as JSON | | `search(query, translation)` | `query.translation` and the top level of every chapter in `results` | | `search_json(query, translation)` | The same search envelope, encoded as JSON | For example, `select("Genesis 1:1", "kjv")["kjv_1_1"]` combines those translation fields with the existing `book_nr`, `book_name`, `chapter`, `name`, `ref`, and `verses` fields. In a search, `response["query"]["translation"]["translation"]` is the full translation name; `response["query"]["translation"]["abbreviation"]` is its identifier. The same contract applies to direct chapter reads, retained chapters, and chapters populated by `warm_query()` or `reload_translation()`. Empty searches and pages beyond the final result still include the projected `query.translation`; their `results` and `matches` remain empty. The chapter-keyed dictionary, book/chapter identity, references, and complete verse dictionaries retain their existing structure. Search keeps its `query`, `results`, and `matches` envelope, including criteria, totals, pagination, matching details, source SHA, cache state, analysis, and cost metadata. The projection does not change matching or verse text. ### Complete translation metadata Translation history, descriptions, distribution/license data, source details, and every other supplemental translation field are excluded from query and search responses. Fetch the existing [API translation catalogue](https://api.getbible.net/v2/translations.json) separately when those details are needed. It contains metadata for all translations, so a client can retain that catalogue and use `abbreviation` to associate query/search results with it. For a custom API-compatible repository, use its corresponding catalogue if it provides one. This is a result-assembly change. Librarian still loads and validates complete source payloads, verifies checksums, preserves last-known-good translations, and uses the lightweight chapter path for ordinary references. It does not fetch the catalogue as part of a search or reference request. ### Upgrade from 2.x Removing fields is an intentional breaking compatibility decision and the reason for version `3.0.0`. Earlier `query.translation` copied every top-level translation field except `books`; warmed reference chapters could carry the same supplemental metadata. Neither pass-through behavior is part of the 3.0 contract. Do not restore it when adding source fields or changing cache paths. 1. Keep using the six API fields at their existing locations. Consumers that need additional translation details should obtain the catalogue separately and look up the result's `abbreviation`. 2. Update response schemas, expected output, and consumers that required the removed fields. Do not require optional metadata omitted by a valid source or replace valid empty values with guessed labels. 3. Invalidate saved reference responses that contain old metadata. Include the package/response contract version in any application-owned reference-result cache key; the source SHA alone does not identify the response contract. 4. Invalidate saved search responses or key them with the exported `SEARCH_ENGINE_VERSION`, now `5`. Its previous value was `4`; the source SHA can stay the same while the response shape changes. Source-generation namespaces alone do not distinguish library response versions. 5. Pin `getbible==3.0.0` once the existing release workflow publishes it. Before publication, test this checkout or a wheel built from the reviewed commit; an immutable full-commit Git dependency pin can identify that same source revision. The version change in this repository does not itself publish a package or create a release tag. Verified source translation caches do not need to be deleted for this migration: the projection happens when results are assembled. Matching criteria and source-integrity validation keep their existing behavior. ## Support and source documentation For questions about this project, installation, unexpected output, or contributing, use the [single GetBible support desk](https://git.vdm.dev/getBible/support). Include the project, installed release or commit, operating system, relevant API version, and a minimal reproduction. General enquiries can be sent to [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). This guide follows the [repository README](https://github.com/getbible/librarian/blob/HEAD/README.md) and [USAGE](https://github.com/getbible/librarian/blob/HEAD/docs/USAGE.md), [SEARCH](https://github.com/getbible/librarian/blob/HEAD/docs/SEARCH.md), [CACHING](https://github.com/getbible/librarian/blob/HEAD/docs/CACHING.md), [OPERATIONS](https://github.com/getbible/librarian/blob/HEAD/docs/OPERATIONS.md), [TRANSLATION METADATA](https://github.com/getbible/librarian/blob/HEAD/docs/TRANSLATION_METADATA.md). Scripture and study resources retain their own source licences; a software licence does not relicense the texts. --- # Loader — embed Scripture in any website Add Bible verses to articles, sermons, study pages, or an existing application with a small JavaScript include and ordinary HTML. Loader finds elements marked with the `getBible` class, resolves their references through [Query API v2](/api/query/v2/), and displays Scripture inline, in a tooltip, or in a modal. [Repository](https://github.com/getbible/loader) · [Support](https://git.vdm.dev/getBible/support) · [Joomla integration](/project/joomla/) ## A complete working page Save the following as an HTML page and serve it from your website. The script is pinned to the documented Loader release, `3.1.0`, so a new upstream version cannot change your site without review. ```html Scripture with GetBible Loader

Read John 3:16

John 3:16
``` No GetBible API token is needed for this public reference request. Your content remains visible as a written reference before JavaScript loads. The returned translation text and its upstream terms still determine how Scripture may be used. ## Choose the display | Format | Intended use | Markup | |---|---|---| | `inline` | Put the verse directly in the document | `data-format="inline"` | | `tooltip` | Show Scripture around a short reference | `data-format="tooltip"` | | `modal` | Open a larger passage without leaving the page | `data-format="modal"` | The source default is **inline**. Set the format explicitly when authoring reusable content. ```html

Read Psalm 23:1-6 and Romans 8:1-4.

``` Loader includes adapters for Bootstrap, Foundation, Tailwind, and UIkit, as well as its base display implementations. Use the repository's matching [framework examples](https://github.com/getbible/loader/tree/master/tests) when integrating with an existing CSS/JavaScript framework. Framework assets and their correct versions remain the host page's responsibility. ## Data-attribute reference These defaults come from the Loader's [Action class](https://github.com/getbible/loader/blob/master/src/js/core/Action.js). | Attribute | Accepted value | Default | Purpose | |---|---|---|---| | `data-format` | `inline`, `tooltip`, `modal` | `inline` | Display behavior | | `data-translation` | One abbreviation or a semicolon-separated list | `kjv` | Translation selection | | `data-show-book-name` | `0` or `1` | `0` | Include the book name | | `data-show-reference` | `0` or `1` | `1` | Include the resolved reference | | `data-show-local-reference` | `0` or `1` | `0` | Show the reference as authored locally | | `data-show-translation` | `0` or `1` | `0` | Include the full translation name | | `data-show-abbreviation` | `0` or `1` | `0` | Include the translation abbreviation | | `data-show-language` | `0` or `1` | `0` | Include the language name | | `data-show-language-code` | `0` or `1` | `0` | Include the language code | | `data-show-bible-link` | `0` or `1` | `0` | Include a link to a Bible reader | | `data-bible-url` | Bible-reader base URL | Historical `https://getBible.net/` | Set the reader destination | When `data-show-local-reference="1"`, Loader disables the resolved-reference display. Setting a custom `data-bible-url` automatically enables the Bible link. **Set the reader URL explicitly to `https://getbible.life/` when enabling Bible links.** The historical Loader default points to `getBible.net`, which now hosts the project documentation. A custom reader destination must implement the Joomla component's translation/book/chapter/verse routes. The documentation host does not expose those reading routes. ## Multiple translations Translation abbreviations are lowercased and separated with semicolons. Fetch the current [translation catalogue](https://api.getbible.net/v2/translations.json) to discover available codes. ```html
John 3:16,19
``` Each translation is fetched independently. Do not infer the available translations or their licensing from a fixed count in an old article. ## Reference syntax | Selection | Example | |---|---| | A single verse | `John 3:16` | | Several verses from one chapter | `John 3:16,18,21` | | A range in one chapter | `John 3:16-19` | | Separate passages | `John 3:16-19;1 John 3:16` | | Common abbreviated book name | `Jn 3:16` | Use explicit book, chapter, and verse coordinates in published examples. Aliases are resolved by the Query service using Librarian's language-aware reference data. Each semicolon-separated reference should target one chapter. An unsupported alias, malformed reference, or missing passage needs correction; current Query API error handling should be used instead of relying on historical fallbacks. To inspect the exact upstream request independently of your page: ```bash curl --fail-with-body --silent --show-error \ 'https://query.getbible.net/v2/kjv/John%203%3A16' ``` The Query API returns chapter-keyed Scripture groups rather than a single unwrapped verse. Loader handles this grouping for you. ## Loading and caching behavior The distributed script registers a `DOMContentLoaded` listener, scans `.getBible` elements, and creates a Loader for each matching element. Include the script in the initial page with `defer`, as in the complete example. The default bundle does not advertise a public rescanning API for content injected after that event. Reference/translation responses are stored in the page origin's `localStorage` with a 30-day timestamp expiry. This is a reference cache; it is not the hash-verified offline corpus used by the newer reader applications. Browser storage restrictions, malformed stored values, or a full storage quota can surface as loading errors. The default API URL is fixed in the [Api class](https://github.com/getbible/loader/blob/master/src/js/core/Api.js) to `https://query.getbible.net/v2/`. The documented HTML attributes do not include an API-version override. Test the data contract before adapting the source to another endpoint. ## Host the bundle yourself The repository commits both development and minified bundles under `dist/js/`. For a deployment that does not use a CDN, copy the reviewed `getBible.min.js` into your site's assets and reference that local asset from the page. To rebuild from the repository: ```bash git clone https://github.com/getbible/loader.git cd loader npm ci npm run build ``` The build uses Rollup. Commit or distribute the generated bundle through your own release process. ## Troubleshooting | Symptom | Check | |---|---| | Only the original reference is visible | Verify that the bundle loaded before `DOMContentLoaded` and that the element has the exact `getBible` class | | Fetch fails | Inspect the browser Network panel and test the same reference with cURL | | Tooltip/modal appearance is wrong | Compare against the matching framework example and check the host framework assets | | Reference text works in one translation only | Confirm the abbreviation exists and try an explicit book name | | A Bible link opens documentation | Set `data-bible-url="https://getbible.life/"` | | Old Scripture persists | Check the Loader's 30-day origin-local cache and test with a clean browser profile | For assistance, use the [GetBible support desk](https://git.vdm.dev/getBible/support). Include the page URL or minimal HTML, browser, Loader version, translation, reference, and failing request. General enquiries: [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). ## Source and licence This guide consolidates the [Loader README](https://github.com/getbible/loader/blob/master/README.md), [entry point](https://github.com/getbible/loader/blob/master/src/js/getBible.js), [configuration](https://github.com/getbible/loader/blob/master/src/js/core/Action.js), [API client](https://github.com/getbible/loader/blob/master/src/js/core/Api.js), and [cache implementation](https://github.com/getbible/loader/blob/master/src/js/core/Memory.js). Loader uses the [MIT licence](https://github.com/getbible/loader/blob/master/LICENSE.md). Scripture retains its own source terms. --- # Robot — Scripture inside Telegram GetBible Robot brings reading, reference lookup, full-text search, selections, bookmarks, and Scripture posting into Telegram. The Mini App reads public Bible data directly while Robot handles Telegram sessions and authoritative posting. [Repository](https://github.com/getbible/robot) · [Support](https://git.vdm.dev/getBible/support) · [All projects](/project/) The current reader uses Bible API v2 and Query API v2. Full-text search runs through Librarian on the Robot server. A Telegram bot token is needed to run your own bot; it is separate from access to the public GetBible data APIs. GetBible Robot is a hardened Telegram interface for Scripture reading, search, history, bookmarking, selection, copying, and posting. The Mini App uses GetBible API V2 directly for public Scripture data. Temporary selections, durable device-local history, and the public Scripture cache stay in the browser; compact personal bookmarks and the last-read coordinate additionally synchronize through Telegram Mini App storage when the client supports it. Robot remains the authenticated Telegram control plane and the sole adapter for Librarian full-text search. ## Architecture at a glance | Responsibility | Implementation | |---|---| | Public chapters and indexes | Bible API v2, called by Mini App | | Reference resolution | Query API v2 | | Selection and copy | Browser memory | | Reading history | Scoped localStorage | | Public Scripture cache | IndexedDB | | Personal bookmarks and last read | Local storage with Telegram DeviceStorage/CloudStorage support | | Global-topic visibility | Scoped localStorage and DeviceStorage | | Sessions, preferences, Post, backup | Robot | | Full-text search | Robot → Librarian | Only full-text search and search pagination use Librarian. A normal reader action does not pass through Robot. Selecting, unselecting, reordering, clearing, highlighting, counters, and copying are browser-owned and issue no Robot request. Final Post is the only selection synchronization boundary; Robot validates authoritative Scripture before Telegram delivery. See [Architecture](https://github.com/getbible/robot/blob/HEAD/docs/ARCHITECTURE.md), [Browser data](https://github.com/getbible/robot/blob/HEAD/docs/BROWSER_DATA.md), [Mini App](https://github.com/getbible/robot/blob/HEAD/docs/MINI_APP.md), and [Interactions](https://github.com/getbible/robot/blob/HEAD/docs/INTERACTIONS.md). ## Commands ```text /bible 1 John 3:16 /bible John 3:16-19;1 John 3:10-17 /bible Gen 1:1-5 codex /bible Ps 1:1-5 aov /bible /search grace /search /help ``` `/get` and `/getbible` are aliases of `/bible`. - An explicit `/bible ` keeps the native fast path and posts immediately. - Bare `/bible` opens the Mini App reader at the saved translation/book/chapter/verse. - `/search ` opens Librarian-backed results in the Mini App. - Bare `/search` opens the search form. - Intermediate browsing never floods the chat. ## Mini App behavior The Mini App has Home, Search, Bible, History, and Selected in one permanent bottom navigation. Bookmarks is a Home-managed surface rather than a sixth footer action. Home offers **Search Scripture** and **Read the Bible**, followed by current Selected, History, and Bookmarks summaries; the History summary appears only when history exists. Search and Bible retain the translation control; Home, History, Selected, and Bookmarks show only the centered getBible icon in the top bar. - Translation metadata, localized books, chapter maps, chapter text, and hashes come directly from Main API. - Explicit references use Query API. - Public data is cached in bounded IndexedDB with exact-scope hash revalidation and in-memory fallback. - Reader and search verses normalize to one descriptor. - Coordinate identity is translation, book number, chapter, and verse. - A verse selected in Search is selected in Reader and vice versa. - A second click unselects immediately. - Selected verse number/body styling, ARIA state, range boundaries, counters, and copy output derive from `BrowserSelectionStore`. - Failed Post preserves the complete ordered browser selection. - Successful Post clears it. - A bounded, coordinate-only reading history remembers opened chapters and selected verses in user-scoped browser `localStorage`. Revisiting the same chapter or exact verse across translations moves its existing entry to the top. History remains available from every surface, displays verse text from the bounded public chapter cache, and opens each coordinate in the currently selected translation. Entries can be removed individually or cleared together. - Selecting a reader verse reveals a compact bottom-right ellipsis. The anchored bookmark menu opens only when that control is activated. Each of the 800 personal canonical verse records may belong to multiple colored topics without consuming another verse slot; assigning an existing translation-independent coordinate updates its record instead of duplicating it. - The Bookmarks surface keeps personal and global verse links in one topic list. Compact **Add all** and **Remove all** controls sit above topic search, while each topic retains its own add/remove controls. Global links carry a **G** marker and may also be hidden individually. Adding a topic or the complete catalog restores its hidden links without duplicating them. The built-in catalogue contains the repository's reviewed topic-to-verse links. Its scoped visibility, exclusions, and legacy numeric-topic mapping are mirrored through Telegram `DeviceStorage` when supported, so a Telegram Desktop WebView can restore them after its browser storage is discarded. They never enter CloudStorage, personal synchronization, or backups. Global rows resolve their verse text in the currently selected translation without copying that text into personal storage. - A plus-card after the topic list creates personal topics. Topic detail keeps editing in context: every topic color is user-editable, custom names support inline confirm/cancel editing, and global names remain read-only server-owned metadata. Removing a topic warns that its linked verse assignments will also be removed; removing a global topic is user-local and **Add all** restores it. Approved contributors alone see the collapsible **Manage Contribution** panel immediately below Global topics. - **Sync now** drips the contribution to Robot in bounded idempotent batches of at most 50 events over the same session-authenticated same-origin request path search uses. Snapshot-derived events carry deterministic content-derived IDs, so a redelivered event replays safely, and every response returns the complete result set: receipt counts, the full contributor status, and the live catalogue revision/checksum. The final batch settles the panel in one round trip. Alongside the session bearer, every batch body carries the short-lived `contribution_token` that only approved contributors receive inside JSON payloads — never a custom header — and the drip runs on its own contribution rate budget (`CONTRIBUTION_RATE_CAPACITY`, `CONTRIBUTION_RATE_REFILL_PER_SECOND`) separate from the public search limits. It requires no WebSocket, additional port, or repeated raw Telegram `initData` header. - Personal bookmark aggregate version 3, topics, the clearable recently-used topic order, the active topic, and the compact last-read coordinate reconcile by timestamp across scoped `localStorage`, Telegram `DeviceStorage`, and Telegram `CloudStorage`; CloudStorage uses compact topic indexes for each bookmark. Unsupported or temporarily unavailable Telegram storage degrades to the local copy without blocking reading. Global visibility/exclusions use DeviceStorage only; history, selections, the global catalog itself, and downloaded Scripture never enter Telegram storage. - Bookmark recovery supports both a local bounded JSON download/import and **Back up to chat**. Chat backup sends the validated JSON document to the user's private bot chat with an owner-bound **Restore bookmarks** button. A restore creates a fresh short-lived Mini App launch, merges only after user confirmation, persists the result, and explicitly acknowledges that launch; the backup message itself remains available for later recovery. New backups use compact version 4 `colorIndexes`; version 1, 2, and 3 documents remain importable. Browser display text and UI identifiers are not final posting authority. ## Security boundaries The public Mini App shell is not an authentication boundary. Robot protects actions with: - Telegram-signed `initData` at the initial session exchange, fresh unless a one-time launch token the robot itself issued proves the live tap; - owner-bound, one-time launch tokens; - bounded opaque sessions with a ninety-day default absolute lifetime; - per-batch contributor-authority rechecks in the durable contribution store; - user/chat/topic binding; - bounded request bodies and output; - per-user, per-chat, and trusted-client rate limits; - idempotent final posting; - escaped Telegram HTML and UTF-16-aware chunking; - correlation IDs and user-safe errors. The bot token remains server-side. It is never placed in HTML, JavaScript, URLs, browser storage, public API traffic, or logs. Public API transport: - uses only `https://api.getbible.net/v2/` and `https://query.getbible.net/v2/`; - omits credentials and cookies; - sends no Telegram data; - rejects redirects; - uses `no-referrer`; - enforces timeout, size, schema, and coordinate bounds. ## Cache integrity The browser cache stores public, identity-free data only under a versioned namespace. It has bounded record count, bounded total bytes, bounded per-record bytes, least-recently-used eviction, and request coalescing. Every cached scope stores its published SHA-1 and is revalidated at least weekly. Parent hash changes invalidate descendants. Chapter replacement requires stable pre/post hashes, exact-byte SHA-1 verification, bounded schema validation, and atomic replacement. Failed validation never overwrites a valid record. ## Search isolation Search and pagination alone use Librarian. They have separate bounded execution, timeout, cache, and circuit behavior so expensive corpus work cannot consume every direct-reference permit. Search failure does not affect reader navigation. Main API or Query API failure does not invalidate Telegram authentication. Librarian derives the matching strategy from the query text, so the robot ships no per-language branch and no match-mode detector. Chinese, Japanese, Korean, Thai, Lao, Khmer, Myanmar and Tibetan queries reach the index under the default filters, unaccented Greek reaches accented text, and an unpointed Hebrew or Arabic stem reaches the word behind its attached particle. See [Search](https://github.com/getbible/robot/blob/HEAD/docs/SEARCH.md). ## Runtime and deployment Supported runtime: - Python 3.10, 3.11, 3.12, 3.13, or 3.14; - Linux Docker/OCI for portable deployment; - Linux with `systemd` for host-native deployment; - a Telegram bot token; - outbound HTTPS to Telegram and GetBible API; - public HTTPS when the Mini App is enabled. The host deployment keeps health, webhook, and Mini App listeners separate and loopback/private behind Caddy. Docker contains no Caddy or systemd and leaves TLS/ingress to the platform. Published images are available from GitHub Container Registry: ```bash docker pull ghcr.io/getbible/robot:2.1.0 ``` Use exact reviewed image/version tags for production and rollback. ## Docker quick start Run these commands on the host where you intend to deploy your own Robot instance: ```bash git clone --branch v2.1.0 --depth 1 https://github.com/getbible/robot.git cd robot ./setup.sh docker-init ${EDITOR:-vi} .env ./setup.sh docker-validate ./setup.sh docker-deploy ./setup.sh docker-doctor ``` The default Compose deployment runs one bot in one bounded, non-root, read-only container. Multi-bot mode is explicit and requires unique ports and isolated state. See [Docker deployment](https://github.com/getbible/robot/blob/HEAD/docs/DOCKER.md). ## Host-native installation ```bash git clone https://github.com/getbible/robot.git cd robot read -r -p 'Reviewed Robot commit SHA: ' ROBOT_COMMIT if git checkout --detach "$ROBOT_COMMIT"; then sudo ./setup.sh install fi ``` The manager creates an isolated service identity, exact hashed environment, root-only token/configuration, bounded cache/state/log paths, health listener, Mini App listener, and hardened systemd unit. Use the manager for operations: ```bash read -r -p 'Robot instance name: ' ROBOT_INSTANCE sudo getbible-robot status "$ROBOT_INSTANCE" sudo getbible-robot doctor "$ROBOT_INSTANCE" sudo getbible-robot miniapp "$ROBOT_INSTANCE" sudo getbible-robot update "$ROBOT_INSTANCE" ``` `update` automatically hands control to newer upgrade logic in the reviewed target checkout, migrates configuration, regenerates setup-managed Caddy routes, and verifies the Mini App contribution APIs. Running it again at the same commit performs a safe deployment refresh, which repairs stale generated routes without replacing the application tree. See [Upgrading and rollback](https://github.com/getbible/robot/blob/HEAD/docs/UPGRADING.md). Do not edit generated Caddy/systemd configuration directly. ## Dependency policy Human-maintained intent lives in `requirements.in` and `requirements-dev.in`. Production and CI install exact hashed locks from `requirements.txt` and `requirements-dev.txt`. Robot supports compatible Librarian 2.x releases beginning with 2.0.0: ```text getbible>=2.0.0,<3 ``` The reviewed runtime lock currently selects a specific released version. Production never resolves an unreviewed latest dependency during startup. See [Dependency policy](https://github.com/getbible/robot/blob/HEAD/docs/DEPENDENCIES.md). ## Development and verification ```bash git clone https://github.com/getbible/robot.git cd robot python3 -m venv venv venv/bin/python -m pip install --upgrade pip venv/bin/python -m pip install --require-hashes -r requirements-dev.txt (cd miniapp && npm ci --ignore-scripts && npx playwright install chromium) bash scripts/run-checks.sh ``` Focused iteration: ```bash venv/bin/python -m unittest discover -s tests -v (cd miniapp && npm run check) (cd miniapp && npm run test:browser) ``` After reviewing updated global topic metadata or verse associations, regenerate the deterministic browser catalogue with `(cd miniapp && npm run generate:global-bookmarks)`. Accepted moderation exports use the documented importer in `data/global-bookmarks/README.md`. The permanent release gate requires: - Python 3.10, 3.11, 3.12, 3.13, and 3.14; - production container build and smoke test; - Ruff, strict mypy, and branch coverage; - browser unit and real Chromium tests; - public API routing and CSP parity; - cache hash/invalidation/bounds tests; - browser selection add/remove/reorder/clear and visual highlight tests; - scoped durable reading-history move-to-front/reopen/remove/clear and persistence tests; - bookmark topic/domain, Telegram storage reconciliation, bounded JSON, and private-chat backup/restore tests; - session-authenticated batched contribution sync, idempotent event replay, revocation, and rate-limit pacing tests; - no pre-Post Robot selection mutation; - authoritative idempotent Post tests; - Bandit, dependency audit, secret scan, systemd verification, and CodeQL. See [Testing](https://github.com/getbible/robot/blob/HEAD/docs/TESTING.md) and [Release gate](https://github.com/getbible/robot/blob/HEAD/docs/RELEASE_GATE.md). ## Production acceptance After deploying one exact green commit, verify: 1. bare `/bible` opens the reader; 2. cold and warm chapter loads work; 3. explicit references resolve through Query API; 4. selecting highlights verse number and body; 5. second-click unselect works; 6. Search and Reader selections interoperate; 7. navigation preserves selected styling; 8. Copy does not Post or clear selection; 9. failed Post preserves selection; 10. successful Post delivers authoritative Scripture and clears selection; 11. reading history shows the verse text and reopens the exact verse in the currently selected translation; 12. History remains available in the footer on every Mini App surface; 13. revisiting a history location moves it to the top without duplication; 14. individual and complete history clearing work; 15. a personal bookmark can belong to multiple colored topics, be reopened, unassigned per topic, and remain within the 800-verse bound; 16. personal bookmarks and last-read reconcile across supported Telegram clients while history and Scripture caches remain device-local; 17. JSON download/import and private-chat backup/restore both work, including user confirmation and one-launch acknowledgement; 18. the unified topic list identifies global links with **G**, supports per-link hide and per-topic/all-catalog reset, and never includes those links in personal sync or backup; 19. approved-contributor Sync now completes through sequential `POST /api/v1/contributions/events` batches whose final response settles receipt counts and status, retried events replay without duplicates, and an ordinary or revoked user cannot submit; 20. private command and launcher cleanup still works. Record the deployed commit SHA and permanent CI/CodeQL run links with release evidence. ## License See the repository license and the copyright metadata returned for each Scripture translation. Robot's software license does not relicense Scripture translations or override publisher terms. ## Docker deployment The recommended Docker layout runs one Telegram bot in one container. The image contains only GetBible Robot and its non-root supervisor. It does not install Caddy, systemd, a firewall, certificates, or listeners on ports 80 and 443. The container serves the Mini App and, when selected, Telegram webhook delivery on independently configurable application ports; TLS, DNS, and routing remain outside the container. The same image also supports an explicit multi-bot mode for compact deployments, but separate containers are the operational default because each bot then has an independent memory limit, health state, restart policy, data volume, update cycle, and application port. ### Published images The repository publishes multi-platform Linux AMD64 and ARM64 images to GitHub Container Registry: ```bash docker pull ghcr.io/getbible/robot:2.1.0 ``` The available tag contract is: | Tag | Meaning | Production use | |---|---|---| | `2.1.0` | Exact stable release | Recommended | | `2.1` | Newest patch in the selected minor series | Controlled rolling updates | | `2` | Newest release in the selected major series | Compatibility testing | | `latest` | Newest non-prerelease release | Convenient evaluation | | `sha-` | One immutable source commit | Audit and rollback | | `edge` | Latest `master` commit whose complete CI workflow passed | Pre-production only | Every published image includes OCI source/license metadata, a BuildKit SBOM and provenance record, and a signed GitHub artifact attestation. Verify an image against this repository with a current GitHub CLI: ```bash gh attestation verify \ oci://ghcr.io/getbible/robot:2.1.0 \ --repo getbible/robot ``` The release workflow accepts a stable release only when its `vX.Y.Z` tag matches the version in `pyproject.toml` and the exact commit already has green `robot/security-gate` and `robot/codeql-gate` statuses. A published `v2.1.0` release produces `2.1.0`, `2.1`, `2`, and `latest`. Successful CI on `master` publishes only `edge` and the immutable commit tag. #### Maintainer release procedure After merging the intended release commit: 1. confirm CI and CodeQL are green for that exact commit; 2. confirm `pyproject.toml`, the generated Compose environment, Kubernetes example, changelog, and release notes all name the same version; 3. create and publish the matching GitHub release, such as `v2.1.0`; 4. wait for **Publish container image** to complete; 5. record the published manifest digest and verify the attestation; 6. pull and smoke-test the exact version before moving production. Creating a tag without publishing a GitHub release does not publish stable container tags. This prevents an accidental tag push from changing `latest`. The workflow needs no registry password or repository secret; GitHub's short-lived workflow token publishes the package associated with this public repository. ### Recommended one-bot quick start From a checkout of the matching stable release: ```bash git clone --branch v2.1.0 --depth 1 https://github.com/getbible/robot.git cd robot ./setup.sh docker-init ${EDITOR:-vi} .env ./setup.sh docker-validate ./setup.sh docker-deploy ./setup.sh docker-doctor ``` At minimum, replace these values: ```dotenv TELEGRAM_API_TOKEN=123456789:replace-with-the-token-from-BotFather MINI_APP_PUBLIC_URL=https://bot.example.com/getbible/production ``` `compose.yaml` reads the project `.env` automatically. The same values may instead be exported in the shell or supplied through: ```bash read -r -p 'Path to your Robot environment file: ' ROBOT_ENV_FILE ./setup.sh docker-deploy --env-file "$ROBOT_ENV_FILE" ``` `compose.yaml` is the versioned, static deployment definition. The private `.env` file is the operator-editable value layer generated by `docker-init`. It pins `ROBOT_IMAGE=ghcr.io/getbible/robot:2.1.0` by default. Together they expose the image release plus the application's concurrency, session, cache, timeout, rate, abuse, memory, CPU, PID, tmpfs, and log-retention controls without rebuilding the image. Edit and apply the default environment in one operation: ```bash ./setup.sh docker-config ``` Or edit it directly and recreate the workload: ```bash ${EDITOR:-vi} .env ./setup.sh docker-validate ./setup.sh docker-restart ``` `docker-restart` deliberately uses Compose to recreate the currently installed image. A plain `docker restart` does not reload changed environment variables or Compose resource settings. Pass `--env-file`, `--secure`, or `--multi` to the setup commands when using those matching deployment variants. `docker-config --no-restart` validates and saves a change without applying it yet. `docker-deploy` and its `docker-update` alias pull `ROBOT_IMAGE`, validate it, and recreate the workload without compiling source on the server: ```bash ./setup.sh docker-update ``` For a deliberate local source build, add the optional build overlay: ```bash ./setup.sh docker-validate --build ./setup.sh docker-deploy --build ``` This uses `compose.build.yaml` and tags the result as `ROBOT_BUILD_IMAGE` (default `getbible-robot:local`). The production Compose files contain no `build` directive, so normal deployments cannot silently replace a reviewed registry image with whatever source happens to be present on the host. No interactive installation runs during container startup. The supervisor derives per-instance state paths, validates the complete application configuration, starts the bot, waits for health, and restarts it safely when a runtime failure occurs. Missing or invalid application values are written to stdout/stderr as structured `ERROR` events: ```bash ./setup.sh docker-logs getbible-robot-production 200 ``` For example, a missing token produces an `instance_configuration_rejected` event containing `TELEGRAM_API_TOKEN is required`. The supervisor remains available for status and diagnostics instead of repeatedly crash-looping the application. The supervisor owns both SQLite paths and will not accept shared overrides: ```text /data//state/preferences.sqlite3 /data//state/contributions.sqlite3 ``` The second file contains contributor applications, Telegram profile metadata, immutable events, review decisions, notification state, private audit history, and live catalogue revisions. It is therefore more sensitive than recoverable cache data. Keep the `robot-data` volume private, include it in encrypted backups when contributions are enabled, and never mount it into another bot instance. `CONTRIBUTION_CONTRIBUTOR_LIMIT` and `CONTRIBUTION_EVENT_LIMIT` pass through Compose with defaults of `10000` and `250000` respectively. ### Token handling The default Compose model accepts `TELEGRAM_API_TOKEN` from `.env` because it is the smallest fully automatic deployment path. Keep `.env` mode `0600`; it is ignored by Git. For production, the optional Compose-secret overlay removes the token from the container environment and mounts it at `/run/secrets/telegram_bot_token`: ```bash ./setup.sh docker-deploy --secure ``` The overlay sources the secret from `TELEGRAM_API_TOKEN` in the operator environment or supplied Compose environment file and mounts it mode `0400` as UID/GID 10001. The application receives only `TELEGRAM_API_TOKEN_FILE=/run/secrets/telegram_bot_token`. The explicit multi-bot mode uses file-backed secrets because each instance needs a different token. Those source files must be readable by the host UID mapped to container UID 10001. ### Ports and external routing The default container publishes the Mini App backend and the optional Telegram webhook backend on loopback: ```dotenv MINI_APP_PORT=9201 MINI_APP_HOST_PORT=9201 MINI_APP_BIND_ADDRESS=127.0.0.1 TELEGRAM_WEBHOOK_PORT=9001 TELEGRAM_WEBHOOK_HOST_PORT=9001 TELEGRAM_WEBHOOK_BIND_ADDRESS=127.0.0.1 ``` This produces `127.0.0.1:9201 -> container:9201` and `127.0.0.1:9001 -> container:9001`. Point an existing HTTPS reverse proxy at the first port for the Mini App. When `TELEGRAM_DELIVERY_MODE=webhook`, route the exact private path in `TELEGRAM_WEBHOOK_PUBLIC_URL` to the second port. In polling mode nothing listens on the webhook mapping. If the reverse proxy is another container, use a Compose override to attach both services to a private Docker network and route directly to the matching container ports; host publishing can then be removed. The health listener remains inside the container on port 8081 and is used by the image `HEALTHCHECK`. It does not need a public or host mapping. Polling is the default Telegram delivery mode, so its deployment does not need a routed webhook endpoint even though Compose retains the configurable mapping. `MINI_APP_PUBLIC_URL` must remain the externally reachable HTTPS URL used by Telegram. Its path must be forwarded unchanged to the application port. ### Operate the deployed container The host setup manager discovers containers by the `io.getbible.robot.container=true` label: ```bash ./setup.sh docker-list ./setup.sh docker-status ./setup.sh docker-doctor ./setup.sh docker-logs ./setup.sh docker-follow ./setup.sh docker-manage ./setup.sh docker-shell ``` If multiple Robot containers exist, the interactive commands show a numbered selector. A known container name may be supplied directly: ```bash ./setup.sh docker-manage getbible-robot-production ./setup.sh docker-shell getbible-robot-production ``` `docker-manage` opens `/app/setup.sh` inside the selected container. Its menu supports listing, status, diagnostics, start, stop, restart, configuration reload, contribution review/export, and a non-root Bash shell. Direct equivalents are: ```bash docker exec getbible-robot-production /app/setup.sh list docker exec getbible-robot-production /app/setup.sh status production docker exec getbible-robot-production /app/setup.sh doctor production docker exec getbible-robot-production /app/setup.sh restart production docker exec -it getbible-robot-production /app/setup.sh contributions production docker exec getbible-robot-production /app/setup.sh contributions production status docker exec -it getbible-robot-production /app/setup.sh docker exec -it getbible-robot-production /bin/bash docker logs --since 30m getbible-robot-production ``` The shell runs as the image's unprivileged UID/GID 10001. The root filesystem remains read-only; only the instance data volume and bounded `/tmp` tmpfs are writable. The contribution submenu reviews applications, resolves topics, reviews verses with authoritative text, publishes a live instance revision, and writes a privacy-safe repository export. `status` and `export` also work non-interactively. Exports are mode `0600` below: ```text /data//state/contribution-exports/reviewed-catalog-.json ``` The image does not contain Node, Git, or a repository credential. Automated branch publication from a container export is not supported in this release; retain the JSON only for a separately reviewed manual repository import. Do not add a Git credential or publisher checkout to the application container. The guarded one-command repository publication workflow is available only for native deployments through the dedicated non-root publisher account described in [Operations](https://github.com/getbible/robot/blob/HEAD/docs/OPERATIONS.md#contributor-enrolment-and-moderation); it is not a runtime-container permission. Container-to-host publication needs a separate privilege-boundary and lease design and is deliberately outside this release. ### User experience under load Resource controls do not change the Telegram command, search, selection, posting, or Mini App interface. The expensive search worker has an independent bounded executor. A slow search therefore does not consume the direct Scripture lookup workers or block ordinary Telegram update handling. The supplied production defaults use: - sixteen concurrent Telegram updates; - eight direct Scripture/catalog workers; - four CPU-bound search workers; - bounded interactive and Mini App sessions; - up to eight resident shared search corpora and one translation cache; - a 1792 MiB per-bot RSS guard inside a 2 GiB container limit. When capacity is temporarily exhausted, the application returns a controlled retry message while liveness remains responsive. Three consecutive liveness failures restart the bot child. Repeated failures open the restart circuit so the container cannot consume the host in an endless restart/prewarm loop. The search result, verse selection, single-verse/range behavior, saved default translation, CJK handling, and explicit final posting flow are unchanged. Lightweight authenticated Mini App navigation consumes only the configured fractional `MINI_APP_NAVIGATION_RATE_COST`; session exchange, search, Scripture fetches, and posting retain full request cost. Normal browsing therefore does not exhaust the same budget intended to stop expensive request floods. ### Identity, client address, and abuse controls Telegram Bot API updates contain a numeric Telegram user and chat identity, but they do not expose the user's IP address. Mini App HTTP requests do have a network peer address. `AUDIT_IDENTITY_MODE` controls what is attached to structured events: - `disabled` records no user, chat, or client identity; - `pseudonymous` (the application default) records stable keyed identifiers; - `raw` records numeric Telegram user/chat IDs and the resolved Mini App client IP for incident investigation. The supplied Docker operator example selects `raw`. Treat those logs as personal data and set access and retention accordingly. The bot never logs tokens, names, usernames, verse bodies, or browser authorization data. External proxy mode assumes the operator controls access to the backend and accepts the standard forwarded client address from Caddy, Traefik, Nginx, the container ingress, or a cloud load balancer. To add an application-level restriction as well, set the optional `MINI_APP_TRUSTED_PROXY_CIDRS` list: ```dotenv AUDIT_IDENTITY_MODE=raw MINI_APP_TRUSTED_PROXY_CIDRS=172.20.0.5/32 ``` User, chat, authenticated Mini App client, and unauthenticated session-exchange token buckets remain bounded and configurable. Repeated individual user or authenticated client exhaustion within `ABUSE_WINDOW_SECONDS` triggers a temporary `ABUSE_BLOCK_SECONDS` pause after `ABUSE_REJECTION_THRESHOLD` violations. Chat-wide saturation alone never accuses or blocks one member. When the application knows the Telegram user, it sends `ABUSE_WARNING_MESSAGE` privately or as an ephemeral group notice. Warnings use a cooldown and a new block produces one immediate notice, so a flood cannot create a second outbound-message flood. ### Resource profile for an 8 GiB host The measurements below were taken against Librarian 1.x and are retained only as a floor. They are not a baseline to hold Librarian 2 against: 1.x returned nothing at all for continuous scripts under default criteria, so part of what it was not spending was the cost of search that worked. A resident 2.x index is the price of correct results, and it is paid once per translation and policy rather than per search — see [Search](https://github.com/getbible/robot/blob/HEAD/docs/SEARCH.md). Budget for that resident set rather than trying to shrink it. Lowering `SEARCH_SHARED_CORPUS_LIMIT` does not save steady-state memory so much as force the same corpora to be parsed and analysed again on the next search, which trades a bounded, one-off cost for an unbounded, repeated one. Current KJV measurements are approximately: | State | Robot RSS | |---|---:| | Mini App listener initialized | 72 MiB | | Default KJV search index warmed | 111 MiB | | All four KJV search modes exercised | 148 MiB | The default one-bot profile has a 2 GiB hard memory ceiling, a 1536 MiB reservation, two CPUs, and a 256-task ceiling. It targets an 8 GiB, i3-class or stronger host but does not enforce host eligibility. This leaves capacity for the kernel, SSH, Docker, an external reverse proxy, and controlled additional workloads. The child supervisor restarts the bot before it can cross 1792 MiB RSS, while Docker remains the final aggregate limit. These values are environment-driven ceilings, not a promise that every workload will consume them. Translations vary in size. The largest corpus observed in July 2026 was about 31 MB before Python parsing and indexing. Load-test non-default translations before lowering the guard or increasing search concurrency. ### Multi-bot mode Use multi-bot mode only when sharing one container is intentional. The following creates a new `production` instance; choose a different instance name and matching files when adding to an existing deployment. Enter the real token at the prompt so it is not saved as literal shell-history text: ```bash mkdir -p docker/instances docker/secrets cp docker/examples/production.env.example \ docker/instances/production.env read -r -s -p 'Telegram bot token from BotFather: ' ROBOT_TELEGRAM_TOKEN printf '\n' printf '%s\n' "$ROBOT_TELEGRAM_TOKEN" > docker/secrets/production.token unset ROBOT_TELEGRAM_TOKEN chmod 400 docker/secrets/production.token sudo chown 10001:10001 docker/secrets/production.token ./setup.sh docker-deploy --multi ``` Each `/config/instances/*.env` file defines one bot. Every enabled Mini App, health listener, or webhook listener must use a unique container port. Add the matching secret and application-port mapping to `compose.multi.yaml` for each additional instance, then run: ```bash docker compose -f compose.multi.yaml up -d docker exec getbible-robot getbible-robot-container reload ``` The supervisor rejects port collisions before starting a second bot and isolates cache and SQLite state under `/data/`. In particular, each bot receives its own `state/contributions.sqlite3` even if an instance file attempts to configure another path. The supplied multi-bot file starts with the same one-bot aggregate profile: 1536 MiB reserved, 2 GiB hard limit, and two CPUs. Before adding another bot, raise `ROBOT_MEMORY_RESERVATION`, `ROBOT_MEMORY_LIMIT`, `ROBOT_CPU_LIMIT`, and `ROBOT_PIDS_LIMIT` for the combined workload. Each instance retains its own `CONTAINER_INSTANCE_MEMORY_LIMIT_MB` guard. Budget from observed per-bot RSS, preserve host headroom, and prefer separate containers when independent failure and deployment boundaries matter. ### Cluster deployment [`deploy/kubernetes.example.yaml`](https://github.com/getbible/robot/blob/HEAD/deploy/kubernetes.example.yaml) is the one-bot-per-workload cluster example. It includes: - one replica per Telegram bot token; - a mounted token Secret; - persistent bounded cache, preference, and private contribution state; - startup, liveness, and readiness probes; - CPU, memory, and ephemeral-storage controls; - a Service exposing the Mini App and optional Telegram webhook backends. Keep `replicas: 1` for polling and for the current process-local Mini App session model. Deploy additional bot tokens as separate workloads. ### External proxy contract Forward the exact path in `MINI_APP_PUBLIC_URL` to the bot's application port. Preserve `Host`, set trusted forwarding headers at the proxy, and do not expose plain HTTP directly to the internet. Apply: - request-header and request-body timeouts; - a 64 KiB body cap for ordinary routes, with one narrowly matched exception of at least 4 MiB + 4 KiB only for `POST .../api/v1/bookmarks/backup` (the supplied Caddy configuration uses 5 MiB for the backup endpoint); - an idle connection timeout; - connection and request-rate budgets; - current TLS certificate and protocol policy. The embedded Tornado server independently applies a 16 KiB header cap, a 64 KiB ordinary body cap, a 4 MiB + 4 KiB cap only for the exact bookmark backup POST route, a 10-second body timeout, a 30-second idle/header timeout, and a 64 KiB socket buffer. Contribution event batches and ordinary actions share the same Mini App domain, HTTPS ingress, application listener, and 64 KiB body budget; no WebSocket or extra port is part of synchronization. ### Capacity and incident logs Application and supervisor output is structured JSON on stdout/stderr and is available through `docker logs` or `./setup.sh docker-logs`. The important pressure events are: | Event | Meaning | |---|---| | `instance_memory_pressure` / `instance_memory_pressure_cleared` | Child RSS crossed or recovered below the configurable warning threshold | | `instance_memory_limit_exceeded` | The child reached the hard per-bot RSS guard and was restarted | | `capacity_queue_rejected` | A bounded worker permit was unavailable before the queue timeout | | `lookup_timed_out` | Upstream work exceeded the outer lookup deadline | | `upstream_circuit_rejected` | Repeated upstream failures opened the protective circuit | | `inbound_rate_limited` | A user, chat, or Mini App client exhausted a request budget | | `mini_app_request` | Route, status, duration, and configured identity for a Mini App request | | `instance_restart_circuit_open` | Repeated child failures stopped automatic restart thrashing | Aggregate counts, active blocks, process RSS, sessions, threads, file descriptors, queues, timeouts, and circuit state remain available from `/metrics` and `./setup.sh docker-doctor`. Use the warning events to tune Compose limits before raising hard ceilings; raising a container limit cannot create physical memory that the host does not have. ### Build validation The exact Python dependency lock is installed with `--require-hashes`. Local source builds are explicitly opt-in: ```bash docker compose -f compose.yaml -f compose.build.yaml build --pull robot docker build --pull -t getbible-robot:test . docker run --rm --entrypoint python getbible-robot:test \ -c 'from config import Settings; print("runtime imports OK")' docker run --rm --entrypoint /app/setup.sh \ getbible-robot:test help ``` CI validates the published-image and local-build Compose models, builds the exact image, verifies the non-root user, and smoke-tests both the supervisor and the in-container setup utility. After complete CI succeeds on `master`, a separate least-privilege workflow publishes `edge`. Publishing a GitHub release creates the stable tags only after rechecking the exact version and required commit gates. ## Support and source documentation For questions about this project, installation, unexpected output, or contributing, use the [single GetBible support desk](https://git.vdm.dev/getBible/support). Include the project, installed release or commit, operating system, relevant API version, and a minimal reproduction. General enquiries can be sent to [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). This guide follows the [repository README](https://github.com/getbible/robot/blob/HEAD/README.md) and [DOCKER](https://github.com/getbible/robot/blob/HEAD/docs/DOCKER.md). Scripture and study resources retain their own source licences; a software licence does not relicense the texts. --- # Scripture — object-oriented Bible access for PHP Build PHP applications around validated, immutable, lazy Bible objects backed by installed SWORD modules. Scripture adds configuration, indexing, cache generations, refresh services, and Joomla Framework integration above the native extension. [Repository](https://github.com/getbible/scripture) · [Support](https://git.vdm.dev/getBible/support) · [All projects](/project/) Scripture is a local native-data library, separate from the HTTP Bible APIs and the installable Joomla CMS component. Its dependencies include the [SWORD PHP extension](/project/sword/). It exposes Bible modules; dictionaries and commentaries remain outside this library's object model. `getbible/scripture` is the object-oriented Bible application layer for the native [`getbible/sword`](https://github.com/getbible/sword) PHP extension. It validates the complete `getbiblesword.ndjson/v1` stream and exposes immutable, lazy `Translation`, `Book`, `Chapter`, and `Verse` objects without loading an entire Bible object graph into every PHP process. The package is deliberately Bible-only. Non-Bible SWORD modules remain visible in the low-level catalog but are not exposed as Scripture translations. ## Capabilities Installed SWORD Bible modules are exposed through validated, immutable snapshots. The package provides bounded reader/writer locking, durable refresh state, per-module outcomes, Joomla Console commands, and a Joomla Scheduled Tasks bridge. The released native ABI lists and exports installed modules. It does not download, update, or remove CrossWire modules. Those operations remain disabled unless the application injects a provisioner that explicitly advertises and implements them. See the [provisioning boundary](https://github.com/getbible/scripture/blob/HEAD/docs/provisioning.md). ## Getting started ### Product-distributed runtime People receiving an application should receive PHP, the native extension, the Composer dependencies, and policy-approved SWORD modules as one tested runtime. They should not need a compiler, PIE, or Composer on the production host. The [shipping and deployment guide](https://github.com/getbible/scripture/blob/HEAD/docs/distribution.md) provides a concrete container build and the equivalent installer contract for application distributors. ### Existing Composer project Direct library integration requires: - Linux with PHP 8.2, 8.3, 8.4, or 8.5. - The `getbiblesword` PHP extension, installed through PIE. - Joomla Framework Console, DI, Event, Filesystem, and Registry packages, installed by Composer. - A readable SWORD module root. ```bash pie install 'getbible/sword:^0.1.1' php --ri getbiblesword composer require getbible/scripture ``` PIE owns the native-install confirmation and any administrator prompt. Version `0.1.1` is the first extension release whose source asset follows PIE's normal discovery convention. An already-installed `0.1.0` extension remains compatible with this package, but its published source asset cannot be installed by that one-command path. The extension check is intentionally strict. Composer treats PHP extensions as platform requirements; it verifies that `ext-getbiblesword` is loaded but does not install it. Composer also does not execute scripts declared by dependency packages. See [installation and setup](https://github.com/getbible/scripture/blob/HEAD/docs/installation.md) for the exact boundary and supported deployment choices. ### Interactive setup After Composer installation, inspect the runtime and configure the library: ```bash vendor/bin/getbible-scripture scripture:doctor vendor/bin/getbible-scripture scripture:setup ``` `scripture:setup` validates the loaded native runtime, module and cache paths, installed Bible modules, refresh policy, and permissions. It does not invoke PIE and cannot download CrossWire modules through ABI v1. Applications can perform the same persisted configuration update through `SetupServiceInterface::apply()`, including immediate warm-up. See [programmatic setup](https://github.com/getbible/scripture/blob/HEAD/docs/api.md#programmatic-setup). ### Programmatic setup ```php '/var/lib/getbible/sword', 'cache_path' => '/var/cache/getbible/scripture', ]); $container = ContainerFactory::create($configuration); /** @var ScriptureInterface $scripture */ $scripture = $container->get(ScriptureInterface::class); $initialization = $scripture->initialize(['KJV']); if (!$initialization->succeeded()) { throw new RuntimeException( json_encode( $initialization->toArray(), JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR, ), ); } $kjv = $scripture->translation('KJV'); $john316 = $kjv->book('John')->chapter(3)->verse(16); $text = $john316->stripped(); if ($text === null) { throw new RuntimeException('This module does not provide stripped projections.'); } echo $text->requireUtf8(), PHP_EOL; foreach ($kjv->verses('John', 3, 16, 18) as $verse) { $text = $verse->stripped()?->requireUtf8() ?? $verse->raw()->requireUtf8(); printf( "%s %d:%d %s\n", $verse->scope()->bookName()->requireUtf8(), $verse->scope()->chapter(), $verse->scope()->verse(), $text, ); } ``` The first request for an installed translation performs one full native export, validates it, and creates an immutable indexed generation. Later requests open that generation and hydrate only the requested objects. Run interval-based maintenance from the application scheduler: ```php $maintenance = $scripture->refreshIfDue(); if (!$maintenance->succeeded()) { // Send $maintenance->toArray() to the application's operational log. } ``` No constructor performs network or full-module work. Both methods return structured per-module results and continue safely across independent failures. ## Available data layers Every verse retains: - authoritative raw bytes; - SWORD default-rendered bytes; - stripped text bytes; - the exact verse key and scope; - lossless lexical annotation segments; - SWORD's ordered three-level official attribute map; and - the original contract record. Every byte value verifies canonical Base64, decoded size, and SHA-256 before it is exposed. The optional `utf8` member is treated only as a verified convenience projection. ## Configuration Configuration precedence depends on the entry point. Explicit configuration objects always win. Interactive or programmatic setup applies request values, then environment values, then persisted JSON, then documented defaults. Normal container loading applies environment values over persisted JSON. | Key | Environment variable | Default | |---|---|---| | `module_path` | `GETBIBLE_SCRIPTURE_MODULE_PATH` | Native extension resolution | | `cache_path` | `GETBIBLE_SCRIPTURE_CACHE_PATH` | `$XDG_CACHE_HOME/getbible/scripture` | | `refresh_interval` | `GETBIBLE_SCRIPTURE_REFRESH_INTERVAL` | `P1M` | | `auto_refresh` | `GETBIBLE_SCRIPTURE_AUTO_REFRESH` | `true` | | `lock_timeout` | `GETBIBLE_SCRIPTURE_LOCK_TIMEOUT` | `30` seconds | | `modules` | `GETBIBLE_SCRIPTURE_MODULES` | All installed translations | | `provisioning_enabled` | `GETBIBLE_SCRIPTURE_PROVISIONING_ENABLED` | `false` | | `install_all` | `GETBIBLE_SCRIPTURE_INSTALL_ALL` | `false` | See [configuration](https://github.com/getbible/scripture/blob/HEAD/docs/configuration.md) for operational details. ## Documentation - [Architecture](https://github.com/getbible/scripture/blob/HEAD/docs/architecture.md) - [Installation and setup](https://github.com/getbible/scripture/blob/HEAD/docs/installation.md) - [Public API](https://github.com/getbible/scripture/blob/HEAD/docs/api.md) - [Configuration](https://github.com/getbible/scripture/blob/HEAD/docs/configuration.md) - [Contract v1 mapping](https://github.com/getbible/scripture/blob/HEAD/docs/contract-v1.md) - [Caching and refresh](https://github.com/getbible/scripture/blob/HEAD/docs/caching.md) - [Module provisioning](https://github.com/getbible/scripture/blob/HEAD/docs/provisioning.md) - [Production operations](https://github.com/getbible/scripture/blob/HEAD/docs/operations.md) - [Shipping and deployment](https://github.com/getbible/scripture/blob/HEAD/docs/distribution.md) - [Releasing](https://github.com/getbible/scripture/blob/HEAD/docs/releasing.md) ## License GPL-2.0-only, matching the native `getBibleSword` and `getbible/sword` foundation. Individual CrossWire modules retain their own licenses and distribution terms. ## Public API ### Composition ```php $configuration = Configuration::fromEnvironment([ 'module_path' => '/var/lib/getbible/sword', 'cache_path' => '/var/cache/getbible/scripture', ]); $container = ContainerFactory::create($configuration); $scripture = $container->get(ScriptureInterface::class); ``` To load the versioned JSON document written by `scripture:setup`: ```php $container = ContainerFactory::create( configuration: null, configurationPath: '/etc/getbible/scripture.json', ); $scripture = $container->get(ScriptureInterface::class); ``` Applications already using Joomla DI can register `ScriptureServiceProvider` with their own container and pre-register `Configuration` when they need custom values. ### Programmatic setup Applications can persist validated settings and warm installed translations through the same service used by the interactive command: ```php use GetBible\Scripture\Setup\SetupRequest; use GetBible\Scripture\Setup\SetupServiceInterface; /** @var SetupServiceInterface $setup */ $setup = $container->get(SetupServiceInterface::class); $result = $setup->apply(new SetupRequest( configurationPath: '/etc/getbible/scripture.json', values: [ 'module_path' => '/var/lib/getbible/sword', 'cache_path' => '/var/cache/getbible/scripture', 'modules' => ['KJV'], 'auto_refresh' => true, ], warm: true, )); if (!$result->succeeded()) { throw new RuntimeException( json_encode($result->toArray(), JSON_PRETTY_PRINT | JSON_THROW_ON_ERROR), ); } ``` `SetupServiceInterface` never invokes PIE, Composer, a system package manager, or a module download. It changes only the application-owned JSON configuration and optionally warms modules already available to the native runtime. ### Scripture service ```php $translations = $scripture->translations(); $translation = $scripture->translation('KJV'); $verse = $scripture->verse('KJV', 'John', 3, 16); $range = $scripture->verses('KJV', 'John', 3, 16, 18); $scripture->refreshTranslation('KJV'); $scripture->provisioningCapabilities(); $scripture->installTranslations(['KJV', 'WEB']); $scripture->installAllTranslations(); $scripture->refreshSelectedModules(['KJV']); $scripture->refreshModules(); $scripture->removeTranslation('KJV'); $scripture->initialize(); $scripture->refresh(); $scripture->refreshIfDue(); $scripture->maintenanceStatus(); ``` `translations()` lists installed Bible modules. `translation()` opens the current valid snapshot or performs one full warm-up. A forced refresh re-exports the installed module and activates a new generation only after validation. Provisioning methods are stable even when the injected native backend cannot perform them. Inspect `provisioningCapabilities()` first. The default getBibleSword ABI v1 adapter accurately reports every mutating capability as unavailable and throws `ProvisioningUnavailableException` when called. `initialize()`, `refresh()`, and `refreshIfDue()` return `MaintenanceResult` objects with ordered snapshot outcomes, the optional native provisioning result, operation errors, timestamps, and interval status. These operations continue across independent module failures and report partial failure through `succeeded()`. ### Translation ```php $translation->moduleName(); $translation->metadata(); $translation->books(); $translation->book('John'); $translation->bookByPosition(testament: 2, book: 4); $translation->verses('John', 3, 16, 18); $translation->configEntriesNamed('DistributionLicense'); $translation->rawExportPath(); $translation->activatedAt(); $translation->expiresAt(); $translation->generationId(); ``` Configuration entries are ordered and repeated keys are preserved. ### Book ```php $book->testament(); $book->position(); $book->name(); $book->abbreviation(); $book->versification(); $book->chapters(); $book->chapter(3); ``` `position()` is the SWORD `VerseKey` book position within its versification and testament. It is not assumed to be a universal 1-66 number. ### Chapter ```php $chapter->number(); $chapter->verse(16); $chapter->verses(); $chapter->verses(16, 18); $chapter->introductions(); ``` Ranges are inclusive. A reversed or invalid range throws `InvalidReferenceException`. ### Verse ```php $verse->scope(); $verse->key(); $verse->raw(); $verse->rendered(); $verse->stripped(); $verse->annotationSegments(); $verse->officialAttributes(); $verse->contractRecord(); ``` `raw()`, `rendered()`, and `stripped()` return verified `ByteValue` objects. `rendered()` and `stripped()` may be `null` only when the native producer could not create projections. ### Byte values ```php $bytes = $value->bytes(); $utf8 = $value->utf8(); $requiredUtf8 = $value->requireUtf8(); $hash = $value->sha256(); $size = $value->size(); $originalEnvelope = $value->toArray(); ``` `requireUtf8()` throws when no exact UTF-8 projection exists. It never attempts a lossy conversion. ### Events The default Joomla dispatcher emits: - `onGetBibleScriptureWarmStarted` - `onGetBibleScriptureWarmCompleted` - `onGetBibleScriptureWarmFailed` - `onGetBibleScriptureRefreshStarted` - `onGetBibleScriptureRefreshCompleted` - `onGetBibleScriptureRefreshFailed` - `onGetBibleScriptureProvisioningStarted` - `onGetBibleScriptureProvisioningCompleted` - `onGetBibleScriptureProvisioningFailed` - `onGetBibleScriptureMaintenanceStarted` - `onGetBibleScriptureMaintenanceCompleted` - `onGetBibleScriptureMaintenanceFailed` Event arguments contain the relevant module, operation, result, snapshot, or exception for that lifecycle boundary. Listeners must not mutate an active generation. Listener exceptions are contained so an observer cannot turn a committed core operation into a reported failure. ## Production operations ### Lifecycle semantics The public service exposes three explicit maintenance operations: ```php $scripture->initialize(); $scripture->refresh(); $scripture->refreshIfDue(); ``` `initialize()` installs missing configured translations only when runtime policy enables provisioning and the injected backend advertises the required capability. It then opens or warms validated snapshots for every target. `refresh()` invokes remote module refresh only when `provisioning_enabled` is true. It always rebuilds snapshots for installed targets. Under getBibleSword ABI v1, leave provisioning disabled and manage the SWORD module root through a separate trusted deployment process. `refreshIfDue()` compares durable last-success state with `refresh_interval`. The default is one calendar month. A failed or partially failed run does not advance last-success time, so the next scheduler invocation retries. All operations: - take one bounded whole-run maintenance lock; - isolate snapshot failures by module; - preserve the last active snapshot on export or validation failure; - write maintenance state through a synchronized temporary file and atomic rename; - emit Joomla lifecycle events; and - return a structured `MaintenanceResult`. ### CLI Composer exposes the Joomla Console application as `vendor/bin/getbible-scripture`. Run commands from the Composer application's directory. Start with the read-only runtime and state checks: ```bash vendor/bin/getbible-scripture scripture:doctor --json vendor/bin/getbible-scripture scripture:status ``` Configure the application interactively when it has not yet been set up: ```bash vendor/bin/getbible-scripture scripture:setup ``` For an already-installed KJV module, initialize its indexed snapshot and run maintenance when due: ```bash vendor/bin/getbible-scripture scripture:initialize --module=KJV vendor/bin/getbible-scripture scripture:refresh --if-due ``` Multiple installed modules can be selected by repeating `--module`. An explicit `scripture:refresh --module=KJV` forces that module's refresh rather than waiting for the interval. Doctor is read-only. Setup saves validated application configuration and can warm already-installed translations; it never installs the native extension or downloads modules. Both accept `--config=/absolute/path.json`. Setup also uses `GETBIBLE_SCRIPTURE_CONFIG_PATH` when the option is absent and prompts for a path only in an interactive terminal. Commands emit deterministic JSON with `--json` or non-interactive input. Interactive setup prints a concise summary followed by the same structured result. Initialization and refresh return exit code `0` only when the complete result succeeds, and `1` for partial or complete failure. Bootstrap, readiness, and uncaught application failures use a non-zero Joomla Console exit code. `--all` remains an explicit operation. It also requires `GETBIBLE_SCRIPTURE_PROVISIONING_ENABLED=true` and a native backend that advertises all-module installation. ### Environment A production deployment can use: ```dotenv GETBIBLE_SCRIPTURE_MODULE_PATH=/var/lib/getbible/sword GETBIBLE_SCRIPTURE_CACHE_PATH=/var/cache/getbible/scripture GETBIBLE_SCRIPTURE_MODULES=KJV,WEB GETBIBLE_SCRIPTURE_REFRESH_INTERVAL=P1M GETBIBLE_SCRIPTURE_AUTO_REFRESH=true GETBIBLE_SCRIPTURE_PROVISIONING_ENABLED=false GETBIBLE_SCRIPTURE_INSTALL_ALL=false GETBIBLE_SCRIPTURE_LOCK_TIMEOUT=30 ``` The PHP-FPM and scheduler users must share read access to the SWORD root and read/write access to the cache root. Run maintenance as the same operating system identity as the application whenever possible. For file-based configuration, set: ```dotenv GETBIBLE_SCRIPTURE_CONFIG_PATH=/etc/getbible/scripture.json ``` The setup command writes only allowlisted settings through an atomic same-directory replacement, refuses a symlink target, and gives a new file mode `0600`. Environment values remain available for deployments that manage configuration outside the application. ### Cron These scheduler examples are for administrators of a deployed PHP application. They assume the application lives at `/srv/getbible-app`, PHP is `/usr/bin/php`, and the configured module/cache paths below exist with the stated permissions. Adjust the deployment configuration to match the actual installation before registering a scheduled task. The command contains its own bounded interprocess lock, so overlapping cron runs safely serialize: ```cron 17 3 * * * cd /srv/getbible-app && /usr/bin/php vendor/bin/getbible-scripture scripture:refresh --if-due >> /var/log/getbible-scripture.log 2>&1 ``` Run the cron entry daily or weekly; durable interval state decides whether the monthly work is due. ### systemd `/etc/systemd/system/getbible-scripture.service`: ```ini [Unit] Description=GetBible Scripture maintenance After=network-online.target Wants=network-online.target [Service] Type=oneshot User=www-data Group=www-data WorkingDirectory=/srv/getbible-app EnvironmentFile=/etc/getbible/scripture.env ExecStart=/usr/bin/php vendor/bin/getbible-scripture scripture:refresh --if-due PrivateTmp=true NoNewPrivileges=true ProtectSystem=strict ProtectHome=true ReadWritePaths=/var/cache/getbible/scripture ReadOnlyPaths=/var/lib/getbible/sword ``` `/etc/systemd/system/getbible-scripture.timer`: ```ini [Unit] Description=Run GetBible Scripture maintenance daily [Timer] OnCalendar=*-*-* 03:17:00 Persistent=true RandomizedDelaySec=15m Unit=getbible-scripture.service [Install] WantedBy=timers.target ``` After installing both unit files and the `/etc/getbible/scripture.env` environment file, verify that `www-data` is your application identity and that it can access the configured paths. Then enable the timer on that host: ```bash sudo systemctl daemon-reload sudo systemctl enable --now getbible-scripture.timer systemctl list-timers getbible-scripture.timer ``` If an injected native provisioner writes to the SWORD root, change its systemd path allowance from `ReadOnlyPaths` to the narrow required `ReadWritePaths`. ### Joomla Scheduled Tasks `ScheduledRefreshHandler` is registered in the same Joomla DI container as the Scripture service: ```php use GetBible\Scripture\Integration\Joomla\ScheduledRefreshHandler; $handler = $container->get(ScheduledRefreshHandler::class); $result = $handler(); ``` A Joomla CMS scheduler plugin can call this service from its task execution callback, log `MaintenanceResult::toArray()`, and map `succeeded()` to the CMS task success/failure status. The handler performs interval gating itself, so the CMS task can run daily without forcing a monthly refresh on every run. ### Health checks Use: ```bash vendor/bin/getbible-scripture scripture:doctor --json vendor/bin/getbible-scripture scripture:status ``` Doctor verifies configuration parsing, native extension compatibility, module root access, cache access, installed modules, and warm-up readiness without changing state. Status reports: - whether maintenance is due; - the next due time; - last attempt, success, and failure timestamps; - consecutive failures and the last error; - configured and installed translations; - runtime provisioning policy; and - exact native backend capabilities. Alert on a non-null `last_error`, increasing `consecutive_failures`, or a due state that remains unchanged across multiple scheduler invocations. ## Support and source documentation For questions about this project, installation, unexpected output, or contributing, use the [single GetBible support desk](https://git.vdm.dev/getBible/support). Include the project, installed release or commit, operating system, relevant API version, and a minimal reproduction. General enquiries can be sent to [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). This guide follows the [repository README](https://github.com/getbible/scripture/blob/HEAD/README.md) and [api](https://github.com/getbible/scripture/blob/HEAD/docs/api.md), [operations](https://github.com/getbible/scripture/blob/HEAD/docs/operations.md). Scripture and study resources retain their own source licences; a software licence does not relicense the texts. --- # SWORD for PHP — native extension Stream installed CrossWire SWORD modules directly into PHP through `GetBible\Sword\Engine`. The extension embeds the pinned native extraction engine and keeps the same NDJSON contract as the standalone CLI. [Repository](https://github.com/getbible/sword) · [Support](https://git.vdm.dev/getBible/support) · [All projects](/project/) This is the native extension layer. Choose [Scripture](/project/scripture/) when an application needs lazy Translation, Book, Chapter, and Verse objects. Module data remains external. Native ABI v1 lists and extracts already-installed modules; it does not download modules or provide direct verse queries. `getbible/sword` is the native PHP extension for [getBibleSword](https://github.com/getbible/getbiblesword). It exposes the released getBibleSword `0.3.0` C ABI to PHP without starting a subprocess and without requiring a system installation of `libsword`, `diatheke`, or the `getbiblesword` executable. The package is designed for installation through the official [PHP Installer for Extensions (PIE)](https://github.com/php/pie): ```bash pie install getbible/sword ``` Check the [published releases](https://github.com/getbible/sword/releases) and [Packagist setup guide](https://github.com/getbible/sword/blob/HEAD/docs/packagist.md) for package availability. If PIE cannot resolve a published package, use the source-build workflow below. The extension and native engine use separate release numbers. ## Runtime model The extension embeds: - getBibleSword `0.3.0`; - getBibleSword C ABI version `1`; - CrossWire SWORD `1.9.0`; and - the `getbiblesword.ndjson/v1` output contract. The resulting `getbiblesword.so` PHP module does not dynamically depend on `libsword.so` or `libgetbiblesword.so`. Bible translations, commentaries, dictionaries, and other SWORD modules remain external data. ## PHP API The API is intentionally streamed. A full Bible is never concatenated into one PHP string. ```php streamModules($list); fclose($list); $output = fopen('/tmp/kjv.ndjson', 'wb'); $extractBytes = $engine->streamModule( module: 'KJV', destination: $output, artifactChunkSize: Engine::DEFAULT_ARTIFACT_CHUNK_SIZE ); fclose($output); ``` Both methods write the exact NDJSON bytes emitted by the standalone getBibleSword `0.3.0` CLI. They return the accepted byte count and throw `GetBible\Sword\Exception` when the C ABI reports an extraction, write, cancellation, argument, or internal error. The exception code is the underlying `gbs_status` value. Metadata is available without constructing an engine: ```php Engine::abiVersion(); // 1 Engine::productVersion(); // "0.3.0" Engine::contractIdentifier(); // "getbiblesword.ndjson/v1" ``` See [docs/php-api.md](https://github.com/getbible/sword/blob/HEAD/docs/php-api.md) for the complete interface and error contract. ## Module-path resolution `new Engine()` resolves its module root in this order: 1. the path passed to the constructor; 2. the `getbiblesword.module_path` PHP INI setting; 3. the `SWORD_PATH` environment variable; 4. `$HOME/.sword`; or 5. the effective operating-system user's home directory plus `/.sword`. For PHP-FPM, configure a stable application-owned path: ```ini getbiblesword.module_path=/var/lib/getbiblesword/sword ``` The executing user needs read access to installed module data. ABI v1 does not install missing modules or perform network operations. Automatic repository installation and direct verse/reference queries require additive getBibleSword C ABI functions and are tracked as follow-up work; this initial package does not claim behavior the released native library does not provide. ## Supported platforms - Linux on `x86_64` and `arm64` - PHP `8.2`, `8.3`, `8.4`, and `8.5` - non-thread-safe and Zend thread-safe PHP builds PIE source packages include the exact native sources. A source build requires a C/C++ build toolchain, PHP development tools, `pkg-config`, Autotools, CMake, and the development packages used by SWORD. On Debian or Ubuntu: ```bash sudo apt-get install \ autoconf automake binutils build-essential cmake curl git \ libbz2-dev libcurl4-openssl-dev libicu-dev liblzma-dev \ libtool pkg-config zlib1g-dev ``` PIE can detect many missing build tools, but not every native SWORD dependency. ## Source layout The extension source is not missing: PHP extensions traditionally keep `config.m4`, their primary C file, public header, stub, and generated arginfo in the repository root. In this repository: | Path | Purpose | |---|---| | `getbiblesword.c` | Zend/PHP stream and object adapter | | `php_getbiblesword.h` | Extension identity and module declaration | | `getbiblesword.stub.php` | Canonical PHP API signatures | | `getbiblesword_arginfo.h` | Generated Zend argument metadata | | `config.m4` | phpize/PIE native build definition | | `vendor/getbiblesword/` | Verified native engine source, created while packaging | | `vendor/sword-1.9.0.tar.gz` | Verified SWORD source, created while packaging | The large native dependencies are deliberately not duplicated in Git. The release source archive vendors and verifies them before PIE receives the package. The complete map is in [docs/repository-layout.md](https://github.com/getbible/sword/blob/HEAD/docs/repository-layout.md). ## Dependency integrity Release source packages vendor, rather than dynamically select: | Dependency | Pin | Verification | |---|---|---| | getBibleSword | `v0.3.0` / `c52003438dc7e3d5bab0d6680372b1de8a0077ce` | Exact Git commit | | CrossWire SWORD | `1.9.0` | SHA-256 `42409cf3de2faf1108523e2c5ac0745d21f9ed2a5c78ed878ee9dcc303426b8a` | Official builds never fall back to an ambient `libsword`. ## Development Install the dependencies shown above, clone the repository, and run: ```bash git clone https://github.com/getbible/sword.git cd sword ./scripts/build-extension.sh ``` The script: 1. verifies and vendors the two pinned sources; 2. builds SWORD as a PIC static library; 3. builds the PHP extension with `phpize`; 4. runs PHPT tests; 5. creates a real SWORD module fixture; 6. compares CLI and PHP output byte-for-byte; and 7. verifies that the extension has no SWORD shared-library dependency. To build the current branch through PIE before a release: ```bash pie repository:add vcs https://github.com/getbible/sword pie build 'getbible/sword:dev-main' ``` ## Golden release evidence Every pull request builds the extension and validates its deterministic local Public Domain SWORD fixture. The separate scheduled golden-baseline workflow and every release additionally download the public CrossWire KJV module as live test input, build the extension, stream that module through `GetBible\Sword\Engine`, and select the first and last chapters of canonical book 66 from getBibleSword's NDJSON output. The live gate requires all 20 verses of Revelation 1 and all 21 verses of Revelation 22. CrossWire's archive is not the expected result or test oracle. The workflow compares both chapters' newly generated entry records and readable text byte-for-byte with the maintainer-approved historical output committed under `tests/baselines/kjv-revelation-1/` and `tests/baselines/kjv-revelation-22/`. It fails before publication on any output change, prints every verse, and publishes: - two exact selected NDJSON entry-record files; - two human-readable chapter-text files; and - two manifests containing engine, ABI, contract, source, and artifact hashes. PR artifacts remain downloadable even when the comparison fails, making an unexpected result inspectable without weakening the golden baselines. The separate **Golden Baseline** workflow runs after each `main` update, daily, and on demand. If its strict comparison fails, **Golden Baseline Recovery** performs five independent live downloads and extension extractions. It proceeds only when all six generated files match byte-for-byte across all five runs. A stable changed result is proposed on an `automation/kjv-golden-*` branch in a normal pull request. It is never written directly to `main`; a maintainer must inspect and merge the PR before the candidate becomes the approved baseline. Unstable output, build failures, and results that still match the current baseline create no PR. ## Release process for repository maintainers Installing or consuming the extension does not require publishing a release. Authorized repository maintainers use the **Release** workflow. Its default `auto` mode releases an untagged `VERSION`, or derives the next semantic version from changes since the latest release: - `BREAKING CHANGE:` or a conventional `!` commit selects `major`; - `feat:` selects `minor`; - all other changes select `patch`. The workflow updates `VERSION` and `CHANGELOG.md`, commits when necessary, creates the annotated version tag, builds and verifies the PIE source package, creates the KJV evidence artifact, and publishes the GitHub release. A manually pushed matching `vX.Y.Z` tag follows the same build, evidence, and publication path. See [docs/releasing.md](https://github.com/getbible/sword/blob/HEAD/docs/releasing.md). ## Documentation | Document | Purpose | |---|---| | [PHP API](https://github.com/getbible/sword/blob/HEAD/docs/php-api.md) | Complete public PHP interface and errors | | [Architecture](https://github.com/getbible/sword/blob/HEAD/docs/architecture.md) | Native, Zend, trust, and packaging boundaries | | [Repository layout](https://github.com/getbible/sword/blob/HEAD/docs/repository-layout.md) | Location and origin of every source layer | | [Packagist setup](https://github.com/getbible/sword/blob/HEAD/docs/packagist.md) | One-time package registration and synchronization | | [Releasing](https://github.com/getbible/sword/blob/HEAD/docs/releasing.md) | Automated and tag-driven release operations | | [AI summary](https://github.com/getbible/sword/blob/HEAD/llms.txt) | Compact machine-oriented capability map | ## Security SWORD parsing occurs in the PHP process. A native memory-safety defect can terminate the PHP CLI or FPM worker, unlike the existing standalone-CLI subprocess boundary. Treat module data as untrusted, validate completed NDJSON before committing downstream state, and review [SECURITY.md](https://github.com/getbible/sword/blob/HEAD/SECURITY.md) and [docs/architecture.md](https://github.com/getbible/sword/blob/HEAD/docs/architecture.md) before production deployment. ## License GPL-2.0-only. The extension statically links GPL-2.0-only getBibleSword and CrossWire SWORD code. ## PHP API ### `GetBible\Sword\Engine` #### Construction ```php new Engine(?string $modulePath = null) ``` An explicit non-empty path is preserved exactly. When the argument is `null`, the resolver uses the INI setting, environment, and effective-user rules documented in the main README. Resolution does not require the directory to exist; getBibleSword emits a deterministic failed NDJSON stream if the path cannot be opened. #### Metadata ```php Engine::abiVersion(): int Engine::productVersion(): string Engine::contractIdentifier(): string ``` These return native library metadata with static lifetime. Extension startup fails if the embedded ABI version is not `1`. #### Path ```php $engine->modulePath(): string ``` Returns the resolved module root owned by this engine object. #### Module listing ```php $engine->streamModules(mixed $destination): int ``` `$destination` must be a writable PHP stream resource. The method calls `gbs_list_modules_v1()` synchronously, writes each callback span completely, and returns the number of bytes accepted by the stream. #### Module extraction ```php $engine->streamModule( string $module, mixed $destination, int $artifactChunkSize = Engine::DEFAULT_ARTIFACT_CHUNK_SIZE ): int ``` The module name must be non-empty. The chunk size must be from `4096` through `16777216` bytes. Chunk size controls getBibleSword artifact records, not the size of PHP stream writes and not NDJSON record boundaries. ### Exceptions Native failures throw `GetBible\Sword\Exception`, which extends `RuntimeException`. Its integer code maps directly to C ABI status: | Code | Native status | Meaning | |---:|---|---| | `1` | `GBS_STATUS_INVALID_ARGUMENT` | ABI or native input was invalid | | `2` | `GBS_STATUS_EXTRACTION_FAILED` | A complete `success:false` footer was emitted | | `3` | `GBS_STATUS_WRITE_FAILED` | The PHP destination refused output | | `4` | `GBS_STATUS_CANCELLED` | The native callback operation was cancelled | | `255` | `GBS_STATUS_INTERNAL_ERROR` | A contained native failure occurred | PHP signature and range violations use normal `TypeError` or `ValueError`. An extraction failure can still produce a complete NDJSON stream. Applications should inspect or retain that stream for diagnostics even when the method throws. ### Concurrency Engine objects hold only an immutable module-path string. They are safe in NTS and ZTS builds. getBibleSword ABI v1 serializes SWORD operations within one process; separate PHP-FPM workers remain independent. Do not modify, install, replace, or remove module data while any engine call is reading the same root. ## Support and source documentation For questions about this project, installation, unexpected output, or contributing, use the [single GetBible support desk](https://git.vdm.dev/getBible/support). Include the project, installed release or commit, operating system, relevant API version, and a minimal reproduction. General enquiries can be sent to [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church). This guide follows the [repository README](https://github.com/getbible/sword/blob/HEAD/README.md) and [php-api](https://github.com/getbible/sword/blob/HEAD/docs/php-api.md). Scripture and study resources retain their own source licences; a software licence does not relicense the texts. --- # Access and tokens **Normal public GetBible access is free and does not require an account or token.** This includes scripture, query, search, dictionaries, commentaries, public bookmarks and the MCP service. Start directly with the [API guides](/api/) or connect an AI application to the [MCP endpoint](/mcp/). Optional tokens are issued by GetBible administrators for approved access to individual endpoints. [Published access policy](https://github.com/getbible/mcp/blob/main/site/v2/usage-policy.md). ## Request an optional token Email [getBible@TrueChristian.church](mailto:getBible@TrueChristian.church) privately. Explain which endpoint you want to use, what your application does, and the request volume or access requirement you would like the team to consider. This helps the administrators assess the request; no automated signup or automatic quota upgrade is implied. The administrators provide any approved token, its scope and its applicable policy. A token for one host is not automatically valid for another. Keep credentials out of the public [support desk](https://git.vdm.dev/getBible/support), repository issues, screenshots and shared logs. ## Where a token belongs Use the secure credential settings in your application or MCP client to send an issued token as an HTTP bearer credential to its approved endpoint. The standard header is `Authorization: Bearer` followed by that token. Do not place tokens in a URL, Bible reference, MCP tool argument, public source code or a browser-delivered static site. The public ChatGPT development connection uses **No Authentication**. GetBible's optional bearer credentials do not establish an OAuth flow or a ChatGPT API-key sign-in method. Use them in clients that support secure custom HTTP credentials, following the administrators' instructions. [Client authentication guidance](https://github.com/getbible/mcp/blob/main/docs/CLIENTS.md). A credential configured for the MCP connection authenticates that connection. It is not a request to forward the credential to upstream API hosts. Deployment or package-publication credentials used by project maintainers are also separate from public API access tokens. ## Anonymous MCP traffic limits The official MCP service documents the same default anonymous limits as public search, per client address: | Control | Published default | | --- | --- | | Request rate | 50 requests per second | | Burst allowance | 250 requests | | Nominal hourly budget | 10,000 requests per hour | | Nominal daily budget | 100,000 requests per day | | Concurrent connections | 100 per address | Hourly and daily figures are sustained-rate budgets, not calendar quotas that reset at a fixed time. All applicable controls must be satisfied together. These MCP/search defaults must not be assumed to apply identically to every service; use each endpoint's documentation and actual response headers. [Limit definitions](https://github.com/getbible/mcp/blob/main/site/v2/usage-policy.md). ## Handle rate limits and failures When the server returns HTTP `429`, wait for `Retry-After` when it is present. Reduce concurrency and request rate, and use backoff instead of immediate retry loops. Handle other HTTP errors and unavailable upstreams explicitly. Successful health checks do not guarantee that every lookup can complete. For efficient integrations, prefer individual chapters and study entries over repeatedly downloading whole translations or modules. Follow search pagination without restarting the same query unnecessarily. Optional tokens do not remove content-license requirements or cache freshness rules. ## Content rights and caching Use each API version's translation catalog to read rich metadata and copyright information. Compact chapter, query or search results do not repeat every field, but the content's terms still apply. Dictionary and commentary modules have their own attribution, provenance and distribution terms. Public bookmarks supply topic/reference data with a separate license. If you cache eligible content, preserve source freshness, obey shorter HTTP lifetimes and `no-store`, and refresh within the absolute 30-day retention ceiling. Retain exact checksums where published and invalidate changed data at the appropriate scope. An unchanged hash does not extend an expired response indefinitely. [Full cache policy](https://github.com/getbible/mcp/blob/main/site/v2/cache-policy.md). Public questions about integrations, projects and API behavior belong at the [GetBible support desk](https://git.vdm.dev/getBible/support). Private token questions belong in [email](mailto:getBible@TrueChristian.church). You can also [support the project](/donate/) as it expands access to Scripture for developers and readers around the world.