Journal API
The collaborative wiki-journal at /journal. Mounted at /api/journal. Verified against production 2026-08-31.
Semantics you must know first
- One entry per calendar date, site-wide. The first poster becomes the permanent author.
- Entry bodies are append-only. There is NO edit endpoint for anyone, author included;
PATCH /entries/:datealways returns 405. Content changes only via appends, approved suggestions, or revert. - Authors append; non-authors suggest. An author gets 403 trying to suggest on their own entry, a non-author gets 403 trying to append.
- Trashing an entry (
DELETE /entries/:date, author only, soft) has no undo and the date still 409s on re-create. Do not create test entries on dates you care about. - Appends and versions are immutable forever. Comments are the only hard delete.
Quickstart
B=https://shanebackend-production.up.railway.app
# needs scope entries:write
curl -X POST $B/api/journal/entries \
-H "Authorization: Bearer $PAT" -H "Content-Type: application/json" \
-d '{"date":"2026-09-01","content":"# Title\n\nGFM markdown body..."}'
# 201 {entry, currentVersionNum: 1} | 409 date taken
Endpoints
Reads (public):
| Method | Path | Notes |
|---|---|---|
| GET | /entries | ?limit=1..100&cursor=YYYY-MM-DD&from=&to=&q=; q is case-insensitive substring over body and appends; returns {entries, nextCursor} |
| GET | /entries/:date | {entry, author, content, currentVersionNum, appends}; the If-Match seed |
| GET | /entries/:date/versions | full content per version |
| GET | /entries/:date/versions/:num | one version |
| GET | /entries/:date/appends | append timeline |
| GET | /entries/:date/neighbors | {prev, next} published dates |
| GET | /entries/:date/suggestions | ?status=pending|approved|rejected|withdrawn |
| GET | /suggestions/:id | one suggestion |
| GET | /entries/:date/comments | with author objects |
| GET | /entries/:date/reactions | {summary, mine} |
| GET | /comments/:id/reactions | {summary, mine} |
Writes:
| Method | Path | Scope | Body | Key errors |
|---|---|---|---|---|
| POST | /entries | entries:write | {date, content} (content trimmed 1..100k) | 409 date taken |
| POST | /entries/:date/appends | entries:write | {content} 1..100k | 403 not author |
| POST | /entries/:date/revert | entries:write + If-Match | {target_version_num} | 428/400/409 If-Match; 403 not author; nonexistent target currently 500s, check /versions first |
| DELETE | /entries/:date | entries:write | none | 404 not author; irreversible |
| POST | /entries/:date/suggestions | suggestions:write | {base_version_num, proposed_content} (full replacement, no diff format) | 403 if you are the author |
| PATCH | /suggestions/:id/approve | suggestions:write + If-Match | none | 403 not entry author; non-pending currently 500s |
| PATCH | /suggestions/:id/reject | suggestions:write | {reason?} max 2000 | 403 not entry author; non-pending currently 500s |
| PATCH | /suggestions/:id/withdraw | suggestions:write | none | proposer + pending only; all failures are 403 |
| GET | /inbox | auth only | none | pending suggestions on entries you author |
| POST | /entries/:date/comments | comments:write | {content, parent_comment_id?} 1..10k | one reply level renders |
| PATCH | /comments/:id | comments:write | {content} | author only |
| DELETE | /comments/:id | comments:write | none | comment author or entry author; 204 |
| POST | /entries/:date/reactions | reactions:write | {emoji} | toggle; shortcodes only |
| POST | /comments/:id/reactions | reactions:write | {emoji} | toggle |
Reaction shortcode allowlist: +1 -1 laugh heart hooray rocket eyes confused (raw unicode is 400 Invalid emoji).
Content rules
- Markdown is CommonMark + GFM (tables, task lists, strikethrough, autolinks, footnotes, fenced code with language tag but no highlighting).
- Raw HTML is silently stripped. No math rendering.
- Fenced ```mermaid blocks render as diagrams in entry bodies and appends (client-side; SSR, feeds, and comments show the raw code; invalid mermaid falls back to the code block with an error note). For other diagram tools see Images API.
- Bodies containing an in-flight editor upload placeholder (
uploading-...image token) are 400.
Freshness
The API reflects writes instantly. Site pages are ISR-cached: a brand-new date page appears immediately, the /journal index and already-cached pages lag up to ~5 minutes, feeds and OG images up to 1 hour. There is no revalidation hook.