Skip to content

Conventions

Shared rules that apply across the whole bridge API. Read once; they hold for every endpoint in the reference.

Base URL

Every path in this reference is relative to the origin of your Hermes Web UI server — e.g. https://hermes.example.com or http://127.0.0.1:8787. There is no /v1 version prefix; the surface is versioned by the server release (see Insights & updates for the running version).

Headers

Header When
Content-Type: application/json On any request with a JSON body (most POSTs).
Accept: text/event-stream On the SSE streaming GETs.
Cookie: hermes_session=… On every request once logged in (your HTTP session replays it automatically).
Authorization / X-Api-Key / custom Only for proxy/token-gated deployments — see Authentication.

Uploads (/api/upload, /api/transcribe) use multipart/form-data instead of JSON — noted per endpoint.

Methods

  • GET — reads (lists, details, streams, status).
  • POST — everything mutating (create, rename, delete-by-body, chat, git ops, cron ops). Hermes uses POST for most mutations including deletes (the delete target is in the JSON body), rather than DELETE. A handful of newer endpoints use PATCH/DELETE/PUT — noted per endpoint.

Session IDs

Most endpoints operate on a session (a conversation). A session_id is an opaque string returned by /api/sessions and /api/session/new. Pass it either as a query param (?session_id=… on GETs) or in the JSON body (on POSTs) — each endpoint's spec says which. Workspace, git, file, approval, and clarify calls are all scoped by session_id.

Response shape

Successful JSON responses are objects. List endpoints wrap their array under a named key ({ "sessions": [...] }, { "projects": [...] }, { "crons": [...] }) rather than returning a bare array, so the response can carry sibling metadata. Field names are snake_case.

Errors

Failed requests use standard HTTP status codes with a JSON body:

{ "error": "human-readable message" }

(Some endpoints also include a detail or message field.) Common codes:

Status Meaning
400 Malformed request (bad/missing params or body).
401 Not authenticated — log in (see Authentication).
403 Authenticated but the action is refused.
404 No such session / resource / path.
409 Conflict (e.g. a git operation that can't proceed).
429 Rate-limited (repeated login attempts).
500 Server-side failure — surface the message; safe to retry idempotent reads.

A client should treat any non-2xx as a failure and read the error field for display.

Pagination & large payloads

  • Session list returns all sessions (sidebar-sized). Session detail (/api/session) supports messageLimit / messageBefore to page a long transcript, and includeMessages=false to fetch metadata only.
  • Search (/api/sessions/search) takes query, a content flag (search message bodies vs. titles), and a depth.
  • File reads stream raw bytes (/api/file/raw, /api/media); JSON file reads come via /api/file.

IDs, timestamps, and booleans

  • Timestamps are ISO-8601 strings (UTC) unless noted.
  • Booleans are JSON true/false (not 0/1).
  • Message ids within a session are integers; session/project/cron ids are strings.

Idempotency & retries

Reads (GET) are safe to retry. Mutations are generally not idempotent (a second /api/session/new makes a second session) — don't blind-retry a POST on a network timeout without checking state first (e.g. re-list sessions).

Streaming

Anything real-time (live chat, approvals, clarifications) is Server-Sent Events, documented in Streaming (SSE). SSE GETs are long-lived — don't apply your normal short request timeout to them.