Generation endpoints return either one complete response or a Server-Sent Events (SSE) stream, chosen per request with 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 may end the connection if the upstream 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.
Legacy Agent and Agent apps stream only.
Parse the Stream#
Every event except ping arrives as a data: 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.
Chatflow and Workflow app streams open with a ping as the very first frame, and more arrive roughly every 10 seconds during the run. Treat the first data: event (workflow_started), not the first frame, as the signal that the run was accepted.
On the wire, a stream looks like this:
When testing with curl, pass -N (--no-buffer) so events print as they arrive instead of after the run completes.
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 Legacy Agent and Agent apps
For Agent apps, a single closing
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, Legacy Agent, 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 stays 200. 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.
Handle both, and treat either as terminal for that request.
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.
Both arrive on the stream itself: every event except 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-second ping interval so idle stretches between events don’t kill the connection. The pings themselves need no handling beyond being skipped.