StabilityMatrix + ComfyUI → Web API: From Local Image Generation to a Real Service

Manage your ComfyUI environment with StabilityMatrix, enable --listen mode, wrap it with FastAPI, and ship a REST API that anyone can call to generate AI images over HTTP.

You have StabilityMatrix installed, ComfyUI running, images looking great. But every session means opening a browser and dragging nodes around — no way to share it, no way to plug it into a product.

This post fixes that: turn your local ComfyUI into a callable API service. Someone sends an HTTP request, your machine returns an image.


Step 1 — Environment: Manage with StabilityMatrix

StabilityMatrix is the best AI model package manager for Windows/macOS/Linux. It handles:

  • Isolated Python virtual environments (no system pollution)
  • One-click install/upgrade for ComfyUI, A1111, Forge
  • Unified model storage directory
  • GUI for launch arguments

Setup:

  1. Download the latest release from github.com/LykosAI/StabilityMatrix/releases
  2. On first launch, pick a storage directory (separate drive recommended — models are large)
  3. Click Add Package → ComfyUI, install
  4. Hit Launch once to confirm everything works

Step 2 — Enable API Mode

ComfyUI has a built-in HTTP API, but it only listens on 127.0.0.1 by default. To expose it to the LAN or a container, you need one launch argument.

In StabilityMatrix:

Click the ⚙️ next to ComfyUI → Extra Launch Arguments, add:

--listen 0.0.0.0 --port 8188

⚠️ 0.0.0.0 binds all interfaces. Fine for LAN; add auth before exposing to the public internet.

After launch, anyone on your LAN can reach http://your-ip:8188.

Verify the API is up:

curl http://localhost:8188/system_stats

JSON response means you’re good.


Step 3 — Understand the ComfyUI API

The ComfyUI API is small and clean. Three endpoints cover everything:

EndpointMethodPurpose
/promptPOSTSubmit a workflow, get back a prompt_id
/history/{prompt_id}GETPoll status + fetch results
/viewGETDownload the output image

Getting the workflow payload:

Design your workflow in the ComfyUI UI, then click Save (API format) in the top-right menu. The saved workflow_api.json is your request body.

Polling for the result:

import requests, time

def generate(workflow: dict, host="http://localhost:8188"):
    r = requests.post(f"{host}/prompt", json={"prompt": workflow, "client_id": "demo"})
    pid = r.json()["prompt_id"]

    while True:
        h = requests.get(f"{host}/history/{pid}").json()
        if pid in h:
            output = h[pid]["outputs"]
            img = list(output.values())[0]["images"][0]
            return requests.get(f"{host}/view", params=img).content
        time.sleep(1)

Step 4 — Wrap It with FastAPI

Exposing the raw ComfyUI API is too low-level for callers — they’d need to know the workflow format. Add a FastAPI layer to present a clean business interface:

# app.py
from fastapi import FastAPI
from fastapi.responses import Response
import json, requests, time, copy

app = FastAPI()
COMFY = "http://localhost:8188"

with open("workflow_api.json") as f:
    WORKFLOW_TPL = json.load(f)

@app.post("/generate")
def generate(prompt: str, width: int = 512, height: int = 512, steps: int = 20):
    wf = copy.deepcopy(WORKFLOW_TPL)

    for node in wf.values():
        if node["class_type"] == "KSampler":
            node["inputs"]["steps"] = steps
        if node["class_type"] == "EmptyLatentImage":
            node["inputs"]["width"] = width
            node["inputs"]["height"] = height
        if node["class_type"] == "CLIPTextEncode":
            node["inputs"]["text"] = prompt

    r = requests.post(f"{COMFY}/prompt", json={"prompt": wf, "client_id": "api"})
    pid = r.json()["prompt_id"]

    while True:
        h = requests.get(f"{COMFY}/history/{pid}").json()
        if pid in h:
            imgs = list(h[pid]["outputs"].values())[0]["images"]
            img_data = requests.get(f"{COMFY}/view", params=imgs[0]).content
            return Response(content=img_data, media_type="image/png")
        time.sleep(1)

Run it:

pip install fastapi uvicorn requests
uvicorn app:app --host 0.0.0.0 --port 8000

Call it:

curl "http://localhost:8000/generate?prompt=a+cat+in+space&width=768&height=768" \
  --output cat.png

Step 5 — Add API Key Auth

Don’t run a naked API. A simple Bearer token check is enough to start:

from fastapi import Header, HTTPException, Depends

API_KEYS = {"sk-your-key-here"}

def verify(authorization: str = Header(...)):
    token = authorization.removeprefix("Bearer ").strip()
    if token not in API_KEYS:
        raise HTTPException(status_code=401, detail="Unauthorized")

@app.post("/generate")
def generate(prompt: str, _=Depends(verify)):
    ...
curl -H "Authorization: Bearer sk-your-key-here" \
  "http://localhost:8000/generate?prompt=a+cat+in+space" \
  --output result.png

Step 6 — Expose to the Internet

No public IP required. Cloudflare handles TLS and routing.

winget install Cloudflare.cloudflared
cloudflared tunnel login
cloudflared tunnel create comfyui-api
cloudflared tunnel --url http://localhost:8000

You get a *.trycloudflare.com URL instantly. You can bind a custom domain too.

Option B: nginx reverse proxy (if you have a public IP)

server {
    listen 443 ssl;
    server_name api.yourdomain.com;

    location / {
        proxy_pass http://127.0.0.1:8000;
        proxy_read_timeout 120s;
    }
}

Option C: ngrok (fastest, good for testing)

ngrok http 8000

Step 7 — Real-time Progress via WebSocket (optional)

Staring at a blank page while waiting for an image is bad UX. ComfyUI pushes progress events over WebSocket:

const ws = new WebSocket(`ws://localhost:8188/ws?clientId=my-app`);

ws.onmessage = (e) => {
  const msg = JSON.parse(e.data);
  if (msg.type === "progress") {
    console.log(`Progress: ${msg.data.value}/${msg.data.max}`);
  }
  if (msg.type === "executing" && msg.data.node === null) {
    console.log("Done!");
  }
};

Wire this to a progress bar on the frontend and the experience feels instant.


Summary

StepToolPurpose
EnvironmentStabilityMatrixIsolated Python + one-click ComfyUI
API exposure--listen 0.0.0.0ComfyUI built-in HTTP API
Business layerFastAPIClean interface, hide workflow details
AuthBearer tokenPrevent abuse
Public accessCloudflare TunnelFree, secure, no public IP needed
Live progressWebSocketBetter user experience

At the end of this, you have your own AI image generation API — pluggable into any product, shareable with friends, or wrappable in a frontend to ship as a full Web App.


Posted by Seraph @ u14.co · May 2026