Files
volumen/docs/api-reference.md
T

2.2 KiB
Raw Blame History

API Reference

Status: the public read API (/api/volumen) and the admin (/admin) are implemented. The admin is server-rendered HTML, not part of the JSON API.

Base path: /api/volumen. All responses are JSON unless noted. Read endpoints send Access-Control-Allow-Origin: *.

GET /api/volumen/site

Returns site metadata from the configuration.

{
  "title": "My Blog",
  "description": "A blog powered by volumen.",
  "base_url": "https://example.com",
  "language": "en",
  "author": "Anonymous"
}

GET /api/volumen/posts

Paginated list of published posts (drafts are excluded), newest first. Posts with all_langs = true in their frontmatter match every lang filter.

Name Type Default Description
lang string Filter by language
tag string Filter by tag
page int 1 Page number
limit int 20 Per page (1100)
{
  "page": 1,
  "page_size": 20,
  "total": 1,
  "posts": [
    {
      "slug": "hello",
      "title": "Hello",
      "excerpt": "Hello world.",
      "date": "2026-01-15",
      "lang": "en",
      "tags": ["intro"],
      "author": null,
      "cover": null,
      "reading_time": 1,
      "translations": {},
      "url": "/api/volumen/posts/hello"
    }
  ]
}

GET /api/volumen/posts/{slug}

Single post including the raw Markdown body and rendered HTML. Optional ?lang= selects a translation. Returns 404 with {"error":"not_found"} if no match.

{
  "slug": "hello",
  "title": "Hello",
  "excerpt": "Hello world.",
  "date": "2026-01-15",
  "lang": "en",
  "tags": ["intro"],
  "author": null,
  "cover": null,
  "reading_time": 1,
  "translations": {},
  "url": "/api/volumen/posts/hello",
  "body": "Hello **world**.",
  "html": "<p>Hello <strong>world</strong>.</p>\n"
}

GET /api/volumen/tags

Tag cloud with counts (published posts only), most frequent first.

{ "tags": [{ "name": "intro", "count": 1 }] }

GET /api/volumen/feed.xml, GET /api/volumen/sitemap.xml

RSS 2.0 feed (latest 20 posts) and a sitemap of post URLs, built from site.base_url.