ComfyUI API: документация и примеры
ComfyUI это не только UI — у него есть полноценный REST + WebSocket API. Разбираем все endpoints, аутентификацию, формат workflow JSON и примеры на Python.
Обновлено: 2026-05-19
TL;DR
У ComfyUI есть полноценный HTTP + WebSocket API, документации на которые «официально» нет — придётся читать server.py или гайды вроде этого. Базовые эндпоинты: POST /prompt (запуск задачи), GET /history/{id} (статус и результаты), GET /view (скачать файл), WS /ws (события прогресса). В этом гайде — полный контракт, готовые примеры на Python и curl, типичные ошибки, отличия managed-API.
Что такое ComfyUI API
ComfyUI — графовый интерфейс для Stable Diffusion. Сервер ComfyUI слушает на порту 8188 и предоставляет HTTP-эндпоинты, которые UI использует для всех действий. То же самое API доступно вам напрямую — UI не обязателен.
Архитектурно ComfyUI устроен так:
- Очередь задач в памяти процесса. Все
POST /prompt падают в одну глобальную очередь и выполняются последовательно.
- История выполненных задач хранится по
prompt_id (UUID).
- Output-файлы записываются на диск в
output/ (или подкаталоги), доступ через GET /view.
- WebSocket шлёт события прогресса всем подключённым клиентам.
В managed-API (gpupool, ComfyICU, RunComfy, fal.ai workflows) есть обёртка поверх этого: аутентификация, асинхронность, изоляция между клиентами, S3-выдача результатов, webhook. Базовый контракт остаётся узнаваемым, но названия эндпоинтов и поля могут отличаться.
Базовый workflow
Минимальный happy-path для self-hosted ComfyUI:
1. POST /prompt ← отправили workflow JSON, получили prompt_id
2. WS /ws ← или GET /history/{prompt_id} в цикле для polling
3. GET /view?filename=... ← скачали результат
В этом гайде — оба варианта (websocket и polling), плюс типичные обёртки.
POST /prompt — запуск задачи
Метод: POST
URL: http://comfyui-host:8188/prompt
Body:
{
"prompt": { /* workflow JSON в API-формате */ },
"client_id": "my-client-uuid",
"extra_data": { "extra_pnginfo": { /* опционально */ } }
}
Ответ:
{
"prompt_id": "9f3c1a8b-2d4e-4f0a-b5c6-7a8b9c0d1e2f",
"number": 42,
"node_errors": {}
}
prompt_id — главное, сохраняйте его. number — порядковый номер в очереди (для UI). node_errors — если граф невалиден, здесь будет список ошибок (например, отсутствует чекпойнт).
Где взять workflow JSON
В UI ComfyUI: Settings → Enable Dev mode Options. После этого в меню появится Save (API Format) — экспорт даст функциональный JSON без UI-координат. Это и есть prompt для POST.
Альтернативно — можно собрать JSON программно. Каждая нода — это запись { "class_type": "...", "inputs": { ... } }, связи указываются как [node_id, output_index].
GET /history — статусы и результаты
Метод: GET
URL: http://comfyui-host:8188/history/{prompt_id} (или без prompt_id — вся история).
Ответ (когда задача завершена):
{
"9f3c1a8b-...": {
"prompt": [42, "9f3c1a8b-...", { /* исходный workflow */ }, { /* extra_data */ }, ["9"]],
"outputs": {
"9": {
"images": [
{ "filename": "ComfyUI_00042_.png", "subfolder": "", "type": "output" }
]
}
},
"status": {
"status_str": "success",
"completed": true,
"messages": [...]
}
}
}
Пока задача в очереди или выполняется — history для её prompt_id пуст. Это и есть сигнал «не готово».
GET /view — скачать файл
Метод: GET
URL: http://comfyui-host:8188/view?filename=ComfyUI_00042_.png&type=output&subfolder=
Возвращает binary PNG/JPEG. Можно стримить, можно сохранить. Здесь же доступны input-файлы (type=input) и временные (type=temp).
WebSocket — прогресс в реальном времени
Подключение: ws://comfyui-host:8188/ws?clientId={uuid}.
clientId — тот же, что отправили в POST /prompt. Это позволяет сервису шлёт события только «вашему» подключению, а не широковещательно.
Типы событий:
{ "type": "execution_start", "data": { "prompt_id": "..." } }
{ "type": "executing", "data": { "node": "3", "prompt_id": "..." } }
{ "type": "progress", "data": { "value": 12, "max": 30 } }
{ "type": "executed", "data": { "node": "9", "output": { "images": [...] } } }
{ "type": "execution_cached","data": { "nodes": ["4"], "prompt_id": "..." } }
{ "type": "execution_error", "data": { "prompt_id": "...", "node_id": "3", "node_type": "...", "exception_message": "..." } }
Подписка через WebSocket даёт гораздо меньше трафика, чем polling, и моментальный прогресс. Минус — нужно держать соединение, что усложняет деплой через nginx/Caddy (надо Upgrade headers).
Python-клиент
Готовый шаблон, который вы можете адаптировать под managed-API:
import json
import urllib.request
import urllib.parse
import uuid
import time
COMFYUI_URL = "http://localhost:8188"
def queue_prompt(workflow: dict, client_id: str) -> str:
body = json.dumps({"prompt": workflow, "client_id": client_id}).encode()
req = urllib.request.Request(
f"{COMFYUI_URL}/prompt",
data=body,
headers={"Content-Type": "application/json"},
)
with urllib.request.urlopen(req) as r:
data = json.loads(r.read())
if data.get("node_errors"):
raise RuntimeError(f"Invalid workflow: {data['node_errors']}")
return data["prompt_id"]
def wait_for_result(prompt_id: str, timeout: float = 300) -> dict:
deadline = time.time() + timeout
while time.time() < deadline:
with urllib.request.urlopen(f"{COMFYUI_URL}/history/{prompt_id}") as r:
history = json.loads(r.read())
if prompt_id in history:
status = history[prompt_id]["status"]
if status.get("completed"):
return history[prompt_id]
if status.get("status_str") == "error":
raise RuntimeError(f"Workflow failed: {status}")
time.sleep(2.0)
raise TimeoutError(f"Workflow {prompt_id} did not finish in {timeout}s")
def download_image(filename: str, subfolder: str = "", type_: str = "output") -> bytes:
params = urllib.parse.urlencode({"filename": filename, "subfolder": subfolder, "type": type_})
with urllib.request.urlopen(f"{COMFYUI_URL}/view?{params}") as r:
return r.read()
# Использование
client_id = str(uuid.uuid4())
workflow = json.load(open("my_workflow_api.json"))
prompt_id = queue_prompt(workflow, client_id)
result = wait_for_result(prompt_id)
image_meta = result["outputs"]["9"]["images"][0] # node "9" = SaveImage
png_bytes = download_image(image_meta["filename"], image_meta["subfolder"])
open("out.png", "wb").write(png_bytes)
Это рабочая обёртка для self-hosted ComfyUI. Для managed-API замените три эндпоинта (/prompt, /history, /view) на их аналоги — контракт обычно совместим по смыслу.
Curl-примеры
Отправка задачи:
curl -X POST http://localhost:8188/prompt \
-H "Content-Type: application/json" \
--data '{"prompt": '$(cat workflow_api.json)', "client_id": "my-client"}'
Проверить статус:
curl http://localhost:8188/history/9f3c1a8b-2d4e-4f0a-b5c6-7a8b9c0d1e2f
Скачать результат:
curl "http://localhost:8188/view?filename=ComfyUI_00042_.png&type=output" -o result.png
Аутентификация
В базовом ComfyUI аутентификации нет. Поднимать его «голым» в интернете — небезопасно: любой может отправлять задачи и скачивать чужие результаты.
Варианты:
- Reverse proxy с Basic Auth (nginx/Caddy). Простой и универсальный.
- comfyui-login custom node — добавляет login-страницу.
- Managed-API уже имеют Bearer-токен из коробки.
Все три способа добавляют слой над базовым ComfyUI, но не меняют сам API.
Дополнительные эндпоинты
| Эндпоинт |
Назначение |
GET /system_stats |
RAM, VRAM, версия python, версия CUDA |
GET /object_info |
Список всех нод и их схема (важно для UI и валидации) |
GET /queue |
Текущая очередь: running + pending |
POST /queue (clear/delete) |
Очистить очередь или удалить конкретный prompt |
POST /interrupt |
Прервать текущую задачу |
POST /upload/image |
Загрузить картинку для использования в workflow (LoadImage node) |
GET /embeddings |
Список доступных text-эмбеддингов |
GET /extensions |
Список JS-расширений UI |
/object_info — мощный инструмент для автоматизации: позволяет программно узнать, какие ноды установлены и какие у них inputs/outputs.
Типичные ошибки
| Симптом |
Причина |
Решение |
node_errors непустой при POST /prompt |
Ссылка на отсутствующий чекпойнт/LoRA/ноду |
Проверить class_type нод через /object_info, имена моделей через /object_info |
prompt_id есть, но /history пуст вечно |
Задача в очереди ждёт своей очереди; либо упала |
Проверить /queue; смотреть логи ComfyUI |
| WebSocket отключается через 60 секунд за nginx |
proxy_read_timeout мал |
proxy_read_timeout 3600s; proxy_send_timeout 3600s; для апстрима ws |
CUDA out of memory в логах при executing |
VRAM не хватает на эту ноду |
--lowvram / tiled VAE / уменьшить разрешение / см. отдельный гайд по CUDA OOM в ComfyUI |
/view возвращает 404 |
Subfolder указан неверно или файл уже удалён |
В outputs смотрите оба поля — filename и subfolder. Иногда subfolder непустой |
| Картинка чёрная или пустая |
Несовместимый VAE, LoRA с другой архитектурой, NaN'ы |
Тестовый прогон через UI, замена VAE, понижение strength LoRA |
Когда хватает self-hosted, а когда нужен managed-API
| Сценарий |
Self-hosted |
Managed-API |
| Один разработчик прототипирует, GPU физически есть |
✅ |
⚠️ overkill |
| Прод с одним клиентом, низкая нагрузка |
✅ |
✅ |
| Несколько клиентов, нужна изоляция данных и VRAM |
⚠️ дорого |
✅ |
| Рваная нагрузка (10 задач в день и 1000 в пиковый день) |
⚠️ дорого |
✅ |
| Нужны редкие GPU (H100) под пиковую задачу |
❌ |
✅ |
| Регуляторика по хранению данных в РФ |
✅ (свой) |
✅ (РФ-API) |
Главное отличие managed-API — изоляция и pay-per-task. Если ваш сценарий — один GPU, который занят 80% времени, self-host часто дешевле. Если меньше — managed выигрывает.
Что почитать дальше
Частые вопросы
Где документация официального ComfyUI API?
Официальной single-page документации нет. Есть страница ComfyUI Wiki + код в server.py. Этот гайд собирает практическую документацию из исходников и опыта эксплуатации.
Как получить workflow JSON для API?
В UI ComfyUI: Settings → Enable Dev mode Options → меню Save (API Format). Это даст функциональный JSON без UI-координат, готовый для POST /prompt.
Чем отличается API JSON от обычного workflow?
API JSON — это только функциональная часть (ноды и связи), без UI-координат и группы. Обычный JSON ComfyUI содержит ещё UI-метаданные, которые server не использует.
Как получать прогресс через WebSocket?
Подключитесь к ws://comfyui-host/ws?clientId=<uuid>. ComfyUI шлёт события execution_start, executing, progress, executed, execution_cached. Лучше всего работает для long-running задач.