Recoup

Get started with Recoup.

API REFERENCE

Resume chat stream

On this page
GET/api/chat/{chatId}/stream

Reconnects to an in-progress chat response without submitting another message. POST /api/chat starts a new turn: an existing live run returns 409, while uncertain state or a startup reservation returns retryable 503. Returns a live Server-Sent Events stream while a response is being generated, or a 200 finish-only SSE stream when no active response exists or the run is terminal. The chat must belong to the authenticated account.

Send ?streamLifecycle=explicit-stop-v1 on both the initial POST and this reconnect GET to keep server work running when a reader disconnects. Use the authenticated Stop endpoint for cancellation; closing or aborting this reader alone does not confirm that the workflow stopped. Only exactly one streamLifecycle parameter with the exact value opts in; omitted, empty, unknown or repeated parameters retain legacy disconnect cancellation. Keep the existing startIndex cursor when reconnecting an already-read response.

Related endpoints - POST /api/chat — the interactive turn whose stream this resumes. - POST /api/chat/runs — start a headless run, then pass the returned chatId here to watch its output live. - GET /api/chat/runs/{runId} — check whether that run finished (status, not content).

Authentication

x-api-key in header

bearerAuth bearer

Request

cURL
curl --request GET \
  --url 'https://api.recoupable.dev/api/chat/YOUR_CHAT_ID/stream' \
  --header 'x-api-key: YOUR_API_KEY'

Replace the YOUR_ placeholders with your values. Required query parameters are included; optional parameters are listed below.

Try it

Fill in the fields, send the request from your browser, and read the live response. The curl below updates as you type.

Kept in this browser tab only and cleared when it closes.

cURL for this request
curl --request GET \
  --url 'https://api.recoupable.dev/api/chat/{chatId}/stream'

Run this one from the terminal with the curl above.

Parameters

Path parameters

chatIdstringrequired

UUID of the chat to resume.

Query parameters

account_idstring

Act on a chat belonging to another account. Only honoured for a key that is authorised for that account — an organization key may pass a member account's id; a personal key passing anyone else's is rejected with 403 Access denied to specified account_id. Omit it to act as the authenticated account.

startIndexinteger

Zero-based index of the first stream chunk to return, so a client that was already receiving this response resumes where it left off instead of replaying the whole turn.

Pass the number of chunks already received. Omit it to receive the response from the beginning — the right choice for a fresh reader such as a page load, or a client watching a headless POST /api/chat/runs run for the first time.

A long turn's stream can end before the run does; reconnecting with startIndex is how a client keeps rendering without duplicating or skipping chunks.

streamLifecyclestring

Send streamLifecycle=explicit-stop-v1 exactly once on the initial POST and every reconnect GET to keep server work running when that reader disconnects. Only exactly one parameter with that exact value opts in. Omitting it, an empty or unknown value, or repeating the parameter retains legacy disconnect cancellation. Use authenticated POST /api/chat/{chatId}/stop for cancellation; a local reader abort is not confirmation that server work stopped. This is a query parameter, not a request-body field.

Responses

200Server-Sent Events stream of UI message parts for the in-progress response, compatible with the Vercel AI SDK. The x-workflow-run-id response header carries the run ID for this response, and x-workflow-stream-tail-index carries the index of the last chunk known when this read was opened — a base for computing absolute positions, not a record of where the response ended. When there is nothing to resume, the stream contains one terminal finish chunk; workflow headers are absent on that path.
x-workflow-run-idresponse header

Durable workflow run ID of the resumed run.

x-workflow-stream-tail-indexresponse header

Zero-based index of the last chunk known to the stream at the moment this read was opened. Because headers are sent before the body, a read that stays open past that point will deliver chunks beyond it — so this is a base for computing absolute positions, not a record of where the response ended. A client resuming precisely should count the chunks it receives on top of this value. Omitted if the runtime cannot report it.

text/event-stream

string

400Invalid chatId UUID or malformed startIndex. When supplied, startIndex must parse to a non-negative integer; blank, nonnumeric, fractional and negative values fail validation. Authentication/ownership is checked first. Validation errors include status: error, error and missing_fields when a validation path is available.

application/json

statusstring · enum

Values: "error"

errorstringrequired
missing_fieldsarray<string | integer>

Optional validation path for the first rejected field. String entries identify object/query fields; integer entries identify array positions. An empty path can represent validation of the path value itself. Lookup or workflow errors can omit this field.

Item properties for missing_fields

string | integer

401Missing or invalid authentication.

application/json

statusstring · enum

Values: "error"

errorstringrequired
missing_fieldsarray<string | integer>

Optional validation path for the first rejected field. String entries identify object/query fields; integer entries identify array positions. An empty path can represent validation of the path value itself. Lookup or workflow errors can omit this field.

Item properties for missing_fields

string | integer

403The caller does not own the chat session.

application/json

statusstring · enum

Values: "error"

errorstringrequired
missing_fieldsarray<string | integer>

Optional validation path for the first rejected field. String entries identify object/query fields; integer entries identify array positions. An empty path can represent validation of the path value itself. Lookup or workflow errors can omit this field.

Item properties for missing_fields

string | integer

404Chat or owning session not found.

application/json

statusstring · enum

Values: "error"

errorstringrequired
missing_fieldsarray<string | integer>

Optional validation path for the first rejected field. String entries identify object/query fields; integer entries identify array positions. An empty path can represent validation of the path value itself. Lookup or workflow errors can omit this field.

Item properties for missing_fields

string | integer

500The chat or session ownership lookup failed. This is not a missing-chat result.

application/json

statusstring · enum

Values: "error"

errorstringrequired
missing_fieldsarray<string | integer>

Optional validation path for the first rejected field. String entries identify object/query fields; integer entries identify array positions. An empty path can represent validation of the path value itself. Lookup or workflow errors can omit this field.

Item properties for missing_fields

string | integer

502Workflow status lookup failed; this is not an empty or completed response.

application/json

statusstring · enum

Values: "error"

errorstringrequired
missing_fieldsarray<string | integer>

Optional validation path for the first rejected field. String entries identify object/query fields; integer entries identify array positions. An empty path can represent validation of the path value itself. Lookup or workflow errors can omit this field.

Item properties for missing_fields

string | integer

Full specification

Download the OpenAPI file for complete schemas, constraints, and examples.

Download research.json
View operation source
json
{
  "operationId": "getChatByChatIdStream",
  "summary": "Resume a chat response stream",
  "description": "Reconnects to an in-progress chat response without submitting another message. POST /api/chat starts a new turn: an existing live run returns 409, while uncertain state or a startup reservation returns retryable 503. Returns a live Server-Sent Events stream while a response is being generated, or a `200` finish-only SSE stream when no active response exists or the run is terminal. The chat must belong to the authenticated account.\n\nSend `?streamLifecycle=explicit-stop-v1` on both the initial POST and this reconnect GET to keep server work running when a reader disconnects. Use the authenticated Stop endpoint for cancellation; closing or aborting this reader alone does not confirm that the workflow stopped. Only exactly one streamLifecycle parameter with the exact value opts in; omitted, empty, unknown or repeated parameters retain legacy disconnect cancellation. Keep the existing `startIndex` cursor when reconnecting an already-read response.\n\n**Related endpoints**\n- [`POST /api/chat`](/api-reference/chat/workflow) — the interactive turn whose stream this resumes.\n- [`POST /api/chat/runs`](/api-reference/chat/runs) — start a **headless** run, then pass the returned `chatId` here to **watch its output live**.\n- [`GET /api/chat/runs/{runId}`](/api-reference/chat/runs-status) — check **whether** that run finished (status, not content).",
  "security": [
    {
      "apiKeyAuth": []
    },
    {
      "bearerAuth": []
    }
  ],
  "parameters": [
    {
      "name": "chatId",
      "in": "path",
      "required": true,
      "description": "UUID of the chat to resume.",
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    },
    {
      "name": "account_id",
      "in": "query",
      "required": false,
      "description": "Act on a chat belonging to another account. Only honoured for a key that is authorised for that account — an organization key may pass a member account's id; a personal key passing anyone else's is rejected with `403 Access denied to specified account_id`. Omit it to act as the authenticated account.",
      "schema": {
        "type": "string",
        "format": "uuid"
      }
    },
    {
      "name": "startIndex",
      "in": "query",
      "required": false,
      "description": "Zero-based index of the first stream chunk to return, so a client that was already receiving this response resumes where it left off instead of replaying the whole turn.\n\nPass the number of chunks already received. Omit it to receive the response from the beginning — the right choice for a fresh reader such as a page load, or a client watching a headless [`POST /api/chat/runs`](/api-reference/chat/runs) run for the first time.\n\nA long turn's stream can end before the run does; reconnecting with `startIndex` is how a client keeps rendering without duplicating or skipping chunks.",
      "schema": {
        "type": "integer",
        "minimum": 0
      }
    },
    {
      "name": "streamLifecycle",
      "in": "query",
      "required": false,
      "description": "Send streamLifecycle=explicit-stop-v1 exactly once on the initial POST and every reconnect GET to keep server work running when that reader disconnects. Only exactly one parameter with that exact value opts in. Omitting it, an empty or unknown value, or repeating the parameter retains legacy disconnect cancellation. Use authenticated POST /api/chat/{chatId}/stop for cancellation; a local reader abort is not confirmation that server work stopped. This is a query parameter, not a request-body field.",
      "schema": {
        "type": "string"
      },
      "example": "explicit-stop-v1"
    }
  ],
  "responses": {
    "200": {
      "description": "Server-Sent Events stream of UI message parts for the in-progress response, compatible with the Vercel AI SDK. The `x-workflow-run-id` response header carries the run ID for this response, and `x-workflow-stream-tail-index` carries the index of the last chunk known when this read was opened — a base for computing absolute positions, not a record of where the response ended. When there is nothing to resume, the stream contains one terminal finish chunk; workflow headers are absent on that path.",
      "headers": {
        "x-workflow-run-id": {
          "description": "Durable workflow run ID of the resumed run.",
          "schema": {
            "type": "string"
          }
        },
        "x-workflow-stream-tail-index": {
          "description": "Zero-based index of the last chunk known to the stream **at the moment this read was opened**. Because headers are sent before the body, a read that stays open past that point will deliver chunks beyond it — so this is a base for computing absolute positions, not a record of where the response ended. A client resuming precisely should count the chunks it receives on top of this value. Omitted if the runtime cannot report it.",
          "schema": {
            "type": "integer"
          }
        }
      },
      "content": {
        "text/event-stream": {
          "schema": {
            "type": "string",
            "description": "Server-Sent Events stream containing UI message parts"
          }
        }
      }
    },
    "400": {
      "description": "Invalid chatId UUID or malformed startIndex. When supplied, startIndex must parse to a non-negative integer; blank, nonnumeric, fractional and negative values fail validation. Authentication/ownership is checked first. Validation errors include status: error, error and missing_fields when a validation path is available.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ChatStreamErrorResponse"
          }
        }
      }
    },
    "401": {
      "description": "Missing or invalid authentication.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ChatStreamErrorResponse"
          }
        }
      }
    },
    "403": {
      "description": "The caller does not own the chat session.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ChatStreamErrorResponse"
          }
        }
      }
    },
    "404": {
      "description": "Chat or owning session not found.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ChatStreamErrorResponse"
          }
        }
      }
    },
    "500": {
      "description": "The chat or session ownership lookup failed. This is not a missing-chat result.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ChatStreamErrorResponse"
          }
        }
      }
    },
    "502": {
      "description": "Workflow status lookup failed; this is not an empty or completed response.",
      "content": {
        "application/json": {
          "schema": {
            "$ref": "#/components/schemas/ChatStreamErrorResponse"
          }
        }
      }
    }
  }
}