Sign in

Chat Conversations API Reference

REST and WebSocket endpoints for the Chat service: synchronous converse, streaming conversations, Cosmos Assistant and test-session streams, WhatsApp webhook, session events, and file uploads.

chat
chatconversationswebsocketstreamingwhatsappapi

Updated 2026-11-03

Verified 2026-11-03

Chat sits between clients and the ADK agent runtime. It authenticates the caller, checks the chat.initiate permission, and relays conversations to ADK over REST or WebSocket. For architecture and configuration, see Chat Service.

Local base URL: http://localhost:8108. Base URLs, headers, and error shapes are described in API Conventions.

Authentication

Every HTTP endpoint except GET /health/ requires:

HeaderValue
AuthorizationBearer YOUR_TOKEN
X-Org-IdYOUR_ORG_ID

Missing headers or an invalid token return 401 with {"error": "unauthorized", "message": ...}. A caller without chat.initiate in the organization gets 403; if the authorization service is unreachable, Chat returns 503. Service tokens acting for a user send X-On-Behalf-Of-User-Id.

The WebSocket endpoint takes the token at connection time, either in the Authorization header or, for browsers, as a subprotocol: Sec-WebSocket-Protocol: cosmos.v1, cosmos-auth.YOUR_TOKEN. The organization is sent in the start message. The end-user ID is always taken from the token (or the on-behalf-of header), not from the request body.

Endpoints

MethodPathPurpose
GET/health/Health check, returns {"status": "ok"}
POST/api/v1/converseSend one message and wait for the agent's reply
WS/api/v1/converse_streamStreaming conversation
POST/api/v1/converse/whatsappWhatsApp webhook
POST/api/v1/trig-add-eventInject an event into an active session
POST/api/v1/trig-end-sessionEnd a session
POST/api/v1/upload-fileUpload an image or PDF for a conversation

Converse (REST)

POST /api/v1/converse
FieldTypeRequiredDescription
agent_id or app_idstringOne of themTarget agent or app
agent_version, app_versionstringNoDefaults to the version matching type
typestringYesdeployed or draft
querystringYesUser message
user_idstringYesEnd-user identifier
session_idstringNoContinue an existing session
user_name, user_datastring, objectNoEnd-user display name and metadata
sequenceNumberintegerNoMessage sequence number
provider_id, model_idstringNoModel override
project_id, project_namestringNoAttribute the conversation to a project
org_id, eventstringNoOptional overrides
json
{
  "agent_id": "AGENT_UUID",
  "type": "deployed",
  "user_id": "user-123",
  "query": "Hello, how can you help me?",
  "project_id": "PROJECT_UUID"
}

The response is the ADK converse result, including session_id. Errors return {"status": <code>, "error": "..."}; sending neither agent_id nor app_id returns 400.

Streaming Conversations (WebSocket)

WS /api/v1/converse_stream
  1. Open the socket with the token (header or subprotocol).
  2. Send a start message as the first frame. Any other first frame closes the socket with 1003.
  3. Receive streamed response frames.
  4. Send query frames for follow-up messages.

The start message decides which stream you get:

start contentsStream
DefaultAgent or app conversation relayed to ADK v1
"channel": "cosmos_assistant"Cosmos Assistant, relayed to ADK v2 and mapped to the same response frames
"test_protocol": "adk.v2.test.v1"Agent test session with structured ADK v2 events (disabled unless CHAT_V2_TEST_RELAY_ENABLED=true)

Agent or app stream

json
{
  "event": "start",
  "agent_id": "AGENT_UUID",
  "type": "deployed",
  "org_id": "YOUR_ORG_ID",
  "project_id": "PROJECT_UUID",
  "query": "What's the weather in London?"
}

start fields: agent_id or app_id, optional agent_version / app_version, type (default deployed), org_id (required), query, user_name, user_data, and optional project_id and project_name. A browser cannot set an X-Project-Id handshake header, so project scope travels in the body.

Server frames:

json
{"response": {"content": "The weather in London is", "is_final": false}}
json
{"response": {"content": "The weather in London is 18°C and partly cloudy.", "is_final": true, "session_id": "SESSION_ID"}}

Follow-up:

json
{"event": "query", "query": "What about tomorrow?"}

Cosmos Assistant stream

Send "channel": "cosmos_assistant" with org_id and query. Optional fields: images, user_data, provider_id, model_id, additional_instructions, language (default English), and project_id. To resume, send "resume_session": true with session_id. If ADK no longer has the session, the final frame carries "error_code": "SESSION_NOT_FOUND", "fatal": true; start a new session instead of retrying.

Cost notices

When a session, weekly, or monthly cost limit is near or reached, Chat sends:

json
{"response": {"event": "cost_notice", "content": "...", "severity": "warning", "is_final": true}}

severity is warning or error. When ADK stops a session for a cost limit it closes with 4000, and Chat passes that code through; treat it as final rather than reconnecting.

Agent test sessions

When enabled, a start frame with "test_protocol": "adk.v2.test.v1" opens a two-way ADK v2 test session. It carries org_id, agent_id or app_id, optional project_id, a non-blank query, and a test_session object (schema_version, name, tool_refs, graph_ids). Unknown fields are rejected. The client receives structured events (tool_start, tool_complete, turn_complete, error, approval_required) with tool arguments and reasoning redacted, and can send query, tool_result, approval_decision, stop, or pong. Malformed frames get {"event": "error", "code": "...", "message": "...", "fatal": false}.

Close codes

CodeMeaning
1000Normal close (agent finished or disconnected)
1003First frame was not valid JSON or not a start message
1008Test protocol rejected (unsupported version or relay disabled)
1011Agent connection failed or authorization service unavailable
4000Cost limit reached
4401Missing or invalid token, or user identity could not be resolved
4403Permission denied or missing organization

Before closing with 4401 or 4403, Chat may send {"code": 4403, "reason": "..."}.

WhatsApp Webhook

POST /api/v1/converse/whatsapp?org_id=YOUR_ORG_ID&app_id=APP_UUID&type=deployed
Content-Type: application/x-www-form-urlencoded

Requires Authorization and X-Org-Id. org_id must match X-Org-Id, and the caller needs chat.initiate on the app. Query parameters: org_id and app_id (required), app_version, and type (default deployed).

Form fields: From and Body (required), ProfileName, MediaUrl0, MediaContentType0. Supported media types are image/png, image/jpeg, and application/pdf.

Trigger Add Event

Inject an external event (for example a payment confirmation) into an active ADK session.

POST /api/v1/trig-add-event
json
{
  "entity_name": "app-APP_UUID",
  "user_id": "user-123",
  "org_id": "YOUR_ORG_ID",
  "session_id": "SESSION_ID",
  "content": "Payment confirmed for order #12345",
  "state_delta": {"payment_status": "confirmed"}
}

entity_name is app-<id> or agent-<id>. state_delta is required (send {} for none). user_id must match the token's user unless the caller is a superuser. If the user has an open stream, Chat also pushes the agent's reply to it; the response reports this in websocket_status (sent, failed, or no_connection).

Trigger End Session

POST /api/v1/trig-end-session
json
{"entity_name": "agent-AGENT_UUID", "user_id": "user-123", "session_id": "SESSION_ID"}

session_id is optional but recommended; without it Chat ends the session it last cached for that user and entity. user_id must match the token's user unless the caller is a superuser. Returns {"status": "success", "message": "session ended successfully", "data": null}, or "session already ended" when ADK no longer has the session.

Upload File

POST /api/v1/upload-file
Content-Type: multipart/form-data
FieldRequiredDescription
fileYesimage/png, image/jpeg, image/jpg, or application/pdf
userIdYesUser ID for attribution

Returns {"status": "success", "message": "File uploaded successfully", "data": "<signed URL>"}. Other file types return 400.

Testing

bash
curl -s -X POST http://localhost:8108/api/v1/converse \
  -H "Authorization: Bearer YOUR_TOKEN" \
  -H "X-Org-Id: YOUR_ORG_ID" \
  -H "Content-Type: application/json" \
  -d '{"agent_id": "AGENT_UUID", "type": "deployed", "user_id": "test-user", "query": "Hello"}'

# Streaming, using websocat
echo '{"event":"start","agent_id":"AGENT_UUID","type":"deployed","org_id":"YOUR_ORG_ID","query":"Hello"}' | \
  websocat -H "Authorization: Bearer YOUR_TOKEN" ws://localhost:8108/api/v1/converse_stream