hermes-agent/skills/creative/comfyui/references/rest-api.md
SHL0MS a7780fe05f fix(skills/comfyui): bug fixes, cloud parity, expanded coverage, examples, tests
The audit of v4.1 surfaced ~70 issues across the five scripts and three
reference docs — most user-visible (silent file overwrites, status-error
misclassified as success, X-API-Key leaked to S3 on /api/view redirect,
Cloud endpoints that 404 because they were renamed). v5.0.0 fixes those
and fills the gaps that previously forced users to write their own glue
(WebSocket monitoring, batch/sweep, img2img upload helper, dep auto-fix,
log fetch, health check, example workflows).

Critical fixes
- run_workflow.py: poll_status now checks status_str==error BEFORE
  completed:true, so a failed run no longer reports success
- run_workflow.py: download_output streams to disk via safe_path_join,
  preserves server subfolder structure (no silent overwrites), and
  retries with exponential backoff
- run_workflow.py: refuses to overwrite a link with a literal in
  inject_params (would silently break wiring)
- _common.py: _StripSensitiveOnRedirectSession (subclasses
  requests.Session.rebuild_auth) drops X-API-Key/Cookie on cross-host
  redirects — fixes a real key-leak path through Cloud's signed-URL
  download flow. Tested
- Cloud routing (verified live): /history → /history_v2,
  /models/<f> → /experiment/models/<f>, plus folder aliases for the
  unet ↔ diffusion_models and clip ↔ text_encoders rename
- check_deps.py: distinguishes 200/empty vs 404 folder_not_found vs
  403 free-tier; emits concrete fix_command per missing dep
- extract_schema.py: prompt vs negative_prompt determined by tracing
  KSampler.{positive,negative} connections (incl. through Reroute /
  Primitive nodes) instead of meta-title heuristic; symmetric
  duplicate-name resolution; cycle-safe trace_to_node
- hardware_check.py: multi-GPU pick-best, Apple variant detection,
  Rosetta detection, WSL2, ROCm --json, disk-space check, optional
  PyTorch probe; powershell preferred over deprecated wmic
- comfyui_setup.sh: prefers pipx → uvx → pip --user (with PEP-668
  fallback); idempotent — skips relaunch if server already up;
  configurable port/workspace; persistent log; SIGINT trap

New scripts
- run_batch.py — count or sweep (cartesian product), parallel up to
  cloud tier limit
- ws_monitor.py — real-time WebSocket viewer; saves preview frames
- auto_fix_deps.py — runs comfy node install / model download for
  whatever check_deps reports missing (with --dry-run)
- health_check.py — single command that runs the verification checklist
  (comfy-cli + server + checkpoints + optional smoke test that cancels
  itself to avoid burning compute)
- fetch_logs.py — pull traceback / status messages for a prompt_id

Coverage expansion
- Param patterns now cover Flux (BasicScheduler, BasicGuider,
  RandomNoise, ModelSamplingFlux), SD3, Wan/Hunyuan/LTX video,
  IPAdapter, rgthree, easy-use, AnimateDiff
- Embedding refs in CLIPTextEncode strings extracted as model deps
- ckpt_name / vae_name / lora_name / unet_name now controllable so
  workflows can be retargeted per run

Examples
- workflows/{sd15,sdxl,flux_dev}_txt2img.json
- workflows/sdxl_{img2img,inpaint}.json
- workflows/upscale_4x.json
- workflows/{animatediff_video,wan_video_t2v}.json + README

Tests
- 117 tests (105 unit + 8 cloud integration + 4 cross-host security)
- Cloud tests auto-skip without COMFY_CLOUD_API_KEY; verified end-to-end
  against live cloud API

Backwards compatibility
- All existing CLI flags continue to work; new behavior is opt-in
  (--ws, --input-image, --randomize-seed, --flat-output, etc.)
2026-04-29 20:48:01 -07:00

10 KiB

ComfyUI REST + WebSocket API Reference

ComfyUI exposes a REST + WebSocket interface for workflow execution and management. The same surface is used locally and on Comfy Cloud, with auth/path differences.

Connection

Local ComfyUI Comfy Cloud
Base URL http://127.0.0.1:8188 https://cloud.comfy.org
API path prefix none (/prompt, /view, …) /api/... (/api/prompt, /api/view, …)
Auth none (or bearer token if configured) X-API-Key header
WebSocket ws://host:port/ws?clientId={uuid} wss://cloud.comfy.org/ws?clientId={uuid}&token={API_KEY}
/api/view response direct bytes 302 redirect → signed URL (use curl -L)

The skill scripts route URLs automatically via _common.resolve_url().

Endpoint differences on Comfy Cloud

The cloud surface diverges from local ComfyUI in several ways. The skill scripts handle these transparently; document them here so anyone calling curl directly knows.

Local path Cloud path Notes
/system_stats /api/system_stats Cloud version is public (no auth required)
/object_info /api/object_info Paid tier only — free returns 403
/queue /api/queue Paid tier only
/userdata /api/userdata Paid tier only
/prompt (POST) /api/prompt (POST) Paid tier only
/upload/image /api/upload/image Paid tier only; subfolder accepted but ignored
/upload/mask /api/upload/mask Same as above
/view /api/view Paid tier only; returns 302 to signed URL
/history /api/history_v2 Renamed; old path returns 404
/history/{id} /api/history_v2/{id} or /api/jobs/{id} Both work; /jobs returns full job
/models /api/experiment/models Renamed
/models/{folder} /api/experiment/models/{folder} Renamed; response shape differs (see below)

Cloud model-list response shape

  • Local: ["a.safetensors", "b.safetensors", …] — flat list of strings.
  • Cloud: [{"name": "a.safetensors", "pathIndex": 0}, …] — list of objects.
  • Cloud 404 with code: "folder_not_found" — folder is empty or unknown, not an "endpoint missing" error. Distinguish by reading the body.

The skill helper _common.parse_model_list() normalizes both.

Workflow Execution

Submit Workflow

# Local
curl -X POST "http://127.0.0.1:8188/prompt" \
  -H "Content-Type: application/json" \
  -d '{"prompt": '"$(cat workflow_api.json)"', "client_id": "'"$(uuidgen)"'"}'

# Cloud
curl -X POST "https://cloud.comfy.org/api/prompt" \
  -H "X-API-Key: $COMFY_CLOUD_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt": '"$(cat workflow_api.json)"'}'

Response:

{"prompt_id": "abc-123-def", "number": 1, "node_errors": {}}

If node_errors is non-empty, the workflow has validation errors (missing nodes, bad inputs).

Check Job Status (Cloud)

curl -X GET "https://cloud.comfy.org/api/job/{prompt_id}/status" \
  -H "X-API-Key: $COMFY_CLOUD_API_KEY"
Status Description
pending Job is queued and waiting to start
in_progress Job is currently executing
completed Job finished successfully
failed Job encountered an error
cancelled Job was cancelled by user

Job detail with outputs (Cloud)

curl -X GET "https://cloud.comfy.org/api/jobs/{prompt_id}" \
  -H "X-API-Key: $COMFY_CLOUD_API_KEY"

Response includes outputs keyed by node ID. Cloud uses video (singular) in the output structure; local uses videos (plural). The skill scripts accept both.

Get History (Local)

curl -s "http://127.0.0.1:8188/history"          # all
curl -s "http://127.0.0.1:8188/history/{id}"     # one prompt_id

Local entry shape:

{
  "<prompt_id>": {
    "prompt": [...],
    "outputs": {"<node_id>": {"images": [...]}},
    "status": {
      "status_str": "success" | "error",
      "completed": true | false,
      "messages": [["execution_start", {...}], ["execution_error", {...}], ]
    }
  }
}

Important: when reading status, check status_str == "error" BEFORE checking completed, because both can be true for failed runs.

Download Output

# Local (direct bytes)
curl -s "http://127.0.0.1:8188/view?filename=ComfyUI_00001_.png&subfolder=&type=output" \
  -o output.png

# Cloud (302 → signed URL; -L follows; STRIP X-API-Key for the second hop)
curl -L "https://cloud.comfy.org/api/view?filename=...&type=output" \
  -H "X-API-Key: $COMFY_CLOUD_API_KEY" \
  -o output.png

The skill's run_workflow.py strips X-API-Key automatically on the cross-host redirect, so the signed URL never sees your auth.

WebSocket Monitoring

Connect for real-time execution events.

# Local
wscat -c "ws://127.0.0.1:8188/ws?clientId=MY-UUID"

# Cloud
wscat -c "wss://cloud.comfy.org/ws?clientId=MY-UUID&token=$COMFY_CLOUD_API_KEY"

Note: on Cloud the clientId is currently ignored — all messages for a user are broadcast to every connection. Filter messages client-side by data.prompt_id.

JSON Message Types

Type When Key Fields
status Queue change status.exec_info.queue_remaining
notification User-friendly status string value
execution_start Workflow begins prompt_id
executing Node running (or end-of-run if node is null on local) node, prompt_id
progress Sampling steps node, value, max
progress_state Extended progress with per-node metadata nodes (dict)
executed Node output ready node, output (with images/video/etc.)
execution_cached Nodes skipped because of cache nodes (list of IDs)
execution_success All done prompt_id
execution_error Failure exception_type, exception_message, traceback, node_id
execution_interrupted Cancelled prompt_id

Binary Frames (Preview Images)

Type code Meaning
0x00000001 PREVIEW_IMAGE[type:4][image_type:4][data] (image_type 1=JPEG, 2=PNG)
0x00000003 TEXT[type:4][nid_len:4][nid][text] (UTF-8)
0x00000004 PREVIEW_IMAGE_WITH_METADATA[type:4][meta_len:4][json][image_data]

scripts/ws_monitor.py --previews <dir> saves preview frames to disk.

File Upload

# Image
curl -X POST "http://127.0.0.1:8188/upload/image" \
  -F "image=@photo.png" -F "type=input" -F "overwrite=true"
# Returns: {"name": "photo.png", "subfolder": "", "type": "input"}

# Mask (linked to a previously uploaded image)
curl -X POST "http://127.0.0.1:8188/upload/mask" \
  -F "image=@mask.png" -F "type=input" \
  -F 'original_ref={"filename":"photo.png","subfolder":"","type":"input"}'

Cloud equivalent: prepend https://cloud.comfy.org/api and add -H "X-API-Key: $COMFY_CLOUD_API_KEY".

Node & Model Discovery

# All node types and their input specs
curl -s "http://127.0.0.1:8188/object_info" | python3 -m json.tool

# Specific node
curl -s "http://127.0.0.1:8188/object_info/KSampler"

# Models per folder (local)
curl -s "http://127.0.0.1:8188/models/checkpoints"
curl -s "http://127.0.0.1:8188/models/loras"

# Models per folder (cloud — note the experimental prefix)
curl -s "https://cloud.comfy.org/api/experiment/models/checkpoints" \
  -H "X-API-Key: $COMFY_CLOUD_API_KEY"

Queue Management

# View queue
curl -s "http://127.0.0.1:8188/queue"

# Clear all pending
curl -X POST "http://127.0.0.1:8188/queue" \
  -H "Content-Type: application/json" \
  -d '{"clear": true}'

# Delete specific items
curl -X POST "http://127.0.0.1:8188/queue" \
  -H "Content-Type: application/json" \
  -d '{"delete": ["prompt_id_1", "prompt_id_2"]}'

# Cancel currently-running job
curl -X POST "http://127.0.0.1:8188/interrupt"

System Management

# Stats (VRAM, RAM, GPU, ComfyUI version)
curl -s "http://127.0.0.1:8188/system_stats"

# Free GPU memory
curl -X POST "http://127.0.0.1:8188/free" \
  -H "Content-Type: application/json" \
  -d '{"unload_models": true, "free_memory": true}'

ComfyUI-Manager Endpoints (Optional)

These require ComfyUI-Manager installed. Useful for installing nodes/models via the API instead of comfy-cli.

# Install a custom node from a git URL
curl -X POST "http://127.0.0.1:8188/manager/queue/install" \
  -H "Content-Type: application/json" \
  -d '{"git_url": "https://github.com/user/comfyui-node.git"}'

# Check install queue status
curl -s "http://127.0.0.1:8188/manager/queue/status"

# Install model
curl -X POST "http://127.0.0.1:8188/manager/queue/install_model" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://...", "path": "models/checkpoints", "filename": "model.safetensors"}'

POST /prompt Payload Format

{
  "prompt": {
    "3": {
      "class_type": "KSampler",
      "inputs": {
        "seed": 42,
        "steps": 20,
        "cfg": 7.5,
        "sampler_name": "euler",
        "scheduler": "normal",
        "denoise": 1.0,
        "model": ["4", 0],
        "positive": ["6", 0],
        "negative": ["7", 0],
        "latent_image": ["5", 0]
      }
    }
  },
  "client_id": "unique-uuid-for-ws-filtering",
  "extra_data": {
    "api_key_comfy_org": "optional-PARTNER-NODE-key (NOT the cloud auth key)"
  }
}
  • prompt: workflow graph in API format
  • client_id: UUID — local server uses it to filter WebSocket events; cloud ignores it.
  • extra_data.api_key_comfy_org: ONLY required when the workflow uses partner nodes (Flux Pro, Ideogram, etc.). Don't conflate with X-API-Key.

Error Categories (cloud execution_error exception_type)

Type Meaning
ValidationError Bad workflow / inputs (often nicer to surface from node_errors)
ModelDownloadError Required model not available
ImageDownloadError Failed to fetch input image from URL
OOMError Out of GPU memory
InsufficientFundsError Account balance too low (partner nodes)
InactiveSubscriptionError Subscription not active