Skip to main content

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:

![architecture](https://shanebackend-production.up.railway.app/api/journal/images/<uuid>)

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.