Developers Live

Quotes with receipts, one URL away

A free, keyless, read-only API for people, apps and AI agents: JSON by default, CORS open, plain text for terminals, SVG cards, feeds and an MCP server. 288 quotes from 67 voices, each with its source.

Base URLhttps://api.loving-universe.com

Quick start

No key, no signup, no SDK. Paste any of these into a terminal — they are live.

a random quote · plain text for curl
$ curl https://api.loving-universe.com/random
“Heaven is under our feet as well as over our heads.” — Henry David Thoreau, Walden (1854)
text format · business
$ curl "https://api.loving-universe.com/random.txt?category=business"
“Few things help an individual more than to place responsibility upon him, and to let him know that you trust him.” — Booker T. Washington, Up from Slavery: An Autobiography (1901)
quote of the day · JSON (changes daily)
$ curl "https://api.loving-universe.com/today?category=wisdom"
{
  "id": "buddha-hatred-ceases-by-love",
  "text": "For hatred does not cease by hatred at any time: hatred ceases by love, this is an old rule.",
  "author": { "slug": "buddha", "name": "The Buddha" },
  "source": { "title": "The Dhammapada", "year": 1881, "locator": "v. 5", "translator": "F. Max Müller", … },
  "verification": "verified",
  "attribution": "The Buddha, The Dhammapada (1881)",
  …
}
JavaScript · CORS open
const quote = await fetch("https://api.loving-universe.com/today?tz=Europe/Ljubljana")
  .then((r) => r.json());
console.log(quote.text, "—", quote.attribution);

Endpoints

Everything is GET except POST /verify and POST /mcp. Paths are relative to the base URL.

RouteReturns
GET/API index (JSON). curl or Accept: text/plain get a random quote as text.
GET/randomOne random quote. With count, an array of quotes.
GET/todayQuote of the day — the same all day for the same filters (tz = IANA timezone, default UTC).
GET/quotesList and search: { "data": [...], "total": n, "next": "<cursor>" | null }
GET/quotes/{id}One quote.
GET/authors · /authors/{slug}All authors, or one author.
GET/categoriesThe fifteen categories with counts.
GET/tagsTags with counts, most used first.
GET/verify?text=&author= · POST/verifyIs this quote real? See below.
GET/feed.xmlRSS 2.0 — quote of the day for the last 30 days (accepts filters).
GET/calendar.icsiCalendar — one all-day event per day for the next 60 days (accepts filters).
GET/openapi.json · /llms.txtOpenAPI 3.1, and a Markdown guide for LLMs.
POST/mcpMCP server (Streamable HTTP, stateless, no auth).

Filters

All optional. A comma means any of; different parameters combine with and.

ParamApplies toExample
categoryrandom, today, quotes, feedscategory=business,motivation
authorrandom, today, quotes, feedsauthor=marcus-aurelius
tagrandom, today, quotes, feedstag=gratitude
qrandom, quotesq=courage — case- and accent-insensitive
max_length · min_lengthrandom, today, quotes, feedsmax_length=120
verifiedall quote routesverified=true
public_domainall quote routespublic_domain=true
countrandom150
seedrandomany string → the same pick every time
excluderandomcomma-separated quote ids
limit · cursorquoteslimit 1–100 (default 20)
tztoday, feedstz=Europe/Ljubljana

Never a dead end: an unknown category or author returns 400 invalid_filter with did_you_mean; no match returns 404 no_match with a hint.

Formats & cards

/random, /today and /quotes/{id} take an extension or ?format=:

  • .json — the default.
  • .txt — plain text: “text” — Author, Source (year).
  • .md — a Markdown blockquote.
  • .svg — a quote card. theme=dawn|dusk|night|forest|ocean, size=square|story|wide (1080×1080, 1080×1920, 1200×630).

Without either, Accept: text/plain, text/markdown and image/svg+xml are honoured, and curl, wget and HTTPie get text. /random.svg answers 302 to /quotes/{id}.svg, so the image itself stays cacheable.

SVG card
$ curl -o card.svg \
    https://api.loving-universe.com/quotes/tagore-miss-the-stars.svg

# or in HTML
<img src="https://api.loving-universe.com/random.svg?size=wide&theme=night"
     alt="An uplifting quote">
Quote card: “If you shed tears when you miss the sun, you also miss the stars.” — Rabindranath Tagore, Stray Birds (1916)
Live from /quotes/tagore-miss-the-stars.svg · PNG for social: /quotes/tagore-miss-the-stars.png?size=wide

The quote object

Every quote carries its receipt. source passes through every field we hold (publisher, translator …).

GET /quotes/tagore-miss-the-stars
{
  "id": "tagore-miss-the-stars",
  "text": "If you shed tears when you miss the sun, you also miss the stars.",
  "author": { "slug": "rabindranath-tagore", "name": "Rabindranath Tagore" },
  "categories": ["hope", "wisdom"],
  "tags": ["perspective", "loss", "poetry"],
  "source": { "title": "Stray Birds", "type": "book", "year": 1916, "locator": "No. 6",
              "publisher": "Macmillan", "url": "https://www.gutenberg.org/ebooks/6524" },
  "verification": "verified",
  "rights": "public-domain",
  "length": 65,
  "url": "https://api.loving-universe.com/quotes/tagore-miss-the-stars",
  "attribution": "Rabindranath Tagore, Stray Birds (1916)"
}

Author { slug, name, born, died, description, wikipedia, count } · Category { slug, name, description, count } · Error { "error": { "code", "message", "hint" } }

Is this quote real?

Send the words you found (and who they are credited to). The answer is verified, paraphrase, misattributed or unknown — never a guess.

GET /verify
$ curl -G https://api.loving-universe.com/verify \
    --data-urlencode "text=Insanity is doing the same thing over and over again and expecting different results." \
    --data-urlencode "author=Albert Einstein"

{
  "verdict": "misattributed",
  "confidence": 1,
  "claimed_author": "Albert Einstein",
  "actual_author": null,
  "finding": "There is no evidence Einstein said or wrote this. The earliest known uses come from 1981 in Al-Anon and Narcotics Anonymous settings, and the link to Einstein appeared many years after his death.",
  "references": ["https://quoteinvestigator.com/2017/03/23/same/"]
}

Near-exact text in the library is verified (or misattributed when the claimed author differs); close but different wording is a paraphrase with the real words attached. POST /verify takes the same fields as JSON.

MCP for agents

Point any MCP client at https://api.loving-universe.com/mcp (Streamable HTTP, no auth). Every tool is read-only, and the server asks models to quote exactly and always show the author and source.

mcp.json
{
  "mcpServers": {
    "loving-universe": { "url": "https://api.loving-universe.com/mcp" }
  }
}
Claude Code
$ claude mcp add --transport http loving-universe https://api.loving-universe.com/mcp
ToolInputOutput
random_quotecategory? author? tag? max_length? count? (1–10)quotes
quote_of_the_daycategory? tz?quote
search_quotesq category? author? limit?quotes
get_quoteidquote
verify_quotetext author?verify result
list_categories · list_authorscategories · authors

Caching & limits

RouteCache-Control
/random*public, max-age=1, s-maxage=1
/today*public, max-age= seconds until midnight in tz
/quotes/{id}*, /authors*, /categories, /tags, /openapi.json, /llms.txt, GET /verifypublic, max-age=3600, stale-while-revalidate=86400
/quotes, feedspublic, max-age=300

Every response carries Access-Control-Allow-Origin: * and X-Dataset-Version. The soft limit is 120 requests per minute per IP (429 with Retry-After).