Skip to main content
An account API key can hold a full conversation with an agent: start a chat, read the agent’s replies, and send follow-ups. This is the surface a partner backend integrates against most often, so the whole flow is spelled out here — the underlying endpoints are also documented individually under Sessions in the sidebar.
This is a different flow from API triggers. A trigger API key runs one agent on demand and is scoped to a single trigger. An account key holds an open-ended conversation with any agent installed in the account’s workspaces, scoped by sessions:write.

Start a chat

Requires sessions:write on a workspace the key’s account owns. The scope is deliberately sessions, not workspaces, so workspace scope alone can’t quietly grant conversations.

Request body

Example

Response

Returns 201 with the session. The key is recorded as the session’s initiator, serialized as type: "api_key":

Read the conversation

Requires workspaces:read, plus agents:read when the session ran an agent — see Fetch session events. Events default to newest-first (sort_by=-id) with a limit of 20, so a naive read returns the tail of the conversation in reverse. For polling, pass from_id: it’s an exclusive cursor (id > from_id), so each poll returns only what happened since the last one. Event ids are UUIDv7 and therefore time-ordered. The agent’s reply arrives as a runtime_done event whose content.text carries the message. One turn can emit several runtime_done events, because subtasks and tool runs complete with empty content ({}) before the top-level turn does. Read the reply from the runtime_done that carries content.text, not simply the first one to appear. Events persist when a turn completes, not while the model is streaming — a poll during generation returns nothing new until the turn finishes. If you would rather not poll, the same events are available over a WebSocket — see Stream the conversation.

Example

Response

Poll again with from_id=9d2f4a1b-... to only see events after this one.

Stream the conversation

Instead of polling, connect to the session events WebSocket and receive each event as it is written.
Requires the same scopes as the polling read: workspaces:read, plus agents:read when the session ran an agent. Privacy is evaluated identically too — a session the key cannot see closes the connection with 404 rather than reporting an authorization error. Authenticate with the same API key, sent as an Authorization: Basic header on the connection request.
A socket opened without from_id carries only events created after the connection opens. It does not replay anything that already happened, so a client that connects after starting a session can silently miss the agent’s reply. Pass from_id with the last event id you processed — the socket then replays the backlog after that cursor before switching to live delivery. That is also how you resume after a reconnect.
The Authorization header is the only way to authenticate this connection. A browser’s built-in WebSocket cannot set request headers, so connect from a server-side or native client instead.

Query parameters

Example

Each message is a single event, in the same shape as one entry of the items array returned by GET /sessions/{session_id}/events.
This endpoint is not listed in the sidebar or in openapi.yaml: OpenAPI cannot describe WebSockets. It is part of the public API all the same.

Send a follow-up

Requires sessions:write — see Post a follow-up event to a session. The message is authored by the key itself (author.type: "api_key"); a key may never author as anyone else. The agent_id field is accepted but ignored for a key — it only retargets for user viewers — so a key cannot switch which agent answers mid-conversation. Start a new session instead.

Example

Read the agent’s reply the same way as above — poll GET /sessions/{session_id}/events?from_id=... until a new runtime_done event appears.

Containment

A key converses only in the chat sessions it initiated. Posting into any other session — another key’s chat, a person’s chat, a trigger session — is 404, not 403: a key cannot inject messages into a human’s conversation, and cannot even learn that the other session exists. Reading is broader than writing: with workspaces:read, a key can read every session in its account’s unrestricted workspaces, it just cannot speak in them.