Send user or system events to a Session.
POST /api/v1/cloud/sessions/{session_id}/events
Sends one or more accepted events to a Session. User messages trigger asynchronous Agent processing; use the list or stream endpoints to read Agent output.
Path parameters
| Parameter | Type | Description |
|---|---|---|
session_id | string | Session ID with the sess_ prefix |
Headers
| Header | Required | Description |
|---|---|---|
Authorization | Yes | Bearer $QODER_ACCESS_TOKEN |
Content-Type | Yes | application/json |
Request body
| Field | Type | Required | Description |
|---|---|---|---|
events | array | Yes | Non-empty array of event objects |
Supported event types
| Type | Required fields | Notes |
|---|---|---|
user.message | content | content must be a non-empty array of content blocks |
user.interrupt | none | session_thread_id is optional |
user.tool_confirmation | tool_use_id, result | result must be allow or deny. deny_message is optional and only allowed when result = "deny" |
user.tool_result | tool_use_id | Return a built-in tool result from a self-hosted worker. content is optional; when present, it must be an array of content blocks. is_error is optional |
user.custom_tool_result | custom_tool_use_id | Return a client-side custom tool result. content is optional; when present, it must be an array of content blocks. is_error is optional |
user.define_outcome | description, rubric | rubric is an object: either {"type":"text","content":"..."} or {"type":"file","file_id":"file_..."}; unknown fields are rejected. max_iterations is optional and must be an integer between 1 and 20. The server assigns an outcome_id (prefix outc_) — clients must not pass it |
system.message | content | content must be a non-empty array of text content blocks. At most one system.message per request, and it must be the final event of the batch, immediately following user.message, user.tool_result, or user.custom_tool_result |
events[].content is not supported. When an event has a content field, send it as an array of content blocks. Message content blocks lists the block types and fields accepted by each event.
Example request
Send image messages
The following JSON request bodies show the three image sources. See Message content blocks for fields and limits.
Inline Base64
Replace data with raw Base64 image data, without a data:image/png;base64, prefix. Set media_type to match the image format.
HTTPS image URL
Replace the URL with an external HTTPS image URL readable by the model service.
Uploaded image reference
Use Upload file to obtain an accessible image File ID with status ready.
Example response
HTTP 200 OK
Human-in-the-loop responses
When the stream emits an agent.tool_use that requires confirmation, reply with user.tool_confirmation:
user.tool_result. Set tool_use_id to the agent.tool_use event id:
agent.custom_tool_use, execute the tool in your client and reply with user.custom_tool_result:
Errors
| HTTP | Type | Trigger |
|---|---|---|
| 400 | invalid_request_error | Empty events, unsupported event type, missing required field, invalid content blocks, or unsupported legacy field |
| 401 | authentication_error | PAT or SAT invalid or expired |
| 404 | not_found_error | Session or pending action does not exist |
| 409 | invalid_request_error | Session is currently processing a turn, or other Session state conflict (note: type is invalid_request_error, not conflict_error) |
Example: 400 invalid content
Sending user.message with a plain string instead of a content block array:
Example: 404 Session not found
Example: 409 Session is processing a turn
While a Session is running or rescheduling, a new user.message is not queued behind the current turn and returns 409. Wait for session.status_idle, or cancel the current turn first:

