https://{instanceId}.agent37.app, with the same sk_live_ key sent as the X-Agent37-Key header. The platform edge authenticates the key and checks the instance belongs to your workspace, then the gateway answers. See Instance and preview URLs.
Endpoints
You never create a session directly. The first
POST /v1/responses without a session_id mints one and returns its id; reuse that id to continue the thread.Choosing the harness
Every read on this page takes an optional?agent= query, hermes, openclaw, claude-code, codex, grok, or opencode, that selects which harness on the instance answers. Omit it (or send it empty) and the instance’s configured default harness answers; the response echoes which agent it was. An unknown value is 400 validation_error, and targeting a harness the instance was not provisioned with is 503 agent_unavailable. Your agent37-hermes Cloud instances serve Hermes, so you can leave ?agent= off.
codex, grok, and opencode mint their own session ids. A client cannot bring an unknown session_id on the first turn: POST /v1/responses rejects one it did not issue with 400 validation_error (param: session_id). Omit session_id to start a thread and reuse the id the response returns. Sessions you start in the instance terminal appear in GET /v1/sessions?agent=codex (or ?agent=grok, ?agent=opencode) on their own. grok stores no editable session title, so PATCH /v1/sessions/{id} answers 405 rename_unsupported there.The session object
Every row ofGET /v1/sessions is the same shape regardless of harness: { id, title, last_active, message_count, preview }. The gateway projects the harness’s own store into it on read, so a field the harness doesn’t track is null rather than missing.
string
The session id you pass back to
GET, PATCH, and DELETE /v1/sessions/{id}, and the session_id every response in the conversation carries. 32 hex characters, no prefix.string | null
The harness’s own editable title, exactly what rename writes. Hermes generates one on its own shortly after the first completed exchange, so Hermes rows usually carry a title without a rename; an OpenClaw session stays
null until a rename sets its label.number | null
When the session was last active, in epoch milliseconds.
null when the harness reports no timestamp.number | null
How many messages the session holds. Hermes reports it; OpenClaw does not track it and returns
null.string | null
The opening of the session’s first user message, for list display. Hermes reports it; OpenClaw does not track it and returns
null.List sessions
GET /v1/sessions returns the harness’s sessions, newest first, wrapped in { "agent": "...", "data": [...] }. The list is capped: Hermes returns up to 100 sessions, most recent activity first. OpenClaw returns only the sessions started through this API, drawn from its 1,000 most recently active sessions of any kind. Conversations from OpenClaw’s own surfaces, such as its Control UI or a connected channel, count toward that window but are not listed and cannot be read by id through this API. The agent names which harness the list is for. Pass ?agent=hermes or ?agent=openclaw to pick a harness; omit it for the instance default. The list carries session metadata only, never history, so it stays cheap to poll for a sidebar. A harness without a list API returns data: [].
Retrieve a session with history
GET /v1/sessions/{id} returns { "id", "agent", "active_response_id", "history", "context" }: history is the full transcript, in order, projected from the harness. You read it for display or audit; you never resend it, because the session already holds it. An unknown id returns an empty history rather than a 404, because the harness owns whether a session exists. Pass ?agent= to pick the harness.
string | null
The id of the response currently running on the session, or
null when it is idle. The harness writes a turn’s messages at turn end, so while this is set the running turn is normally not in history yet. Follow it live with GET /v1/responses/{id}/stream. This is how a client that lost its state (page reload, new device) rediscovers a running turn and reattaches. Two timing edges: right at turn end, one read can briefly show the finished turn in history and its id still here; reattaching is still correct, the replay just ends immediately. And once it reads null the transcript is complete.object | null
The session’s last reported context window:
{ used_tokens, window_tokens }, the tokens occupying the model’s window against the window’s size. null until a turn reports one. The gateway keeps this value in memory rather than in the harness’s store, for at most 1,000 sessions, so it is null again after a gateway restart (or once 1,000 other sessions have reported since) until the next turn reports one.history is a message:
string
The message id. Treat it as opaque; it uses a different format from session and response ids.
string
The session the message belongs to.
string
user, assistant, or system.string
The message text.
string
The assistant’s reasoning for that turn, when the agent recorded any. Absent otherwise.
number
When the message was created, in epoch milliseconds.
Rename a session
PATCH /v1/sessions/{id} sets a session’s title, writing it straight into the harness’s own store, and returns { "id", "agent", "renamed" }. renamed is false when no session matched the id. Send the new title in the body:
string
required
The new title. Cannot be empty. Titles are unique on both harnesses: a title already used by another session returns
409 title_conflict. Hermes also caps the length; an over-long title returns 400 validation_error.405 rename_unsupported; none of the shipped harnesses does. Pass ?agent= to pick the harness.
Delete a session
DELETE /v1/sessions/{id} is a best-effort removal from the harness’s store and returns { "id": "...", "deleted": true|false }. deleted is true when a transcript was removed and false when nothing matched the id, so the call is idempotent: repeating it simply returns deleted: false rather than erroring. On Hermes the transcript is removed from its session database; on OpenClaw the session leaves its list and OpenClaw archives the transcript off its active path. Pass ?agent= to pick the harness.
One turn at a time
A session runs one response at a time. Posting new input while a turn is in flight returns409 session_busy, normally with the running response’s id in error.response_id. Reattach to it with GET /v1/responses/{id}/stream, cancel it with POST /v1/responses/{id}/cancel, or start the new input on another session. Two sessions on the same instance run independently.
To see which models a harness can run, and to set the model per turn, see Models. For the readiness probe an app polls after create or start, see Health & version.