Task Progress Query

Task Progress Query lets clients subscribe to task status changes through WebSocket, reducing polling requests and delivering progress updates faster. The current endpoint is /ws/v1/progress. After a subscription succeeds, the server immediately sends the latest task snapshot and then streams subsequent progress events.

Request

Basic Information

ItemValue
ProtocolWebSocket
Path/ws/v1/progress
AuthenticationAPI Key

Handshake Authentication

Prefer passing the API Key through the Authorization header:

Authorization: YOUR_API_KEY

When custom headers are unavailable in a browser environment, use the api_key query parameter fallback:

wss://api.ai-mcn.tv:10000/ws/v1/progress?api_key=YOUR_API_KEY

Warning: query parameters may be recorded by proxies or gateways. Use the Authorization header in production whenever possible.

Subscribe to Tasks

{
  "type": "subscribe",
  "task_ids": ["TASK_ID"]
}

The server validates each task independently, including existence and ownership by the current API Key user. Valid tasks are added to the subscription set and receive an immediate progress snapshot.

Unsubscribe

{
  "type": "unsubscribe",
  "task_ids": ["TASK_ID"]
}

When the connection closes, the server automatically removes all subscriptions for that connection.

Connection Lifecycle

When every task in the current subscription set reaches completed, failed, or cancelled, the server sends the final terminal progress_update and then proactively closes the WebSocket. Treat this close as a normal completion signal; create a new WebSocket connection before subscribing to new tasks.

If the same connection still has any task in queued or processing, the connection stays open and continues streaming progress for that task.

Progress Message

{
  "type": "progress_update",
  "data": {
    "task_id": "TASK_ID",
    "status": "processing",
    "progress_percent": 42,
    "progress_node": "render",
    "extra": {},
    "timestamp": 1790000000000
  }
}
FieldTypeDescription
typestringAlways progress_update
data.task_idstringTask ID
data.statusstringTask status, matching the task query API
data.progress_percentnumberOptional progress percentage
data.progress_nodestringOptional current processing node
data.extraobjectOptional business-specific extension data
data.timestampnumberServer event time in Unix milliseconds

Progress Nodes by Modality

Different task_type values push slightly different progress_node and extra fields. Treat the following as guidance rather than a hard contract.

Status messages (shared across all task_types)

Every task pushes at least 2 status transition messages:

  • status: "processing" (task begins, progress_percent: 0)
  • Terminal: status: "completed" (progress_percent: 100) / failed / cancelled

Image / Text task_types

Image processing usually < 5 seconds, text < 1 second. These task types do not push intermediate progress, so clients receive only the 2 status transition messages.

Audio task_types (asr / audio_silence_remove / audio_noise_reduce / audio_speaker_split)

Every audio task pushes at least 3 progress nodes:

  • progress_node: "decoded", progress_percent ≈ 10 (input file decoded)
  • progress_node: "processing", progress_percent ≈ 50 (core processing past midway)
  • progress_node: "encoding", progress_percent ≈ 95 (output encoded)

Video processing task_types

Including video_blackborder_remove / video_canvas_adapt / video_interpolate / video_upscale / video_purify / video_stabilizer / video_vaporwave / video_ai_subtitle.

These task types push the following 3 progress nodes:

  • progress_node: "decoded", progress_percent ≈ 10
  • progress_node: "processing", progress_percent ≈ 50
  • progress_node: "encoding", progress_percent ≈ 95

⚠️ The extra for these task types does NOT include current_frame / total_frames. Fields in extra are optional; clients should handle them defensively (treat missing fields as None / absent).

Video splitting task_types (video_segment / video_ai_segment / video_motion_cut)

Splitting tasks (one input video, multiple output segments) include segment_count in extra at the encoding node so clients can sense the split scale:

{
  "type": "progress_update",
  "data": {
    "task_id": "TASK_ID",
    "status": "processing",
    "progress_percent": 95,
    "progress_node": "encoding",
    "extra": { "segment_count": 12 },
    "timestamp": 1790000000000
  }
}

Time-based progress estimate node (elapsed, shared by all task_types)

For long-running tasks, the server continuously pushes a progress estimate based on elapsed time so the progress bar advances smoothly:

  • progress_node: "elapsed"
  • progress_percent is an estimate based on elapsed time

This estimate shares a monotonic increase guarantee with precise progress (progress only goes up): once precise progress arrives, any estimate lower than the precise value is skipped. Clients need no special handling; treat it as a regular progress_update.

Some task types may not include this estimate node; in that case progress comes only from processing-stage nodes and status transitions.

Error Message

{
  "type": "error",
  "code": "TASK_NOT_FOUND",
  "message": "task not found",
  "task_id": "TASK_ID"
}
Error CodeDescriptionResolution
AUTH_REQUIREDMissing or invalid API KeyCheck the Authorization header or api_key query parameter
TASK_NOT_FOUNDTask does not existConfirm that task_id is correct
TASK_FORBIDDENTask does not belong to the current userSubscribe with the API Key that created the task
INVALID_MESSAGEInvalid JSON, missing fields, or unknown typeCheck the message format
RATE_LIMITEDPer-user connection limit exceededClose extra connections and retry

Limits

Each user can open up to 5 WebSocket connections in the initial release. Connections beyond the limit receive RATE_LIMITED and are closed.

Node Example

import WebSocket from 'ws'

const ws = new WebSocket('wss://api.ai-mcn.tv:10000/ws/v1/progress', {
  headers: {
    Authorization: process.env.GITRUCK_API_KEY,
  },
})

ws.on('open', () => {
  ws.send(JSON.stringify({
    type: 'subscribe',
    task_ids: ['TASK_ID'],
  }))
})

ws.on('message', (raw) => {
  const message = JSON.parse(raw.toString())
  console.log(message)
})

ws.on('close', () => {
  console.log('progress stream closed; reconnect before subscribing to new tasks')
})

Python Example

import json
import os
import websocket

ws = websocket.create_connection(
    "wss://api.ai-mcn.tv:10000/ws/v1/progress",
    header=[f"Authorization: {os.environ['GITRUCK_API_KEY']}"],
)

ws.send(json.dumps({
    "type": "subscribe",
    "task_ids": ["TASK_ID"],
}))

try:
    while True:
        print(json.loads(ws.recv()))
except websocket.WebSocketConnectionClosedException:
    print("progress stream closed; reconnect before subscribing to new tasks")
finally:
    ws.close()