API reference · v1.0.1
GraceSoft Storehouse API
Public-domain Proverbs and original GraceSoft quips, as static JSON.
Base URL https://api.gracesoft.dev
GraceSoft Storehouse is a read-only, versioned REST API. Every response is a static JSON file served from Vercel's global CDN, so it's fast, cacheable, and needs no API key.
Envelope. Successful responses are { "data": …, "meta": { "version", "generatedAt" } }. Lists also carry meta.count. Errors are { "error": { "status", "code", "message" }, "meta" }.
Time zone. "Today" is always evaluated in Asia/Singapore (UTC+8). New quips go live at 00:00 SGT on their publishAt date, after the daily scheduled rebuild.
Caching. Responses carry ETag and Cache-Control headers; send If-None-Match to get 304 Not Modified.
CORS. Browser access is limited to an allowlist of GraceSoft origins. Server-side clients (bots, scripts) can call the API from anywhere.
Versioning. Additive changes stay in v1. Breaking changes go to v2.
Licence. Proverbs text is public domain. Quips are © D.L. (GraceSoft) — see CONTENT_LICENSE.md for terms of reuse.
Translations
The public-domain Bible translations available.
GET
/v1/translations.json
List translations
Every translation in the registry, sorted by code.
Responses
- 200 The translation registry. — TranslationListResponse
- 304 The resource hasn't changed since the
If-None-Match ETag.
- 4XX The request can't be served, e.g.
405 for any method other than GET, HEAD, or OPTIONS. — ErrorResponse
Example
curl https://api.gracesoft.dev/v1/translations.json
{
"data": [
{
"code": "asv",
"name": "American Standard Version",
"year": 1901,
"language": "en",
"license": "Public Domain",
"source": "https://ebible.org/find/details.php?id=eng-asv"
},
{
"code": "kjv",
"name": "King James Version",
"year": 1769,
"language": "en",
"license": "Public Domain",
"source": "https://ebible.org/find/details.php?id=eng-kjv2006"
},
{
"code": "web",
"name": "World English Bible",
"year": 2000,
"language": "en",
"license": "Public Domain",
"source": "https://ebible.org/find/details.php?id=engwebp"
}
],
"meta": {
"version": "1.0.1",
"generatedAt": "2026-10-19T10:30:38.042Z",
"count": 3
}
}
Proverbs
The 31 chapters of the book of Proverbs, per translation.
GET
/v1/proverbs/{code}/index.json
List chapters
The 31 chapters of Proverbs for one translation, with verse counts.
Parameters
| Name | In | Type | Description |
code required | path | string | A translation code from /v1/translations.json, e.g. kjv. |
Responses
- 200 Chapter summaries for one translation. — ChapterListResponse
- 304 The resource hasn't changed since the
If-None-Match ETag.
- 404 No resource exists at this path. — ErrorResponse
Example
curl https://api.gracesoft.dev/v1/proverbs/kjv/index.json
{
"data": [
{
"translation": "kjv",
"chapter": 1,
"verseCount": 33,
"href": "/v1/proverbs/kjv/1.json"
},
{
"translation": "kjv",
"chapter": 2,
"verseCount": 22,
"href": "/v1/proverbs/kjv/2.json"
},
{
"translation": "kjv",
"chapter": 3,
"verseCount": 35,
"href": "/v1/proverbs/kjv/3.json"
},
"… 28 more"
],
"meta": {
"version": "1.0.1",
"generatedAt": "2026-10-19T10:30:38.042Z",
"count": 31
}
}
GET
/v1/proverbs/{code}/{chapter}.json
Get a chapter
One chapter of Proverbs, with every verse.
Parameters
| Name | In | Type | Description |
code required | path | string | A translation code from /v1/translations.json, e.g. kjv. |
chapter required | path | integer (1–31) | Chapter number, 1–31. |
Responses
- 200 One chapter with its verses. — ChapterResponse
- 304 The resource hasn't changed since the
If-None-Match ETag.
- 404 No resource exists at this path. — ErrorResponse
Example
curl https://api.gracesoft.dev/v1/proverbs/kjv/3.json
{
"data": {
"translation": "kjv",
"translationName": "King James Version",
"chapter": 3,
"verses": [
{
"verse": 1,
"text": "My son, forget not my law; but let thine heart keep my commandments:"
},
{
"verse": 2,
"text": "For length of days, and long life, and peace, shall they add to thee."
},
{
"verse": 3,
"text": "Let not mercy and truth forsake thee: bind them about thy neck; write them upon the table of thine heart:"
},
"… 32 more"
]
},
"meta": {
"version": "1.0.1",
"generatedAt": "2026-10-19T10:30:38.042Z"
}
}
GET
/v1/proverbs/{code}/today
Dynamic
Get today's chapter
The chapter matching today's day of the month in Asia/Singapore ("a Proverb a day"). On the 19th, this is chapter 19.
Served by a Vercel Function that reads the static chapter file; responses are cached until the next 00:00 SGT. Rate-limited.
Parameters
| Name | In | Type | Description |
code required | path | string | A translation code from /v1/translations.json, e.g. kjv. |
Responses
- 200 One chapter with its verses. — ChapterResponse
- 404 No resource exists at this path. — ErrorResponse
- 429 Rate limit exceeded (60 requests a minute per IP on the dynamic endpoints). Returned by the Vercel Firewall, so the body isn't the JSON error shape. Wait a minute and retry.
Example
curl https://api.gracesoft.dev/v1/proverbs/web/today
{
"data": {
"translation": "web",
"translationName": "World English Bible",
"chapter": 3,
"verses": [
{
"verse": 1,
"text": "My son, don’t forget my teaching, but let your heart keep my commandments,"
},
{
"verse": 2,
"text": "for they will add to you length of days, years of life, and peace."
},
{
"verse": 3,
"text": "Don’t let kindness and truth forsake you. Bind them around your neck. Write them on the tablet of your heart."
},
"… 32 more"
]
},
"meta": {
"version": "1.0.1",
"generatedAt": "2026-10-19T10:30:38.042Z"
}
}
Quips
Original GraceSoft quips and puns. Only published quips are served.
List quips
Every published quip, sorted by id. Drafts and future-dated quips are never included.
Responses
- 200 Every published quip. — QuipListResponse
- 304 The resource hasn't changed since the
If-None-Match ETag.
- 4XX The request can't be served, e.g.
405 for any method other than GET, HEAD, or OPTIONS. — ErrorResponse
Example
curl https://api.gracesoft.dev/v1/quips/index.json
{
"data": [
{
"id": 1,
"slug": "when-youre-on-a-keto-diet",
"variant": "statement",
"punchline": "When you're on a keto diet, you gotta lock down your intake.",
"tags": [
"food"
],
"createdAt": "2026-10-06",
"publishAt": "2026-10-06"
},
{
"id": 2,
"slug": "oh-oh-oats",
"variant": "qa",
"question": "What does Santa like to have for breakfast?",
"punchline": "Oh, oh, oats.",
"tags": [
"food",
"christmas"
],
"createdAt": "2026-10-06",
"publishAt": "2026-10-06"
},
{
"id": 3,
"slug": "young-tau-foo",
"variant": "qa",
"question": "What hawker dish would you consume for youthfulness?",
"punchline": "Young tau foo.",
"tags": [
"food",
"singapore",
"hawker"
],
"createdAt": "2026-10-06",
"publishAt": "2026-10-06"
},
"… 62 more"
],
"meta": {
"version": "1.0.1",
"generatedAt": "2026-10-19T10:30:38.042Z",
"count": 65
}
}
Get a quip
One published quip. Unpublished, draft, and retired ids return 404.
Parameters
| Name | In | Type | Description |
id required | path | integer (≥ 1) | The quip's permanent id. |
Responses
- 200 One published quip. — QuipResponse
- 304 The resource hasn't changed since the
If-None-Match ETag.
- 404 No resource exists at this path. — ErrorResponse
Example
curl https://api.gracesoft.dev/v1/quips/2.json
{
"data": {
"id": 2,
"slug": "oh-oh-oats",
"variant": "qa",
"question": "What does Santa like to have for breakfast?",
"punchline": "Oh, oh, oats.",
"tags": [
"food",
"christmas"
],
"createdAt": "2026-10-06",
"publishAt": "2026-10-06"
},
"meta": {
"version": "1.0.1",
"generatedAt": "2026-10-19T10:30:38.042Z"
}
}
GET
/v1/quips/random
Dynamic
Get a random quip
A random published quip. Never cached. Served by a Vercel Function that reads /v1/quips/index.json. Rate-limited.
Parameters
| Name | In | Type | Description |
tag | query | string | Only pick from quips with this tag. |
Responses
- 200 One published quip. — QuipResponse
- 404 No resource exists at this path. — ErrorResponse
- 429 Rate limit exceeded (60 requests a minute per IP on the dynamic endpoints). Returned by the Vercel Firewall, so the body isn't the JSON error shape. Wait a minute and retry.
Example
curl https://api.gracesoft.dev/v1/quips/random?tag=food
{
"data": {
"id": 2,
"slug": "oh-oh-oats",
"variant": "qa",
"question": "What does Santa like to have for breakfast?",
"punchline": "Oh, oh, oats.",
"tags": [
"food",
"christmas"
],
"createdAt": "2026-10-06",
"publishAt": "2026-10-06"
},
"meta": {
"version": "1.0.1",
"generatedAt": "2026-10-19T10:30:38.042Z"
}
}
Schemas
Meta
| Field | Type | Description |
version required | string | API release version (semver). |
generatedAt required | string (date-time) | When this response was built. |
ListMeta
| Field | Type | Description |
version required | string | API release version (semver). |
generatedAt required | string (date-time) | When this response was built. |
count required | integer (≥ 0) | Number of items in data. |
Translation
| Field | Type | Description |
code required | string | |
name required | string | |
year required | integer | |
language required | string | ISO 639-1 language code. |
license required | "Public Domain" | |
source required | string (uri) | Where the text was obtained. |
ChapterSummary
| Field | Type | Description |
translation required | string | |
chapter required | integer (1–31) | |
verseCount required | integer (≥ 1) | |
href required | string | Path to the chapter resource. |
Verse
| Field | Type | Description |
verse required | integer (≥ 1) | |
text required | string | Plain text (no Markdown or HTML). May contain curly quotes and em dashes. |
Chapter
| Field | Type | Description |
translation required | string | |
translationName required | string | |
chapter required | integer (1–31) | |
verses required | Verse[] | |
Quip
| Field | Type | Description |
id required | integer (≥ 1) | Permanent id; never reused. |
slug required | string | |
variant required | "qa" | "statement" | qa has a question and a punchline; statement has only a punchline.
|
question | string | Present only when variant is qa. |
punchline required | string | Plain text. Paragraphs are separated by a blank line (\n\n). |
tags required | string[] | |
createdAt required | string | ISO 8601 date (YYYY-MM-DD) or date-time with offset. |
publishAt required | string | ISO 8601 date or date-time. A date means 00:00 Asia/Singapore. |
TranslationListResponse
ChapterListResponse
ChapterResponse
| Field | Type | Description |
data required | Chapter | |
meta required | Meta | |
QuipListResponse
| Field | Type | Description |
data required | Quip[] | |
meta required | ListMeta | |
QuipResponse
| Field | Type | Description |
data required | Quip | |
meta required | Meta | |
ErrorResponse
| Field | Type | Description |
error required | object | |
meta required | Meta | |