실험적 API: 이 API는 실험적인 것으로, 변경될 수 있습니다. 엔드포인트, 요청/응답 형식 및 동작은 사전 통지 없이 수정될 수 있습니다.
Comfy Cloud API
Comfy Cloud API는 Comfy Cloud 인프라에서 워크플로우를 실행하기 위한 프로그래밍 방식 접근을 제공합니다. 이 API는 로컬 ComfyUI의 API와 호환되므로 기존 통합을 쉽게 마이그레이션할 수 있습니다.
구독 필요: API 접근은 스탠다드, 크리에이터, 프로 계층에서 이용 가능합니다. 무료 계층에는 API 접근이 포함되지 않습니다. 자세한 내용은 가격 정책을 참조하십시오.
크레딧 및 사용법
API 요청은 Comfy Cloud 웹 UI와 동일한 월별 크레딧 할당량을 사용합니다 — 별도의 API 크레딧 풀은 없습니다. 각 계층에 포함된 크레딧, 추가 옵션 및 워크플로우당 런타임 제한은 UI 작업과 정확히 동일하게 API 작업에도 적용됩니다. 가격 페이지에서 스탠다드, 크리에이터 및 프로 계층의 월별 크레딧 수치를 확인하십시오. 한 달 중간에 크레딧이 부족해지면 계정 대시보드에서 추가 구매가 가능합니다.
기본 URL
모든 API 요청에는 X-API-Key 헤더를 통해 전달되는 API 키가 필요합니다.
API 키 얻기
API 키 생성 및 관리에 대한 지침은 API 키 얻기를 참조하십시오.
API 키 사용하기
모든 요청 시 X-API-Key 헤더에 API 키를 전달하십시오:
curl -X GET "https://cloud.comfy.org/api/user" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY"
핵심 개념
워크플로우
ComfyUI 워크플로우는 노드 그래프를 설명하는 JSON 객체입니다. API는 ComfyUI 프론트엔드의 “저장(API 형식)” 옵션으로 생성된 “API 형식”(노드 ID를 키로 하며 class_type, inputs 등이 포함된) 워크플로우를 수락합니다.
워크플로우를 제출하면 작업이 생성됩니다. 작업은 비동기적으로 실행됩니다:
POST /api/prompt을 통해 워크플로우 제출
prompt_id(작업 ID) 받기
- WebSocket을 통해 진행 상태 모니터링 또는 상태 조회
- 완료 시 출력물 가져오기
병렬 실행(동시 작업)
API 사용자는 이전 작업이 완료될 때까지 기다릴 필요 없이 여러 워크플로우를 동시에 제출할 수 있습니다. 단순히 여러 POST /api/prompt 요청을 보내기만 하면 되며, 특별한 헤더나 매개변수는 필요하지 않습니다. 디스패처는 구독 계층의 제한 내에서 병렬로 실행합니다.
동시 작업 제한을 초과하여 제출된 작업은 일반대로 대기하며, 슬롯이 비워질 때 자동으로 실행됩니다.
현재 병렬 실행은 API를 통해서만 이용 가능합니다. 구독 상세 정보는 가격 정책을 참조하십시오.
예제: 병렬로 여러 작업 제출하기
import os
import json
import asyncio
import aiohttp
BASE_URL = "https://cloud.comfy.org"
API_KEY = os.environ["COMFY_CLOUD_API_KEY"]
async def submit_workflow(session, workflow):
"""단일 워크플로우를 제출하고 prompt_id 반환"""
async with session.post(
f"{BASE_URL}/api/prompt",
headers={"X-API-Key": API_KEY, "Content-Type": "application/json"},
json={"prompt": workflow},
) as response:
result = await response.json()
return result["prompt_id"]
async def main():
with open("workflow_api.json") as f:
base_workflow = json.load(f)
# 시드를 변경해 변형 생성
workflows = []
for seed in [42, 123, 456]:
workflow = json.loads(json.dumps(base_workflow))
workflow["3"]["inputs"]["seed"] = seed
workflows.append(workflow)
# 모든 워크플로우를 동시에 제출
async with aiohttp.ClientSession() as session:
prompt_ids = await asyncio.gather(
*[submit_workflow(session, wf) for wf in workflows]
)
for pid in prompt_ids:
print(f"작업 제출됨: {pid}")
# 각 작업 모니터링을 위해 polling 또는 WebSocket 사용...
asyncio.run(main())
출력물
생성된 콘텐츠(이미지, 동영상, 오디오)는 클라우드 스토리지에 저장됩니다. 출력 파일은 /api/view 엔드포인트를 통해 다운로드할 수 있으며, 이 엔드포인트는 임시 서명된 URL로 302 리다이렉트를 반환합니다.
빠른 시작
워크플로우를 제출하고 진행 상태를 모니터링하며 출력물을 가져오는 방법을 보여주는 전체 예제입니다:
1단계: 워크플로우 제출
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)"'"}'
2단계: 작업 진행 상태 모니터링
폴링 또는 WebSocket을 사용해 작업 완료 여부를 모니터링할 수 있습니다.
옵션 A: 폴링(간단함)
작업 상태 값:
API는 다음 상태 값을 반환합니다:
| 상태 | 설명 |
|---|
pending | 작업이 대기 중이며 시작을 기다리고 있습니다 |
in_progress | 작업이 현재 실행 중입니다 |
completed | 작업이 성공적으로 완료되었습니다 |
failed | 작업 중 오류가 발생했습니다 |
cancelled | 사용자가 작업을 취소했습니다 |
# 작업 완료 여부를 풀링합니다
curl -X GET "$BASE_URL/api/job/{prompt_id}/status" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY"
# 응답 예시:
# {"status": "pending"} - 작업이 대기 중입니다
# {"status": "in_progress"} - 작업이 현재 실행 중입니다
# {"status": "completed"} - 작업이 성공적으로 완료되었습니다
# {"status": "failed"} - 작업 중 오류가 발생했습니다
# {"status": "cancelled"} - 작업이 취소되었습니다
옵션 B: WebSocket(실시간 진행 상태)
실시간 진행 상태 업데이트 및 출력 메타데이터 수집을 위해:
async function listenForCompletion(
promptId: string,
timeout: number = 300000
): Promise<Record<string, any>> {
const wsUrl = `wss://cloud.comfy.org/ws?clientId=${crypto.randomUUID()}&token=${API_KEY}`;
const outputs: Record<string, any> = {};
return new Promise((resolve, reject) => {
const ws = new WebSocket(wsUrl);
const timer = setTimeout(() => {
ws.close();
reject(new Error(`작업이 ${timeout / 1000}s 내에 완료되지 않았습니다`));
}, timeout);
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
const msgType = data.type;
const msgData = data.data ?? {};
// 우리의 작업으로 필터링
if (msgData.prompt_id !== promptId) return;
if (msgType === "executing") {
const node = msgData.node;
if (node) {
console.log(`실행 중인 노드: ${node}`);
} else {
console.log("실행 완료");
}
} else if (msgType === "progress") {
console.log(`진행률: ${msgData.value}/${msgData.max}`);
} else if (msgType === "executed" && msgData.output) {
outputs[msgData.node] = msgData.output;
} else if (msgType === "execution_success") {
console.log("작업이 성공적으로 완료되었습니다!");
clearTimeout(timer);
ws.close();
resolve(outputs);
} else if (msgType === "execution_error") {
const errorMsg = msgData.exception_message ?? "알 수 없는 오류";
clearTimeout(timer);
ws.close();
reject(new Error(`실행 오류: ${errorMsg}`));
}
};
ws.onerror = (err) => {
clearTimeout(timer);
reject(err);
};
});
}
// 완료를 기다리고 출력값 수집
const outputs = await listenForCompletion(promptId);
3단계: 출력물 다운로드
작업이 완료되면 생성된 파일을 다운로드하세요. WebSocket에서 반환되거나 히스토리 엔드포인트를 통해 이용 가능한 outputs 객체는 노드 ID별로 정리된 출력 데이터를 포함합니다. 각 노드의 출력에는 images, video 또는 audio 배열과 파일 메타데이터가 포함될 수 있습니다.
출력물 구조 예시:
{
"9": {
"images": [
{
"filename": "ComfyUI_00001_.png",
"subfolder": "",
"type": "output"
}
]
}
}
노드 ID("9" 예시)는 워크플로우의 SaveImage 또는 기타 출력 노드에 해당합니다. 워크플로우 JSON 파일을 열어 class_type이 SaveImage, VHS_VideoCombine 등의 노드를 찾으면 이 ID를 확인할 수 있습니다.
# 단일 출력 파일 다운로드하기 (302 리디렉션은 -L 옵션으로 따라가기)
curl -L "$BASE_URL/api/view?filename=output.png&subfolder=&type=output" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY" \
-o output.png
/api/view 엔드포인트는 임시 서명된 URL로 302 리다이렉트를 반환합니다. HTTP 클라이언트는 리다이렉트를 따라야만 파일을 다운로드할 수 있습니다.
전체 예제
세 단계를 모두 결합한 전체 엔드투엔드 예제입니다:
import { readFile, writeFile } from "fs/promises";
const BASE_URL = "https://cloud.comfy.org";
const API_KEY = process.env.COMFY_CLOUD_API_KEY!;
async function main() {
// 1. 워크플로우 로드 및 수정
const workflow = JSON.parse(await readFile("workflow_api.json", "utf-8"));
workflow["3"].inputs.seed = 42;
workflow["6"].inputs.text = "아름다운 일몰";
// 2. 워크플로우 제출
const response = await fetch(`${BASE_URL}/api/prompt`, {
method: "POST",
headers: { "X-API-Key": API_KEY, "Content-Type": "application/json" },
body: JSON.stringify({ prompt: workflow }),
});
const { prompt_id } = await response.json();
console.log(`작업 제출됨: ${prompt_id}`);
// 3. 완료 여부 휠링
while (true) {
const statusRes = await fetch(`${BASE_URL}/api/job/${prompt_id}/status`, {
headers: { "X-API-Key": API_KEY },
});
const { status } = await statusRes.json();
if (status === "completed") break;
if (["failed", "cancelled"].includes(status)) {
throw new Error(`작업 ${status}`);
}
await new Promise((resolve) => setTimeout(resolve, 2000));
}
// 4. 작업 세부 정보 엔드포인트를 통해 출력물 가져오기
const jobRes = await fetch(`${BASE_URL}/api/jobs/${prompt_id}`, {
headers: { "X-API-Key": API_KEY },
});
const job = await jobRes.json();
const outputs = job.outputs;
// 5. 출력 파일 다운로드
for (const nodeOutputs of Object.values(outputs)) {
for (const fileInfo of (nodeOutputs as any).images ?? []) {
const params = new URLSearchParams({
filename: fileInfo.filename,
subfolder: fileInfo.subfolder ?? "",
type: "output",
});
const viewRes = await fetch(`${BASE_URL}/api/view?${params}`, {
headers: { "X-API-Key": API_KEY },
redirect: "manual",
});
const signedUrl = viewRes.headers.get("location")!;
const fileRes = await fetch(signedUrl);
await writeFile(`./${fileInfo.filename}`, Buffer.from(await fileRes.arrayBuffer()));
console.log(`다운로드 완료: ${fileInfo.filename}`);
}
}
}
main();
사용 가능한 엔드포인트
| 카테고리 | 설명 |
|---|
| 워크플로우 | 워크플로우 제출, 상태 확인 |
| 작업 | 작업 상태 및 대기열 모니터링 |
| 입력 | 이미지, 마스크 및 기타 입력 업로드 |
| 출력 | 생성된 콘텐츠 다운로드 |
| WebSocket | 실시간 진행 상태 업데이트 |
| 객체 정보 | 사용 가능한 노드 및 그 정의 |
다음 단계
위의 빠른 시작은 워크플로우 제출과 결과 가져오기에 대한 기본 사항을 다룹니다. 더 고급 사용 사례를 위해서는 클라우드 API 참조를 참고하십시오:
- 입력 파일 업로드 - 워크플로우에 외부 입력이 필요한 경우 이미지, 마스크 또는 기타 사용자 제공 콘텐츠 업로드
- 워크플로우 입력 수정 - 제출 전에 프롬프트, 시드 또는 노드 설정과 같은 워크플로우 파라미터를 동적으로 변경
- 파트너 노드 사용 - 추가 API 키 구성이 필요한 외부 AI 서비스(Flux Pro, Ideogram 등) 호출
- 대기열 관리 - 대기열 상태 모니터링, 작업 취소 또는 실행 중인 작업 중단
- 오류 처리 - HTTP 오류, 실행 실패 처리 및 예외 유형 이해
추가 자료: