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: proxies cut long requests, and on Dify Cloud the edge proxy ends them after about 100 seconds.
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 and New 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 and New Agent apps
messageevent repeats the complete answer; treat it as the final answer, not extra text to append. -
Close on the right terminal event:
message_endfor Chatbot, Agent, and New 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.