Extensions/comfy-workflow-api
ComfyUI Extension

comfy-workflow-api

HTTP API for ComfyUI with webhook-based workflow execution.

By isala404·Created 7 months ago·Updated 7 months ago· 2
isala404/comfy-workflow-api
Nodes3
On cloudLocal install
Categorywebhook
Stars2
Updated7 months ago
Readme

ComfyUI Workflow API

HTTP API for ComfyUI with webhook-based workflow execution. Submit workflows via HTTP, receive real-time progress updates and outputs at your callback URL.

Installation

cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/isala404/comfy-workflow-api.git
pip install -r comfy-workflow-api/requirements.txt

Use Cases

  • Backend Integration: Run ComfyUI as a headless service behind your application
  • Batch Processing: Submit multiple workflows and receive results asynchronously
  • Distributed Systems: Decouple workflow submission from result handling
  • Mobile/Web Apps: Trigger image generation from any HTTP client

How It Works

Client                          ComfyUI                         Your Server
  │                                │                                │
  ├─── POST /api/webhook ─────────►│                                │
  │    (workflow + callback_url)   │                                │
  │                                │                                │
  │◄── {request_id, prompt_id} ────┤                                │
  │                                │                                │
  │                                ├── workflow.progress ──────────►│
  │                                ├── workflow.progress ──────────►│
  │                                ├── ...                          │
  │                                │                                │
  │                                ├── multipart (files) ──────────►│
  │                                │                                │

Quick Start

1. Create a workflow using webhook nodes

Use WebhookReceiverWebhookTransformerWebhookSend to read inputs from HTTP and send outputs back:

                    ┌─► WebhookTransformer ──► CLIPTextEncode ──┐
WebhookReceiver ────┤   (extracts "prompt")                     ├──► KSampler ──► WebhookSend
                    └─► WebhookTransformer ──► VAEEncode ───────┘
                        (extracts "image")

2. Submit via HTTP

# Image-to-image example
curl -X POST http://localhost:8188/api/webhook \
  -F "[email protected]" \
  -F "callback_url=http://your-server.com/webhook" \
  -F "prompt=turn it into a watercolor painting" \
  -F "[email protected]"

3. Receive at your callback

Your server receives:

  • Progress events (JSON): {"event": "workflow.progress", "progress": {"value": 5, "max": 20}}
  • Output files (gzip multipart): Images, audio, video, etc.

Nodes

WebhookReceiver

Entry point for webhook workflows. Reads request configuration from the HTTP call.

| Output | Type | Description | |--------|------|-------------| | webhook_context | WEBHOOK_CONTEXT | Context for other webhook nodes |

WebhookTransformer

Extracts a field from the HTTP request. Connects to any input type.

| Input | Description | |-------|-------------| | webhook_context | From WebhookReceiver | | field | Field name to extract (e.g., "prompt") | | default_value | Optional fallback if field missing |

| Output | Type | Description | |--------|------|-------------| | value | * (wildcard) | Extracted value, auto-typed |

Type inference: Strings are converted to INT, FLOAT, BOOLEAN when applicable. File uploads become IMAGE, AUDIO, VIDEO, MESH, or LATENT based on content type.

WebhookSend

Sends outputs to the callback URL. Supports 5 output fields.

| Input | Description | |-------|-------------| | webhook_context | From WebhookReceiver | | field_1..5 | Any ComfyUI type (IMAGE, AUDIO, STRING, etc.) | | field_1..5_name | Names for each output |

Encoding: IMAGE→PNG, AUDIO→FLAC, VIDEO→MP4, MESH→GLB, LATENT→safetensors

API Reference

POST /api/webhook

| Field | Required | Description | |-------|----------|-------------| | workflow | Yes | Workflow JSON | | callback_url | Yes | URL to receive events/outputs | | auth_header | No | Auth header name | | auth_value | No | Auth header value | | timeout | No | HTTP timeout (default: 60s) | | max_retries | No | Retry attempts (default: 3) | | custom fields | No | Any field accessible via WebhookTransformer |

Response:

{"request_id": "...", "prompt_id": "...", "status": "queued"}

GET /api/webhook/status/{request_id}

Check request status.

DELETE /api/webhook/{request_id}

Cancel a queued/running workflow.

Webhook Events

| Event | Content-Type | Description | |-------|--------------|-------------| | workflow.started | application/json | Execution began | | workflow.progress | application/json | Step progress (throttled 500ms) | | workflow.completed | multipart/form-data (gzip) | Output files + metadata | | workflow.error | application/json | Execution failed |

Note: Completion payload is gzip compressed. Decompress before parsing.

Example

workflow.json (see example_workflow.json):

{
  "10": {
    "class_type": "WebhookReceiver",
    "inputs": {"debug": true}
  },
  "11": {
    "class_type": "WebhookTransformer",
    "inputs": {"field": "prompt", "webhook_context": ["10", 0]}
  },
  "6": {
    "class_type": "CLIPTextEncode",
    "inputs": {"text": ["11", 0], "clip": ["4", 1]}
  },
  "...": "... rest of workflow ...",
  "12": {
    "class_type": "WebhookSend",
    "inputs": {"webhook_context": ["10", 0], "field_1": ["8", 0]}
  }
}

Python client (see example_client.py):

import requests, json

# Load image for img2img
image_data = open("input.png", "rb").read()

response = requests.post(
    "http://localhost:8188/api/webhook",
    files={
        "workflow": (None, json.dumps(workflow), "application/json"),
        "callback_url": (None, "http://localhost:5001/webhook"),
        "prompt": (None, "make it look like a painting"),
        "image": ("input.png", image_data, "image/png"),
    }
)

Testing

# Terminal 1: Start ComfyUI
python main.py

# Terminal 2: Run example client (image-to-image)
cd custom_nodes/comfy-workflow-api
python example_client.py sample_input.png "turn it into a watercolor painting"

A sample image (sample_input.png) is included in the repo for testing.

License

MIT