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.
GET/embed/quote-loader.js · /embed/quote-loader.cssDrop-in page-loader script and styles (CDN-cached).
GET/embed/{version}/quote-loader.js · .cssSame assets, pinned version (immutable cache).
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
countrandom1–50
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

Page loader embed

Drop-in JavaScript and CSS for existing page loaders and spinners. Served from the API edge and CDN-cached after the first load — no npm package, no copy/paste into your repo.

URLs: https://api.loving-universe.com/embed/quote-loader.js and https://api.loving-universe.com/embed/quote-loader.css. Responses include an X-Embed-Version header (8-char hash). Pin that value in the path for a permanent browser cache key: /embed/{version}/quote-loader.js (and .css) with immutable cache.

CDN · drop-in loader
<link rel="stylesheet" href="https://api.loving-universe.com/embed/quote-loader.css" />
<div id="app-loader" data-lu-loader data-lu-placement="below">
  <div class="your-spinner"></div>
</div>
<script src="https://api.loving-universe.com/embed/quote-loader.js" defer></script>
URLCacheUse when
/embed/quote-loader.js · .css1 h + stale-while-revalidateAlways get latest after deploy
/embed/{version}/quote-loader.js · .css1 year immutablePin X-Embed-Version from the latest URL

Mark any loader container with data-lu-loader. The script fetches quotes via existing GET /random and GET /today — no new API endpoint.

AttributeExampleMeaning
data-lu-placementbelowbelow (default), above, or overlay
data-lu-linkfalseHide the italic Loving Universe credit
data-lu-font(omit)Default inherit — your site fonts; serif for editorial stack

Overlay mode: data-lu-placement="overlay" keeps the spinner centred and places the quote in the lower third.

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_authors—categories · 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 /verify, /embed/quote-loader.*public, max-age=3600, stale-while-revalidate=86400
/embed/{version}/quote-loader.*public, max-age=31536000, immutable
/quotes, feedspublic, max-age=300

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