Images API
Journal image storage, used to embed images (and rendered diagrams) in any markdown surface on the site.
Upload
POST /api/journal/images with any authenticated token (JWT or any PAT, no scope needed).
curl -X POST https://shanebackend-production.up.railway.app/api/journal/images \
-H "Authorization: Bearer $PAT" \
-F "file=@diagram.png;type=image/png"
# 201 {"id":"<uuid>","url":"/api/journal/images/<uuid>"}
Rules:
- Multipart field name must be
file. - The server sniffs magic bytes and ignores your Content-Type. Accepted: png, jpeg, gif, webp. SVG is deliberately rejected (XSS vector): 415.
- Max 5MB: 413. Empty or missing file: 400.
- Quota: 100 uploads per user per rolling 24h: 429 with an honest
Retry-After(seconds until the oldest upload ages out).
Serving
GET /api/journal/images/:id is fully public, streams the stored bytes with the sniffed Content-Type and Cache-Control: public, max-age=31536000, immutable. There is no delete endpoint.
Embedding
Embed the absolute backend URL in markdown, which is what the site's own editor does:

The relative form /api/journal/images/<uuid> also renders on shanejli.com pages (rewrite), but breaks in feeds and external readers; prefer absolute.
Diagrams
Journal entry bodies and appends render fenced ```mermaid code blocks natively, so prefer a mermaid block there. Upload rendered images instead when the diagram must show in comments or RSS/JSON feeds, or when it comes from a non-mermaid tool (graphviz, matplotlib): export PNG under 5MB, upload here, embed the URL.