---
title: "Send a message to GreenBot and stream the reply"
method: POST
path: "/assistant/threads/{threadId}/messages/stream"
tags: ["Assistant"]
---

# Send a message to GreenBot and stream the reply

`POST /assistant/threads/{threadId}/messages/stream`

Validates the request before streaming (400 / 402 / 404 / 503 are plain JSON errors), then answers text/event-stream. Every event has an `id:` sequence; a `: ping` comment is sent every 15 s. Events: meta {threadId, userMessageId, messageId, title}; text_delta {messageId, delta}; tool_start {messageId, toolCallId, name, label}; tool_progress {messageId, toolCallId, message}; tool_result {messageId, toolCallId, name, status: ok|error, summary}; part {messageId, part} (a rich UI part, in order); error {messageId?, code, message}; done {messageId, finishReason: stop|max_steps|error|cancelled|waiting, creditsCharged?} (waiting: the turn started background work; the thread resumes by itself with a continuation message, trigger job). The persisted assistant message holds, in order, the text part (the deltas coalesced), the tool parts and the rich parts. A client disconnect cancels the turn; the partial reply is saved with status error. The Stop button should call the cancel route first (Cloud Run does not pass a disconnect on). One turn at a time per thread: a turn while another is streaming is a 409 TURN_IN_PROGRESS (a reply still streaming past the deadline + 60 s is closed as stale). With retryOfMessageId the thread's latest reply (failed, stopped or at the step limit) is replaced and its user message reused; content is then ignored and meta.userMessageId is the reused id; any other id is a 409 RETRY_NOT_ALLOWED. Every attachment uploadId must be an upload of the caller's organization (400 INVALID_ATTACHMENT otherwise); context is advisory and never widens access. At most 8 model steps and 240 s per turn. Billed as AI usage under feature area assistant (operation turn); a failed or cancelled turn is recorded but not charged, and a widget proposal is billed separately as a widget draft. Tools are offered by role: reads need org.view_dashboard, propose_widgets org.edit_dashboard, propose_report report.create, analyze_document and start_pcf_analysis org.write_data. Requires org.view_dashboard.

## Path parameters

- `threadId` string, required

## Request body

- AssistantTurnRequest
  - `attachments` object[]
    - `fileName` string
    - `uploadId` string, required
  - `content` string — Required unless retryOfMessageId is set.
  - `context` object — What the user is looking at. Advisory; never widens access.
    - `dashboardId` string
    - `endMonth` string — YYYY-MM
    - `netZero` object — The Net Zero page's state. Values outside the page's own are ignored.
      - `baseYear` integer
      - `tab` string — overview, targets or inventory
      - `targetSetId` string
    - `resource` string — The resource the Utility page has selected (a UtilityResource value). Other values are ignored.
    - `route` string
    - `selectedWidget` object — The selected widget's persisted WidgetConfig JSON, at most 32 KB.
    - `selectedWidgetId` string
    - `startMonth` string — YYYY-MM
    - `usage` string — The Utility page's usage, building or vehicle. Other values are ignored.
    - `widgets` object[]
      - `id` string
      - `title` string
      - `type` string
  - `retryOfMessageId` string — Replace this reply (the thread's latest, when it failed, was stopped or hit the step limit) with a new one to the same user message.

## Response `200`

SSE stream of the reply

## Other responses

- `400` — Bad Request
- `401` — Unauthorized
- `402` — Not enough AI credits, or AI usage is paused for the account
- `403` — Forbidden
- `404` — Not Found
- `409` — TURN_IN_PROGRESS (a reply is still streaming) or RETRY_NOT_ALLOWED
- `503` — The assistant is not configured (no AI gateway key)

## Changes

- **2026-10-01** `b4751fd15397` — 1 info
  - endpoint added

[Change history](https://skmtc.dev/greentally/apis/esgai-api/changes/assistant/threads/:threadId/messages/stream/post.md)

---

[API](https://skmtc.dev/greentally/apis/esgai-api.md) · [All operations](https://skmtc.dev/greentally/apis/esgai-api/llms.txt) · [OpenAPI document](https://skmtc.dev/greentally/apis/esgai-api/revisions/b4751fd15397?raw)
