Invoke an agent with real-time streaming via Server-Sent Events (SSE). Events fire as the agent works — you see tool calls, reasoning steps, and result chunks as they happen. Best for interactive UIs and chat applications.
Path Parameters
Request Body
The request body is identical to Invoke Agent (Sync) . Only input.text is required.
The message or prompt to send to the agent.
URLs of files for the agent to process. For large files, set disable_attachment_injection: true.
Thread ID for multi-turn conversations. Pass the id from a previous task to continue the conversation.
disable_attachment_injection
default or harder. Controls reasoning depth.
Additional instructions appended to the system prompt for this invocation only.
Natural-language description of desired output
Query Parameters
Agent version to invoke. Defaults to latest deployed. Use "draft" to test undeployed changes.
Returns Content-Type: text/event-stream. Each event is a JSON object prefixed with data: , separated by \n\n.
Event Types
Events are emitted in this order during a typical invocation:
Fired immediately. Contains the full task object with status: "pending".
Fired when task status changes (e.g., to executing). Contains the updated task object.
Agent’s internal reasoning step. Contains the thought process as a string.
Agent’s analysis step before tool selection.
Agent is calling a tool. Contains tool name, parameters, and reasoning.
Tool returned a result. Contains the output from the tool.
A piece of the agent’s final response. Accumulate these to build the full result. { "type" : "chunk" , "task_id" : "..." , "data" : "partial response text..." }
Task is done. Contains the complete task object with status, result, finished_at.
A sub-agent was triggered (multi-agent workflows).
Deep planning step was updated (when deep_planning is enabled on the agent).
MCP connector requires authentication. Contains an auth URL the user must visit.
Basic Example
curl -s --no-buffer -X POST "https://api.xpander.ai/v1/agents/<agent-id>/invoke/stream" \
-H "Content-Type: application/json" \
-H "x-api-key: <your-api-key>" \
-d '{"input": {"text": "Say hello in 5 words"}}'
Use --no-buffer (or -N) for real-time output.
Real Event Stream
Here’s what the actual SSE output looks like (from a live invocation):
data: {"type":"task_created","task_id":"c35476a3-...","time":"2026-02-07T10:14:48.466Z","data":{"id":"c35476a3-...","status":"pending","agent_id":"<agent-id>",...}}
data: {"type":"task_updated","task_id":"c35476a3-...","time":"2026-02-07T10:14:49.100Z","data":{"id":"c35476a3-...","status":"executing",...}}
data: {"type":"chunk","task_id":"c35476a3-...","time":"2026-02-07T10:14:50.200Z","data":"Hello there, nice to"}
data: {"type":"chunk","task_id":"c35476a3-...","time":"2026-02-07T10:14:50.300Z","data":" meet you!"}
data: {"type":"task_finished","task_id":"c35476a3-...","time":"2026-02-07T10:14:51.000Z","data":{"id":"c35476a3-...","status":"completed","result":"Hello there, nice to meet you!",...}}
Consuming the Stream (Node.js)
const response = await fetch (
'https://api.xpander.ai/v1/agents/<agent-id>/invoke/stream' ,
{
method: 'POST' ,
headers: {
'x-api-key' : '<your-api-key>' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
input: { text: 'Your task here' }
})
}
);
const reader = response . body . getReader ();
const decoder = new TextDecoder ();
while ( true ) {
const { done , value } = await reader . read ();
if ( done ) break ;
const lines = decoder . decode ( value ). split ( ' \n ' );
for ( const line of lines ) {
if (! line . startsWith ( 'data: ' )) continue ;
const event = JSON . parse ( line . slice ( 6 ));
switch ( event . type ) {
case 'chunk' :
// Stream text to UI as it arrives
process . stdout . write ( event . data );
break ;
case 'tool_call_request' :
console . log ( ` \n [Tool: ${ event . data ?. tool_name } ]` );
break ;
case 'task_finished' :
console . log ( ' \n\n Done:' , event . data . result );
break ;
}
}
}
Consuming the Stream (Python)
import requests
import json
response = requests.post(
'https://api.xpander.ai/v1/agents/<agent-id>/invoke/stream' ,
json ={ 'input' : { 'text' : 'Your task here' }},
headers ={
'x-api-key' : '<your-api-key>' ,
'Content-Type' : 'application/json'
},
stream = True
)
for line in response.iter_lines():
if not line:
continue
line = line.decode( 'utf-8' )
if not line.startswith( 'data: ' ):
continue
event = json.loads(line[ 6 :])
if event[ 'type' ] == 'chunk' :
print (event[ 'data' ], end = '' , flush = True )
elif event[ 'type' ] == 'tool_call_request' :
print ( f " \n [Calling tool: { event[ 'data' ].get( 'tool_name' , 'unknown' ) } ]" )
elif event[ 'type' ] == 'task_finished' :
print ( f " \n\n Done. Status: { event[ 'data' ][ 'status' ] } " )
Notes
Use curl --no-buffer or curl -N for real-time terminal output
The stream ends after the task_finished event — close the connection at that point
chunk events contain raw text fragments; concatenate them for the full response
tool_call_request and tool_call_result events let you show tool usage in your UI
think and analyze events show the agent’s reasoning (useful for debugging and transparency)
For multi-turn conversations, wait for task_finished before sending the next message with the same id
See Also
API Key for authentication
input
AgentExecutionInput · object
required
The input to send to the agent
Thread ID for multi-turn conversations. Pass the id from a previous task to continue the conversation.
Natural-language description of the desired output
Controls the agent's reasoning depth. "default" for standard reasoning, "harder" for deeper analysis.
Available options:
default,
harder
disable_attachment_injection
When true, files in input.files are not injected into the LLM context window
Additional instructions appended to the agent's system prompt for this invocation only. Use this to adjust behavior per-request without changing the agent's configuration.