API Overview
Base URL, transport, auth model summary, and the error envelope every endpoint shares.
Mosaic exposes a JSON REST surface plus a single WebSocket fan-out at /api/ws. Every endpoint the desktop SPA calls is reachable from the API; the SPA itself is a client of this surface, with a transport shim that swaps Wails IPC for fetch + WS when running in browser mode.
This page covers the cross-cutting concerns. For the per-endpoint reference, see REST Endpoints and WebSocket.
Base URL
https://<host>:<port>/api
<port> defaults to 8080 and is configurable via WebConfigDTO.port. When the remote interface is enabled in loopback-only mode the only reachable host is 127.0.0.1. With “Bind to all” toggled on, the listener binds 0.0.0.0 (or [::]:<port>).
The cert is self-signed; expect a browser warning on first connect, and pass -k (or pin the cert) for curl-driven scripts.
Transport
| Surface | Transport |
|---|---|
| REST | application/json over HTTPS |
| WebSocket | wss://<host>:<port>/api/ws |
| File upload | multipart/form-data (one route — POST /api/torrents/file) |
Request bodies are JSON unless noted. Response bodies are JSON; errors share an envelope (see below).
Authentication
Two methods, accepted on every gated route:
- Session cookie — set on
POST /api/login, sent automatically by the browser. Name:mosaic_session. HttpOnly, SameSite=Strict, Secure when behind HTTPS. - Bearer API key —
Authorization: Bearer <key>. For browser WebSocket upgrades that can’t set headers, pass it as?key=<key>instead.
State-changing cookie-authed requests must satisfy the Origin/Referer CSRF guard (host of Origin or Referer must equal Host). Bearer-keyed requests skip this check. See Authentication for the full flow.
Error envelope
Every error response carries the same shape — JSON regardless of route, no exceptions:
{ "error": "<message>" }
| Status | Meaning |
|---|---|
| 200 | Success. |
| 400 | Bad request — missing/invalid body, invalid params, validation failure. |
| 401 | Unauthorized — no valid session cookie and no valid bearer token. |
| 403 | Forbidden — Origin/Referer didn’t match Host on a cookie-authed state-changing request. |
| 429 | Too Many Requests — login rate limiter tripped. Retry-After: 12 header is set. |
| 500 | Internal error. |
| 502 | Upstream failure — e.g. blocklist URL didn’t return. |
A success response is either an explicit shape (DTO or list of DTOs), or a generic ack: {"ok": true} for fire-and-forget commands, {"id": "<value>"} for create endpoints.
Versioning
Mosaic does not currently version its API surface in the URL. The DTOs are documented per release; backwards-incompatible field renames will bump the minor version and call out the change in release notes. The build’s version string is reachable at GET /api/version ({"version": "vX.Y.Z"}).
Quick check
# Replace with your own
export MOSAIC="https://localhost:8080"
export MOSAIC_API_KEY="<paste-from-Settings-WebInterface>"
curl -k "$MOSAIC/api/version" -H "Authorization: Bearer $MOSAIC_API_KEY"
# → {"version":"v0.2.9"}
curl -k "$MOSAIC/api/torrents" -H "Authorization: Bearer $MOSAIC_API_KEY"
# → [...torrent rows...]
If you get {"error":"unauthorized"}, double-check the API key and that the bearer header isn’t being stripped by an intermediate proxy.