response_mode. Streaming is the usual choice: the reply renders as it generates, and long runs aren’t cut off mid-flight.
Choose a Response Mode
blocking returns a single JSON body once generation finishes. It’s the simpler integration for short, non-interactive calls, but long generations risk interruption: a reverse proxy or load balancer in front of your deployment may cut the connection if the response doesn’t arrive within its timeout.
streaming delivers the reply as SSE events. Use it for anything user-facing, for long runs, and for every flow that pauses for Human Input.
Agent apps stream only.
Parse the Stream
Each event arrives as adata: line holding one JSON object, terminated by a blank line.
Read the event field to decide what to do, and skip anything that isn’t a data: line: the keep-alive ping arrives as a bare event: ping line with no data: payload, every 10 seconds.
Dispatch by Event Type
Which events arrive depends on the app type. See the event tables on Send Chat Message, Run Workflow, and Send Completion Message for the contract. The typical minimum:-
Concatenate reply chunks in order:
messageevents for Chatbot and Chatflow appsagent_messageevents for Agent apps
-
Close on the right terminal event:
message_endfor Chatbot and Agent appsmessage_endthenworkflow_finished(both arrive, in that order) for Chatflow appsworkflow_finishedfor Workflow apps
-
Surface
error.
Handle Errors Mid-Stream
A failure after the stream opens doesn’t change the HTTP status: the connection stays200. How the failure surfaces depends on where it happens:
- A workflow node failure arrives as
node_finishedandworkflow_finishedevents withstatus: "failed". - Other failures end the stream with an
errorevent carryingstatus,code, andmessage.
Reconnect and Resume
Two identifiers matter, and they’re easy to mix up:task_idcontrols the in-flight generation and is what the stop endpoints (Stop Chat Message Generation / Stop Workflow Task) take.workflow_run_idnames the persistent run record.
error carries task_id, and workflow and node events carry workflow_run_id. Save workflow_run_id as soon as it arrives: if the connection drops mid-run, it’s the only handle you have for reconnecting or checking the outcome.
For workflow-backed runs (Workflow and Chatflow apps), a dropped connection isn’t fatal. Reopen the stream with Stream Workflow Events, passing the workflow_run_id and the same user that started the run. A mismatch returns 404.
Add include_state_snapshot=true to first replay the status of nodes that already ran, and continue_on_pause=true to keep one stream open across multiple Human Input pauses.
After reconnecting to a still-running workflow, confirm completion with Get Workflow Run Detail rather than relying on the reconnected stream’s final event alone.
Other replies have no resume endpoint: if the connection drops mid-reply, issue a new request. For chat-style apps, List Conversation Messages shows what was saved to the conversation.
Keep the Connection Alive
Set your client’s read timeout comfortably above the 10-secondping interval so idle stretches between events don’t kill the connection. The pings themselves need no handling beyond being skipped.