メインコンテンツへスキップ
実験的 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"
    }
  }'
API キーは platform.comfy.org で生成してください。これは Cloud API 認証(X-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:
StatusDescription
pendingJob is queued and waiting to start
in_progressJob is currently executing
completedJob finished successfully
failedJob encountered an error
cancelledJob 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 テキストフレームとして送信されます。
タイプ説明
statusqueue_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_typeexception_messagetraceback を含む)
execution_interruptedワークフローがユーザーによってキャンセルされました

バイナリメッセージ(プレビュー画像)

画像生成中、ComfyUI はプレビュー画像を含むバイナリ WebSocket フレームを送信します。これらは生のバイナリデータです(JSON ではありません):
バイナリタイプ説明
PREVIEW_IMAGE1拡散サンプリング中の進行中プレビュー
TEXT3ノードからのテキスト出力(進捗テキスト)
PREVIEW_IMAGE_WITH_METADATA4ノードコンテキストメタデータ付きプレビュー画像
バイナリフレーム形式(すべての整数はビッグエンディアン):
オフセットサイズフィールド説明
04 バイトtype0x00000001
44 バイトimage_type形式コード(1=JPEG, 2=PNG)
8可変image_data生の画像バイト
各 JSON メッセージタイプの完全なスキーマ定義については、OpenAPI 仕様をご覧ください。

出力のダウンロード

ジョブ完了後に生成されたファイルを取得します。
# 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必要なモデルが利用できないか、ダウンロードに失敗
ImageDownloadErrorURL から入力画像のダウンロードに失敗
OOMErrorGPU メモリ不足
InsufficientFundsErrorアカウント残高が低すぎる(パートナーノード用)
InactiveSubscriptionErrorサブスクリプションがアクティブでない