API REFERENCE
Resume chat stream
On this page
/api/chat/{chatId}/streamReconnects 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 --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 --request GET \
--url 'https://api.recoupable.dev/api/chat/{chatId}/stream'Run this one from the terminal with the curl above.
Parameters
Path parameters
chatIdstringrequiredUUID of the chat to resume.
Query parameters
account_idstringAct 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.
startIndexintegerZero-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.
streamLifecyclestringSend 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 headerDurable workflow run ID of the resumed run.
x-workflow-stream-tail-indexresponse headerZero-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 · enumValues: "error"
errorstringrequiredmissing_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 · enumValues: "error"
errorstringrequiredmissing_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 · enumValues: "error"
errorstringrequiredmissing_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 · enumValues: "error"
errorstringrequiredmissing_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 · enumValues: "error"
errorstringrequiredmissing_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 · enumValues: "error"
errorstringrequiredmissing_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.jsonView operation source
{
"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"
}
}
}
}
}
}