109 lines
3.0 KiB
Markdown
109 lines
3.0 KiB
Markdown
# 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.
|
||
|
||
```json
|
||
{
|
||
"title": "My Blog",
|
||
"description": "A blog powered by volumen.",
|
||
"base_url": "https://example.com",
|
||
"language": "en",
|
||
"author": "Anonymous",
|
||
"fediverse_creator": "@petrbalvin@mastodon.social"
|
||
}
|
||
```
|
||
|
||
`fediverse_creator` is `null` when the site-wide default is not set; a per-post
|
||
value (see below) takes precedence when present.
|
||
|
||
## `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 |
|
||
| q | string | — | Case-insensitive search across title and body |
|
||
| page | int | 1 | Page number |
|
||
| limit | int | 20 | Per page (1–100) |
|
||
|
||
```json
|
||
{
|
||
"page": 1,
|
||
"page_size": 20,
|
||
"total": 1,
|
||
"has_next": false,
|
||
"has_prev": false,
|
||
"posts": [
|
||
{
|
||
"slug": "hello",
|
||
"title": "Hello",
|
||
"excerpt": "Hello world.",
|
||
"date": "2026-01-15",
|
||
"lang": "en",
|
||
"tags": ["intro"],
|
||
"author": null,
|
||
"fediverse_creator": 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. Drafts return `404` with `{"error":"draft"}`.
|
||
|
||
```json
|
||
{
|
||
"slug": "hello",
|
||
"title": "Hello",
|
||
"excerpt": "Hello world.",
|
||
"date": "2026-01-15",
|
||
"lang": "en",
|
||
"tags": ["intro"],
|
||
"author": null,
|
||
"fediverse_creator": "@petrbalvin@mastodon.social",
|
||
"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.
|
||
|
||
```json
|
||
{ "tags": [{ "name": "intro", "count": 1 }] }
|
||
```
|
||
|
||
## `GET /api/volumen/feed.xml`, `GET /api/volumen/feed.json`, `GET /api/volumen/sitemap.xml`
|
||
|
||
- `feed.xml` — RSS 2.0 feed of the 20 most recent posts.
|
||
- `feed.json` — [JSON Feed 1.1](https://www.jsonfeed.org/) document with
|
||
`content_html` and `date_published` per item.
|
||
- `sitemap.xml` — XML sitemap built from `site.base_url`.
|
||
|
||
## `OPTIONS /api/volumen/*`
|
||
|
||
Preflight requests return an empty `204` with the same CORS headers as the GET
|
||
endpoints, so browsers can reach the JSON API cross-origin. |