実験的 API: この API は実験的であり、変更される可能性があります。エンドポイント、リクエスト/レスポンス形式、および動作は予告なしに変更される場合があります。一部のエンドポイントはローカル ComfyUI との互換性のために維持されていますが、異なるセマンティクスを持つ場合があります(例:無視されるフィールド)。
このページでは、一般的な Comfy Cloud API 操作の完全な例を提供します。
サブスクリプションが必要: API を介してワークフローを実行するには、有効な Comfy Cloud サブスクリプションが必要です。詳細については料金プランをご覧ください。
すべての例で、これらの共通のインポートと設定を使用します:
export COMFY_CLOUD_API_KEY="your-api-key"
export BASE_URL="https://cloud.comfy.org"
オブジェクト情報
利用可能なノード定義を取得します。これは、利用可能なノードとその入出力仕様を理解するのに役立ちます。
curl -X GET "$BASE_URL/api/object_info" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY"
入力のアップロード
ワークフローで使用するための画像、マスク、またはその他のファイルをアップロードします。
直接アップロード(Multipart)
curl -X POST "$BASE_URL/api/upload/image" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY" \
-F "image=@my_image.png" \
-F "type=input" \
-F "overwrite=true"
マスクのアップロード
subfolder パラメータは API 互換性のために受け入れられますが、クラウドストレージでは無視されます。すべてのファイルはフラットなコンテンツアドレス指定ネームスペースに保存されます。
curl -X POST "$BASE_URL/api/upload/mask" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY" \
-F "image=@mask.png" \
-F "type=input" \
-F "subfolder=clipspace" \
-F 'original_ref={"filename":"my_image.png","subfolder":"","type":"input"}'
ワークフローの実行
実行のためにワークフローを送信します。
同時送信をサポート: サブスクリプションティアに応じて、前のジョブの完了を待たずに複数のワークフローを送信できます。ジョブはティアの制限まで並列で実行されます—追加のジョブは自動的にキューイングされます。詳細と同時実行制限については並列実行をご覧ください。
ワークフローの送信
curl -X POST "$BASE_URL/api/prompt" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY" \
-H "Content-Type: application/json" \
-d '{"prompt": '"$(cat workflow_api.json)"'}'
パートナーノードの使用
ワークフローにパートナーノード(Flux Pro、Ideogram などの外部 AI サービスを呼び出すノード)が含まれている場合、リクエストペイロードの extra_data フィールドに Comfy API キーを含める必要があります。
ブラウザでワークフローを実行する際、ComfyUI フロントエンドは自動的に API キーを extra_data にパッケージ化します。このセクションは API を直接呼び出す場合のみ関連します。
curl -X POST "$BASE_URL/api/prompt" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"prompt": '"$(cat workflow_api.json)"',
"extra_data": {
"api_key_comfy_org": "your-comfy-api-key"
}
}'
ワークフロー入力の修改
function setWorkflowInput(
workflow: Record<string, any>,
nodeId: string,
inputName: string,
value: any
): Record<string, any> {
if (workflow[nodeId]) {
workflow[nodeId].inputs[inputName] = value;
}
return workflow;
}
// Example: Set seed and prompt
let workflow = JSON.parse(await readFile("workflow_api.json", "utf-8"));
workflow = setWorkflowInput(workflow, "3", "seed", 12345);
workflow = setWorkflowInput(workflow, "6", "text", "a beautiful landscape");
ジョブステータスの確認
ジョブの完了をポーリングします。
Job Status Values:
The API returns one of the following status values:
| 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 |
# Poll for job completion
curl -X GET "$BASE_URL/api/job/{prompt_id}/status" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY"
# Response examples:
# {"status": "pending"} - Job is queued
# {"status": "in_progress"} - Job is currently running
# {"status": "completed"} - Job finished successfully
# {"status": "failed"} - Job encountered an error
# {"status": "cancelled"} - Job was cancelled
リアルタイム進捗のための WebSocket
リアルタイムの実行更新を取得するために WebSocket に接続します。
clientId パラメータは現在無視されます—ユーザーのすべての接続が同じメッセージを受け取ります。前方互換性のために、一意の clientId を渡してください。
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(`Job did not complete within ${timeout / 1000}s`));
}, timeout);
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
const msgType = data.type;
const msgData = data.data ?? {};
// Filter to our job
if (msgData.prompt_id !== promptId) return;
if (msgType === "executing") {
const node = msgData.node;
if (node) {
console.log(`Executing node: ${node}`);
} else {
console.log("Execution complete");
}
} else if (msgType === "progress") {
console.log(`Progress: ${msgData.value}/${msgData.max}`);
} else if (msgType === "executed" && msgData.output) {
outputs[msgData.node] = msgData.output;
} else if (msgType === "execution_success") {
console.log("Job completed successfully!");
clearTimeout(timer);
ws.close();
resolve(outputs);
} else if (msgType === "execution_error") {
const errorMsg = msgData.exception_message ?? "Unknown error";
clearTimeout(timer);
ws.close();
reject(new Error(`Execution error: ${errorMsg}`));
}
};
ws.onerror = (err) => {
clearTimeout(timer);
reject(err);
};
});
}
// Wait for completion and collect outputs
const outputs = await listenForCompletion(promptId);
WebSocket メッセージタイプ
特に記載がない限り、メッセージは JSON テキストフレームとして送信されます。
| タイプ | 説明 |
|---|
status | queue_remaining カウントを含むキュー状態更新 |
notification | ユーザーフレンドリーな状態メッセージ(value フィールドには “Executing workflow…” などのテキストが含まれます) |
execution_start | ワークフロー実行が開始されました |
executing | 特定のノードが現在実行中です(node フィールドのノード ID) |
progress | ノード内のステップ進捗(サンプリングステップの value/max) |
progress_state | ノードメタデータを含む拡張進捗状態(ネストされた nodes オブジェクト) |
executed | ノードが出力付きで完了しました(output フィールドの画像、動画など) |
execution_cached | 出力がキャッシュされているためスキップされたノード(nodes 配列) |
execution_success | ワークフロー全体が正常に完了しました |
execution_error | ワークフローが失敗しました(exception_type、exception_message、traceback を含む) |
execution_interrupted | ワークフローがユーザーによってキャンセルされました |
バイナリメッセージ(プレビュー画像)
画像生成中、ComfyUI はプレビュー画像を含むバイナリ WebSocket フレームを送信します。これらは生のバイナリデータです(JSON ではありません):
| バイナリタイプ | 値 | 説明 |
|---|
PREVIEW_IMAGE | 1 | 拡散サンプリング中の進行中プレビュー |
TEXT | 3 | ノードからのテキスト出力(進捗テキスト) |
PREVIEW_IMAGE_WITH_METADATA | 4 | ノードコンテキストメタデータ付きプレビュー画像 |
バイナリフレーム形式(すべての整数はビッグエンディアン):
| オフセット | サイズ | フィールド | 説明 |
|---|
| 0 | 4 バイト | type | 0x00000001 |
| 4 | 4 バイト | image_type | 形式コード(1=JPEG, 2=PNG) |
| 8 | 可変 | image_data | 生の画像バイト |
| オフセット | サイズ | フィールド | 説明 |
|---|
| 0 | 4 バイト | type | 0x00000003 |
| 4 | 4 バイト | node_id_len | node_id 文字列の長さ |
| 8 | N バイト | node_id | UTF-8 エンコードされたノード ID |
| 8+N | 可変 | text | UTF-8 エンコードされた進捗テキスト |
| オフセット | サイズ | フィールド | 説明 |
|---|
| 0 | 4 バイト | type | 0x00000004 |
| 4 | 4 バイト | metadata_len | メタデータ JSON の長さ |
| 8 | N バイト | metadata | UTF-8 JSON(下記参照) |
| 8+N | 可変 | image_data | 生の JPEG/PNG バイト |
メタデータ JSON 構造:{
"node_id": "3",
"display_node_id": "3",
"real_node_id": "3",
"prompt_id": "abc-123",
"parent_node_id": null
}
出力のダウンロード
ジョブ完了後に生成されたファイルを取得します。
# Download a single output file (follow 302 redirect with -L)
curl -L "$BASE_URL/api/view?filename=output.png&subfolder=&type=output" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY" \
-o output.png
完全なエンドツーエンドの例
すべてをまとめた完全な例を以下に示します:
const BASE_URL = "https://cloud.comfy.org";
const API_KEY = process.env.COMFY_CLOUD_API_KEY!;
function getHeaders(): HeadersInit {
return { "X-API-Key": API_KEY, "Content-Type": "application/json" };
}
async function submitWorkflow(workflow: Record<string, any>): Promise<string> {
const response = await fetch(`${BASE_URL}/api/prompt`, {
method: "POST",
headers: getHeaders(),
body: JSON.stringify({ prompt: workflow }),
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);
return (await response.json()).prompt_id;
}
async function waitForCompletion(
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("Job timed out"));
}, timeout);
ws.onmessage = (event) => {
const data = JSON.parse(event.data);
if (data.data?.prompt_id !== promptId) return;
const msgType = data.type;
const msgData = data.data ?? {};
if (msgType === "progress") {
console.log(`Progress: ${msgData.value}/${msgData.max}`);
} else if (msgType === "executed" && msgData.output) {
outputs[msgData.node] = msgData.output;
} else if (msgType === "execution_success") {
clearTimeout(timer);
ws.close();
resolve(outputs);
} else if (msgType === "execution_error") {
clearTimeout(timer);
ws.close();
reject(new Error(msgData.exception_message ?? "Unknown error"));
}
};
ws.onerror = (err) => {
clearTimeout(timer);
reject(err);
};
});
}
async function downloadOutputs(
outputs: Record<string, any>,
outputDir: string
): Promise<void> {
for (const nodeOutputs of Object.values(outputs)) {
for (const key of ["images", "video", "audio"]) {
for (const fileInfo of (nodeOutputs as any)[key] ?? []) {
const params = new URLSearchParams({
filename: fileInfo.filename,
subfolder: fileInfo.subfolder ?? "",
type: fileInfo.type ?? "output",
});
// Get redirect URL (don't follow to avoid sending auth to storage)
const response = await fetch(`${BASE_URL}/api/view?${params}`, {
headers: { "X-API-Key": API_KEY },
redirect: "manual",
});
if (response.status !== 302) throw new Error(`HTTP ${response.status}`);
const signedUrl = response.headers.get("location")!;
// Fetch from signed URL without auth headers
const fileResponse = await fetch(signedUrl);
if (!fileResponse.ok) throw new Error(`HTTP ${fileResponse.status}`);
const path = `${outputDir}/${fileInfo.filename}`;
await writeFile(path, Buffer.from(await fileResponse.arrayBuffer()));
console.log(`Downloaded: ${path}`);
}
}
}
}
async function main() {
// 1. Load workflow
const workflow = JSON.parse(await readFile("workflow_api.json", "utf-8"));
// 2. Modify workflow parameters
workflow["3"].inputs.seed = 42;
workflow["6"].inputs.text = "a beautiful sunset over mountains";
// 3. Submit workflow
const promptId = await submitWorkflow(workflow);
console.log(`Job submitted: ${promptId}`);
// 4. Wait for completion with progress
const outputs = await waitForCompletion(promptId);
console.log(`Job completed! Found ${Object.keys(outputs).length} output nodes`);
// 5. Download outputs
await downloadOutputs(outputs, "./outputs");
console.log("Done!");
}
main();
キュー管理
キュー状態の取得
curl -X GET "$BASE_URL/api/queue" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY"
ジョブのキャンセル
curl -X POST "$BASE_URL/api/queue" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY" \
-H "Content-Type: application/json" \
-d '{"delete": ["PROMPT_ID_HERE"]}'
現在の実行の中断
curl -X POST "$BASE_URL/api/interrupt" \
-H "X-API-Key: $COMFY_CLOUD_API_KEY"
エラーハンドリング
HTTP エラー
REST API エンドポイントは標準的な HTTP ステータスコードを返します:
| ステータス | 説明 |
|---|
400 | 無効なリクエスト(不正なワークフロー、欠落したフィールド) |
401 | 未認証(無効または欠落した API キー) |
402 | クレジット不足 |
429 | サブスクリプションが非アクティブ |
500 | 内部サーバーエラー |
実行エラー
ワークフロー実行中、エラーは execution_error WebSocket メッセージを介して配信されます。exception_type フィールドはエラーカテゴリを識別します:
| 例外タイプ | 説明 |
|---|
ValidationError | 無効なワークフローまたは入力 |
ModelDownloadError | 必要なモデルが利用できないか、ダウンロードに失敗 |
ImageDownloadError | URL から入力画像のダウンロードに失敗 |
OOMError | GPU メモリ不足 |
InsufficientFundsError | アカウント残高が低すぎる(パートナーノード用) |
InactiveSubscriptionError | サブスクリプションがアクティブでない |