Stream Events
curl --request GET \
--url https://api.example.com/api/v1/tasks/{id}/streamimport requests
url = "https://api.example.com/api/v1/tasks/{id}/stream"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/api/v1/tasks/{id}/stream', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/tasks/{id}/stream",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/tasks/{id}/stream"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/api/v1/tasks/{id}/stream")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/tasks/{id}/stream")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyTask API
Stream Events
Unified SSE stream for history replay and live task events
GET
/
api
/
v1
/
tasks
/
{id}
/
stream
Stream Events
curl --request GET \
--url https://api.example.com/api/v1/tasks/{id}/streamimport requests
url = "https://api.example.com/api/v1/tasks/{id}/stream"
response = requests.get(url)
print(response.text)const options = {method: 'GET'};
fetch('https://api.example.com/api/v1/tasks/{id}/stream', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.example.com/api/v1/tasks/{id}/stream",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"net/http"
"io"
)
func main() {
url := "https://api.example.com/api/v1/tasks/{id}/stream"
req, _ := http.NewRequest("GET", url, nil)
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.get("https://api.example.com/api/v1/tasks/{id}/stream")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.example.com/api/v1/tasks/{id}/stream")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Get.new(url)
response = http.request(request)
puts response.read_bodyStream Task Events
Connect to the unified SSE stream to receive the complete conversation history followed by live execution events. This is the recommended way to build a real-time chat UI.Request
GET /api/v1/tasks/{id}/stream
Authorization: Bearer {api_key}
Path Parameters
| Parameter | Type | Description |
|---|---|---|
id | string | The unique task identifier |
Stream Behavior
The stream delivers events in three phases:- History replay - Emits
history_messageevents for each saved conversation message - History complete - Emits
history_donewith{ messageCount, isStreaming } - Live events (if task is running) - Catch-up state followed by real-time
content,thought,tool_call,tool_result,subagent_start,subagent_thought,subagent_tool,subagent_end,error, anddoneevents
history_done.
Reconnection
You can disconnect and reconnect at any time. On reconnect, the stream replays the full history and catches up to the current state. The task continues executing in the background regardless of stream connections - disconnecting does not cancel the task.Heartbeat
The server sends:heartbeat comments every 15 seconds to keep the connection alive. These can be safely ignored by your SSE parser.
Stream Output Example
event: history_message
data: {"id":"msg-1","role":"user","content":"Analyze this CSV file","createdAt":"2026-01-26T15:50:54.870Z","attachedFiles":[{"name":"data.csv","path":"uploads/data.csv"}]}
event: history_message
data: {"id":"msg-2","role":"assistant","content":"I analyzed the CSV file...","createdAt":"2026-01-26T15:50:59.998Z","thoughts":[{"subject":"Analyzing","description":"Reading CSV structure"}],"toolCalls":[{"callId":"tc-1","toolName":"read_file","status":"success"}]}
event: history_done
data: {"messageCount":2,"isStreaming":true}
event: content
data: {"text":"Now let me provide additional analysis...","isPartial":true}
event: tool_call
data: {"callId":"call_456","toolName":"write_file","status":"executing","args":{"path":"output.csv"}}
event: tool_result
data: {"callId":"call_456","status":"success","output":"File written successfully"}
event: subagent_start
data: {"agentName":"code-writer","displayName":"Code Writer","description":"Writes and edits code files","objective":"Create summary chart"}
event: subagent_thought
data: {"agentName":"code-writer","text":"I'll generate a chart from the analyzed data"}
event: subagent_tool
data: {"agentName":"code-writer","status":"end","toolName":"write_file","output":"Chart saved"}
event: subagent_end
data: {"agentName":"code-writer","terminateReason":"GOAL","result":"Created summary chart"}
event: content
data: {"text":"I've created the output file.","isPartial":false}
event: done
data: {"finalResponse":"I've created the output file with the analysis results."}
Event Types
history_message
A replayed conversation message from history.
{
"id": "msg-1",
"role": "user",
"content": "Analyze this CSV file",
"createdAt": "2026-01-26T15:50:54.870Z",
"attachedFiles": [
{ "name": "data.csv", "path": "uploads/data.csv" }
]
}
| Field | Type | Description |
|---|---|---|
id | string | Message identifier |
role | string | user or assistant |
content | string | Message text |
createdAt | string | ISO timestamp |
attachedFiles | array | Uploaded files (user messages only) |
thoughts | array | Agent reasoning (assistant messages only) |
toolCalls | array | Tool executions (assistant messages only) |
history_done
Signals that history replay is complete.
{
"messageCount": 2,
"isStreaming": true
}
| Field | Type | Description |
|---|---|---|
messageCount | number | Number of history messages sent |
isStreaming | boolean | Whether the task is currently running (live events follow if true) |
Live Events
Afterhistory_done, if isStreaming is true, the stream delivers live events including content, thought, tool_call, tool_result, subagent events (subagent_start, subagent_thought, subagent_tool, subagent_end), error, and done. See Streaming Events for the complete event format reference.
Examples
# Stream events (Ctrl+C to disconnect - task keeps running)
curl -N https://api.sigmic.ai/api/v1/tasks/YOUR_TASK_ID/stream \
-H "Authorization: Bearer sigmic_your_key_here"
const taskId = 'c37c1d78-4d23-4e53-949a-ddd775f25e01';
const response = await fetch(
`https://api.sigmic.ai/api/v1/tasks/${taskId}/stream`,
{ headers: { 'Authorization': 'Bearer sigmic_your_key_here' } }
);
const reader = response.body.getReader();
const decoder = new TextDecoder();
let buffer = '';
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
const events = buffer.split('\n\n');
buffer = events.pop() || '';
for (const event of events) {
if (!event.trim() || event.startsWith(':')) continue;
const lines = event.split('\n');
const eventType = lines[0]?.replace('event: ', '');
const dataLine = lines[1]?.replace('data: ', '');
if (!dataLine) continue;
const data = JSON.parse(dataLine);
switch (eventType) {
case 'history_message':
console.log(`[${data.role}] ${data.content}`);
break;
case 'history_done':
console.log(`History loaded: ${data.messageCount} messages`);
if (!data.isStreaming) console.log('Task is not running');
break;
case 'content':
process.stdout.write(data.text);
break;
case 'done':
console.log('\nDone:', data.finalResponse);
break;
}
}
}
import json
import requests
task_id = 'c37c1d78-4d23-4e53-949a-ddd775f25e01'
response = requests.get(
f'https://api.sigmic.ai/api/v1/tasks/{task_id}/stream',
headers={'Authorization': 'Bearer sigmic_your_key_here'},
stream=True
)
event_type = None
for line in response.iter_lines():
if not line:
continue
line = line.decode('utf-8')
if line.startswith('event:'):
event_type = line.replace('event: ', '')
elif line.startswith('data:'):
data = json.loads(line.replace('data: ', ''))
if event_type == 'history_message':
print(f"[{data['role']}] {data['content'][:80]}...")
elif event_type == 'history_done':
print(f"History: {data['messageCount']} messages, streaming: {data['isStreaming']}")
elif event_type == 'content':
print(data.get('text', ''), end='', flush=True)
elif event_type == 'done':
print(f"\nDone: {data.get('finalResponse', '')}")
Use Cases
Building a Chat UI
Use the stream endpoint to hydrate your chat interface and receive live updates:async function connectToTask(taskId) {
const messages = [];
const response = await fetch(`${API_BASE}/api/v1/tasks/${taskId}/stream`, {
headers: { 'Authorization': `Bearer ${apiKey}` }
});
// Parse SSE events...
// history_message events → populate chat history
// history_done → render the chat UI
// content events → update current assistant message in real-time
// done event → finalize the message
}
Reconnecting After Disconnect
// User switches tabs, connection drops
// When they come back, just reconnect:
async function reconnect(taskId) {
// Same endpoint - replays full history + catches up
return connectToTask(taskId);
}
The stream endpoint is the recommended way to consume task events. It replaces the previous pattern of reading SSE from POST endpoints. Use
GET /tasks/:id/history as a REST alternative when SSE is not practical.Errors
| Code | Description |
|---|---|
AUTH_REQUIRED | No authentication provided |
INVALID_API_KEY | Invalid or expired API key |
NOT_FOUND | Task with the specified ID was not found |