Everything the cloudrun UI does goes through this API — it is not a separate facade, so
what you can click you can curl. Platform resources (projects, engines, templates, your
organization, API keys) have their own namespaces; engine operations are namespaced by
engine kind, and today that means Hermes:
/api/projects, /api/templates, /api/org, /api/keys, … — the platform
GET /api/engines/{engineId} — what an engine is, whatever its kind
An API key — create one in Settings → API keys (org admins only). Keys are
org-scoped: one key manages every project and engine the organization owns. The full key
is shown once at creation and stored hashed.
Your browser session — the app itself calls these endpoints with your Clerk session,
so anything you can do signed in, the API does too.
Every failure is JSON: { "error": "message" } with a meaningful status —
400 invalid body or an engine kind that doesn't support the resource · 401 missing or
invalid credentials · 403 not yours to touch · 404 unknown resource (including ones
owned by another org) · 409 a name or address is already taken · 502 the engine or an
upstream service failed (box down, unknown profile, …).
POST /api/hermes/{e}/chat?profile={p} streams a conversation turn (AI SDK UI-message
stream). Send { "messages": [...], "id": "<session id>" } — the id names the
engine-side session, created on first use and resumed forever after.
method + path
returns
GET /api/hermes/{e}/profiles/{p}/sessions
[{ id, title, updatedAt }]
GET /api/hermes/{e}/profiles/{p}/sessions/{sessionId}/messages
An agent snapshots into a portable payload (identity, skills, automations, connected
integrations and channels); publishing puts that payload on the marketplace; installing
turns it back into a live agent.
method + path
body
returns
GET /api/hermes/{e}/profiles/{p}/snapshot
—
the agent's portable payload
GET /api/hermes/{e}/profiles/{p}/listing
—
the agent's marketplace listing, or null
PUT …/listing
{ name, description, visibility, tags, payload } — visibility is public | org | private
PATCH /api/me — { firstName, lastName, imageUrl? } → { ok }. Session only: an API
key is an organization credential, not a person, so this endpoint rejects it.