WebSocket
Receive real-time task updates via a persistent WebSocket connection.
Connection URL
wss://socket.wiro.ai/v1
Connect to this URL after calling the Run endpoint. Use the
socketaccesstoken from the run response to register your session.
Connection Flow
- Connect: open a WebSocket connection to
wss://socket.wiro.ai/v1 - Register: send a
task_infomessage with yourtasktoken - Receive: listen for messages as the task progresses through its lifecycle
- Close: disconnect after the
task_postprocess_endevent (this is the final event with results)
Registration message format:
{
"type": "task_info",
"tasktoken": "your-socket-access-token"
}
Message Types
Message Format
Every WebSocket message is a JSON object with this base structure:
{
"type": "task_accept",
"id": "534574",
"message": null,
"result": true,
"success": null,
"terminal": false,
"exitCode": null
}
The type field indicates the status. The message field varies by type: it's null for lifecycle events, a string or object for output events, and an array for the final result.
Use the top-level id to correlate server events with the submitted task.
Lifecycle Events
These events signal task state changes. The message field is null:
// task_accept, task_preprocess_start, task_preprocess_end,
// task_assign, task_start, task_end, task_postprocess_start
{
"type": "task_assign",
"id": "534574",
"message": null,
"result": true
}
Output Events
Standard models: message is a progress object or plain string:
// Progress output (image generation, video, etc.)
{
"type": "task_output",
"id": "534574",
"message": {
"type": "progressGenerate",
"task": "Generate",
"percentage": "60",
"stepCurrent": "6",
"stepTotal": "10",
"speed": "1.2",
"speedType": "it/s",
"elapsedTime": "5s",
"remainingTime": "3s"
},
"result": true
}
// Simple string output (when no progress format is detected)
{
"type": "task_output",
"id": "534574",
"message": "Processing complete.",
"result": true
}
LLM models: message.segments is the cumulative ordered output snapshot. Replace it on every event. The final active item's text grows as chunks arrive, so render it before completion; a new item appears when the output phase changes. See LLM & Chat Streaming for full details:
{
"type": "task_output",
"id": "534574",
"message": {
"type": "progressGenerate",
"task": "Generate",
"speed": "12.4",
"speedType": "words/s",
"segments": [
{ "type": "thinking", "text": "Let me analyze this..." },
{ "type": "answer", "text": "Quantum computing uses qubits..." }
],
"finishreason": "stop",
"usage": {
"input_tokens": 18,
"input_tokens_details": { "cached_tokens": 6 },
"output_tokens": 11,
"output_tokens_details": { "reasoning_tokens": 4 },
"total_tokens": 29
},
"isThinking": false,
"elapsedTime": "3s"
},
"result": true
}
message.segments is always the full accumulated snapshot. Text entries use thinking or answer. Tool-capable models can also emit function_call entries with arguments, or custom_tool_call entries with input; both include id, call_id, name, and status.
message.finishreason and message.usage are final-turn metadata and can be absent from earlier task_output snapshots:
finishreasonisstop,tool_calls,length,content_filter, orerror. Execute a tool only when its segment status iscompletedand the finish reason istool_calls.usagecontains normalized token and server-tool counters. Input totals already include cache reads/writes; output totals already include reasoning. Do not add details tototal_tokens, and use Task Detailtotalcostfor the billed amount.
Inspect finishreason after completion so truncation and content filtering are not mistaken for a normal stop.
Error Events
task_error is an interim diagnostic event, not a failure. It arrives while the task keeps running, usually because the model wrote to stderr. The stderr text is never exposed: message is an empty string, success stays null, and there is no error field. task_error_full has the same shape. Only task_postprocess_end reports the outcome:
{
"type": "task_error",
"id": "534574",
"message": "",
"result": true,
"success": null,
"terminal": false,
"exitCode": null
}
Full Output Events
task_output_full and task_error_full are lifecycle signals. Continue listening for task_postprocess_end, or use authenticated POST /Task/Detail to retrieve the persisted task.
{
"type": "task_output_full",
"id": "534574",
"message": "",
"result": true
}
Final Result
task_postprocess_end is the event you should listen for. The message contains the outputs array:
// Standard model — file outputs with CDN URLs
{
"type": "task_postprocess_end",
"id": "534574",
"message": [{
"name": "0.png",
"contenttype": "image/png",
"size": "202472",
"url": "https://cdn1.wiro.ai/.../0.png"
}],
"result": true,
"success": true,
"terminal": true,
"exitCode": 0
}
// LLM model — structured raw content
{
"type": "task_postprocess_end",
"id": "534574",
"message": [{
"contenttype": "raw",
"content": {
"prompt": "Explain quantum computing",
"segments": [
{ "type": "answer", "text": "Quantum computing uses qubits..." }
],
"finishreason": "stop",
"usage": {
"input_tokens": 18,
"output_tokens": 11,
"total_tokens": 29
}
}
}],
"result": true,
"success": true,
"terminal": true,
"exitCode": 0
}
Realtime Events
These events are exclusive to realtime models (voice conversation, text-to-speech, and speech-to-text):
// Session is ready — start sending audio (voice conversation, speech-to-text)
{
"type": "task_stream_ready",
"id": "534574",
"result": true
}
// The model finished producing output for this turn
{
"type": "task_stream_end",
"id": "534574",
"result": true
}
// Cost update per turn
{
"type": "task_cost",
"id": "534574",
"turnCost": 0.002,
"cumulativeCost": 0.012,
"usage": { "input_tokens": 150, "output_tokens": 89 },
"result": true
}
task_cost.usage is the provider-specific realtime usage payload for that turn. It is separate from the normalized structured finite-LLM message.usage contract described above and can omit total_tokens or detail objects.
Binary Frames
For realtime models that return audio (voice conversation and text-to-speech), the WebSocket may send binary frames containing raw audio data. Check if the received message is a Blob (browser) or Buffer (Node.js) before parsing as JSON.
Ending a Session
For realtime models that maintain a persistent session, send a task_session_end message to gracefully terminate:
{
"type": "task_session_end",
"tasktoken": "your-socket-access-token"
}
After sending this, wait for the task_postprocess_end event before closing the connection. This is the final event that contains the complete results.
Agent WebSocket Events
The same WebSocket connection also supports AI Agent real-time streaming. Instead of task_info, register with agent_info and an agenttoken to receive agent response events.
For full documentation on agent events (agent_subscribed, agent_output, agent_end, and more), see Agent WebSocket.