Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.cyberun.cloud/llms.txt

Use this file to discover all available pages before exploring further.

GET /api/v1/r/tasks/{taskId}/events opens a Server-Sent Events stream that emits one event per status change or progress tick. The connection stays open until the task reaches a terminal state (completed, failed, cancelled), then closes. Prefer this over polling GET /r/tasks/{taskId} — lower latency, fewer requests.

Connect

Use a Bearer token (JWT, sk-, or dk-):
curl -N \
  -H "Authorization: Bearer sk-..." \
  https://core.cyberun.cloud/api/v1/r/tasks/{taskId}/events
The browser’s built-in EventSource does not support custom headers, which means it can’t carry an Authorization header. Server-side runtimes (Node fetch, Python requests, httpx), React Native, or libraries like eventsource work fine. In a browser, proxy through your own backend.

Event types

EventMeaning
statusTask status changed (e.g. pendingwaitingqueuedrunning).
progressExecution tick with progress, step_current, step_total, and the active node.
completedTask finished. Includes the output object.
failedTask failed. Includes the error string.
cancelledTask was cancelled before reaching a terminal state.
errorServer-side error fetching status. The stream may still continue.

status

event: status
data: {"task_id":"...","status":"running","timestamp":"2026-02-01T14:30:05Z"}

progress

event: progress
data: {
  "task_id":"...",
  "progress":0.35,
  "current_node":"3",
  "step_current":7,
  "step_total":20,
  "timestamp":"2026-02-01T14:30:10Z"
}
Nerfstudio tasks add stage (download, process_data, train, export, upload) and a human-readable message to the payload.
FieldTypeMeaning
progressnumber0.01.0 overall progress.
step_currentintegerSteps completed so far (when the runtime reports steps).
step_totalintegerTotal steps for this run.
current_nodestringThe runtime’s active node identifier (ComfyUI node ID for ComfyUI workflows).
stagestringNerfstudio-only. Coarse phase name.
messagestringNerfstudio-only. Free-form status text.

Terminal events

event: completed
data: {"task_id":"...","status":"completed","completed_at":"...","output":{...}}

event: failed
data: {"task_id":"...","status":"failed","error":"ComfyUI execution error: ..."}

event: cancelled
data: {"task_id":"...","status":"cancelled"}
After any of these three the server closes the connection.

error

event: error
data: {"message":"failed to fetch task status"}
A transient server-side problem reading task state. Treat it as recoverable — the task itself may still be running. If the stream also closes, fall back to polling (see below).

Example stream

A typical ComfyUI task end-to-end:
event: status
data: {"task_id":"...","status":"waiting","timestamp":"..."}

event: status
data: {"task_id":"...","status":"queued","timestamp":"..."}

event: status
data: {"task_id":"...","status":"running","timestamp":"..."}

event: progress
data: {"task_id":"...","progress":0.15,"step_current":3,"step_total":20,"current_node":"3"}

event: progress
data: {"task_id":"...","progress":0.5,"step_current":10,"step_total":20,"current_node":"3"}

event: progress
data: {"task_id":"...","progress":1.0,"step_current":20,"step_total":20,"current_node":"3"}

event: completed
data: {"task_id":"...","status":"completed","output":{...}}

Polling fallback

If your network drops SSE, or you’d rather not hold a connection open, poll GET /r/tasks/{taskId} until task_status is one of completed, failed, cancelled. Three seconds between polls is a reasonable default.
curl -s \
  -H "Authorization: Bearer sk-..." \
  https://core.cyberun.cloud/api/v1/r/tasks/{taskId}
When the task is completed, fetch the artifact links via GET /r/tasks/{taskId}/result.

Consume the stream

import json, requests

API_KEY = "sk-..."
BASE = "https://core.cyberun.cloud/api/v1/r"

with requests.get(
    f"{BASE}/tasks/{task_id}/events",
    headers={"Authorization": f"Bearer {API_KEY}"},
    stream=True,
) as stream:
    event_type = None
    for line in stream.iter_lines(decode_unicode=True):
        if not line:
            continue
        if line.startswith("event:"):
            event_type = line[6:].strip()
        elif line.startswith("data:"):
            data = json.loads(line[5:].strip())
            if event_type == "progress":
                pct = int(data["progress"] * 100)
                print(f"{pct}% ({data['step_current']}/{data['step_total']})")
            elif event_type in ("completed", "failed", "cancelled"):
                print(event_type, data)
                break