> ## Documentation Index
> Fetch the complete documentation index at: https://comfyuiwiki.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Comfy SDKs

> Python 또는 TypeScript로 Comfy Cloud, 자체 배포 또는 자체 ComfyUI를 대상으로 ComfyUI 워크플로를 실행하고, 에셋, 작업, 라이브 이벤트, 멱등 재시도를 다룹니다.

<Warning>
  **베타.** SDK와 SDK가 호출하는 Comfy API v2는 아직 1.0 이전입니다. API의 형태는 안정화되기 전에 변경될 수 있습니다. 문제는 [피드백](#피드백)을 통해 알려주세요.
</Warning>

**하나의 패키지, 두 개의 표면.** `comfy-sdk`(PyPI)와 `@comfyorg/sdk`(npm)는 서로 다른 두 서비스와 통신하는 두 개의 클라이언트를 제공합니다. 메서드 이름이 양쪽에서 겹치지만(`run`, `submit`, `events`) 각각 다른 의미를 가지므로, 스니펫을 복사하기 전에 그 코드가 어떤 클라이언트를 만드는지 확인하세요.

| 표면                                                                     | 기능                                                                             | 접근 방법                                                                                                  | 기본 URL                                                                  | 인증                                                  |
| ---------------------------------------------------------------------- | ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------ | ----------------------------------------------------------------------- | --------------------------------------------------- |
| **[Comfy Router](/ko/development/comfy-router/quickstart)**            | 해당 공급자의 자체 요청 본문으로 파트너 모델(FLUX, Veo, Gemini, Kling)을 호출하고, 그 고유한 응답을 그대로 반환합니다 | Python: `Comfy()`의 `client.models`. TypeScript: 모듈 수준 `comfy` 네임스페이스의 `comfy.models`                   | `https://api.comfy.org`, 라우트 `/v2/models/{provider}/{model}`            | `COMFY_API_KEY`, 또는 `comfy.config({ credentials })` |
| **[Comfy Cloud 및 Comfy API v2](/ko/development/api-development/sdks)** | API 형식 ComfyUI 워크플로를 처음부터 끝까지 실행합니다: 에셋 업로드, 그래프 제출, 작업 추적, 출력 다운로드            | `Comfy(api_key=...)` / `new Comfy({ apiKey })`, 그다음 `client.workflows`, `client.assets`, `client.jobs` | 기본값은 `https://cloud.comfy.org`이며, `COMFY_BASE_URL`이 지정하는 주소도 사용할 수 있습니다 | 생성자의 `api_key` / `apiKey`                           |

어느 표면도 다른 쪽을 감싸지 않으며, [Comfy 워크스페이스](https://platform.comfy.org/profile/api-keys)에서 생성한 API 키 하나로 둘 다 사용할 수 있습니다.

<Note>
  두 언어는 Router 표면을 서로 다르게 노출합니다. Python에서는 `Comfy()` 하나가 둘 다 담당합니다. Router에는 `client.models.run(...)`, Cloud에는 `client.workflows` / `client.assets` / `client.jobs`를 사용합니다. TypeScript에서는 의도적으로 비슷한 이름을 가진 별도의 export입니다. `comfy`(소문자, 모듈 수준 네임스페이스)에는 `comfy.models`가 있고, `Comfy`(클래스)는 Cloud 클라이언트이며 `.models`가 없습니다.
</Note>

이 페이지에서는 두 번째 행, 즉 Comfy Cloud와 Comfy API v2 클라이언트를 다룹니다. 모델 라우터에 대해서는 [Comfy Router 빠른 시작](/ko/development/comfy-router/quickstart)에서 시작하세요.

Comfy SDK를 사용하면 애플리케이션에서 ComfyUI 워크플로를 실행하고 결과를 돌려받을 수 있습니다. 워크플로를 제출하면 ComfyUI가 실행하고 출력을 다운로드합니다. 동일한 코드가 Comfy Cloud 또는 직접 호스팅하는 ComfyUI 인스턴스에서 실행됩니다. 기본 URL만 변경됩니다.

SDK는 [Comfy API v2](/ko/api-reference/v2/overview)용 클라이언트입니다. Comfy API v2는 장기적으로 지원할 계획인 버전 관리되는 HTTP API입니다. ComfyUI의 새 릴리스는 이를 기반으로 구축된 통합을 깨뜨리지 않습니다.

이 방식으로 구축하는 것들:

* Blender나 Krita와 같은 다른 애플리케이션 내부에서 콘텐츠를 생성하는 플러그인
* 사용자를 대신하여 생성 작업을 실행하는 소비자 앱
* 배치 파이프라인, 예를 들어 비디오의 모든 프레임에 워크플로 하나를 실행하는 경우
* 한 번에 많은 워크플로를 동시에 실행해야 하는 백엔드 서비스

<Note>
  이 SDK는 ComfyUI를 **외부에서** 구동합니다. ComfyUI **내부에서** 실행되는 커스텀 노드나 프런트엔드 확장 프로그램을 작성하는 경우에는 [커스텀 노드 개발](/ko/custom-nodes/overview)을 대신 참조하세요. 이들은 별도의 API 집합입니다.
</Note>

## 설치

<CodeGroup>
  ```bash Python theme={null}
  pip install comfy-sdk
  ```

  ```bash TypeScript theme={null}
  npm i @comfyorg/sdk
  ```
</CodeGroup>

Python 3.10 이상. Node 22 이상.

<Note>
  **현재 릴리스: 0.4.0.** PyPI의 [`comfy-sdk`](https://pypi.org/project/comfy-sdk/)와 npm의 [`@comfyorg/sdk`](https://www.npmjs.com/package/@comfyorg/sdk)는 함께 릴리스되며 동일한 버전 번호를 공유합니다. 최신 버전을 설치하거나(`pip install comfy-sdk`, `npm install @comfyorg/sdk`), 정확한 고정 대신 범위를 지정하세요. 두 생태계는 이를 다르게 표기합니다. `comfy-sdk>=0.4`는 하한이며 이후 마이너 버전을 허용하지만, `@comfyorg/sdk@^0.4`는 `0.4.x`에 대한 npm의 호환 범위로 `0.5.0` 직전에서 멈추므로, 새 마이너 버전이 나오면 캐럿 범위를 올려야 합니다. npm 쪽도 이후 마이너 버전을 따라가게 하려면 `@comfyorg/sdk@>=0.4.0`을 사용하세요. 이 안내가 뒤처져 있다면 레지스트리 페이지가 우선입니다.
</Note>

## 빠른 시작

입력 이미지를 업로드하고 워크플로를 실행한 다음 결과를 디스크에 기록합니다.

<CodeGroup>
  ```python Python theme={null}
  from comfy_sdk import Comfy

  # Comfy Cloud
  client = Comfy(api_key="comfyui-...")

  wf = client.workflows.from_file("workflow_api.json")

  asset = client.assets.from_file("photo.png")
  wf.set_input("10", "image", asset)

  job = client.run(wf)
  for output in job.get_outputs("9"):
      output.to_file(output.name)
  ```

  ```typescript TypeScript theme={null}
  import { Comfy } from "@comfyorg/sdk";

  // Comfy Cloud
  const client = new Comfy({ apiKey: "comfyui-..." });

  const wf = await client.workflows.fromFile("workflow_api.json");

  const asset = client.assets.fromFile("photo.png");
  wf.setInput("10", "image", asset);

  const job = await client.run(wf);
  await job.getOutputs("9")[0].toFile("out.png");
  ```
</CodeGroup>

`workflow_api.json`은 [API 형식](/ko/development/api-development/workflow-api-format)으로 저장된 워크플로입니다. `"10"`과 `"9"`는 해당 파일의 노드 ID로, 입력 이미지를 받는 노드와 결과를 가져올 출력 노드를 나타냅니다.

에셋 핸들은 지연 방식으로 동작합니다. `photo.png`는 로컬에서 해시되며 서버에 해당 바이트가 없을 때만 업로드되므로, 동일한 입력으로 다시 실행해도 비용이 들지 않습니다.

`run()`은 작업을 제출하고 터미널 상태에 도달할 때까지 대기합니다. 실행되는 동안 다른 작업을 수행하려면 `submit()`을 대신 사용하고 [이벤트 스트림](#작업-실행-보기)을 확인하세요.

대신 자체 ComfyUI를 대상으로 실행하려면 `COMFY_BASE_URL`을 설정하고 키를 제거하세요. 아래를 참조하세요.

## 기본 URL 선택

| 연결 대상            | 기본 URL                               | API 키                      |
| ---------------- | ------------------------------------ | -------------------------- |
| **Comfy Cloud**  | `https://cloud.comfy.org` (기본값)      | 필수                         |
| **Comfy API 배포** | `https://<deployment>.run.comfy.app` | 필수                         |
| **자체 ComfyUI**   | `http://127.0.0.1:8189` (로컬 프록시)     | 기본적으로 없음. 선택적 정적 Bearer 토큰 |

기본 URL은 생성자 인자가 아닌 `COMFY_BASE_URL` 환경 변수에서 가져옵니다:

```bash theme={null}
export COMFY_BASE_URL="https://<deployment>.run.comfy.app"  # Comfy API 배포
export COMFY_BASE_URL="http://127.0.0.1:8189"               # 자체 호스팅 프록시
```

이 값은 클라이언트가 생성될 때마다 읽히며, `http(s)` URL이어야 합니다. 설정되지 않았거나 비어 있으면 Comfy Cloud를 의미합니다. 따라서 클라이언트 자체는 어디서나 동일합니다:

<CodeGroup>
  ```python Python theme={null}
  client = Comfy(api_key="comfyui-...")
  ```

  ```typescript TypeScript theme={null}
  const client = new Comfy({ apiKey: "comfyui-..." });
  ```
</CodeGroup>

<Note>
  초기 빌드에서 업그레이드하시나요? `Comfy("<url>", "<key>")`는 이제 `COMFY_BASE_URL`을 설정한 상태의 `Comfy(api_key="<key>")`입니다. `api_key`는 키워드 전용이므로, 이전의 위치 기반 호출은 URL을 키로 조용히 읽어들이는 대신 `TypeError`를 발생시킵니다.
</Note>

### Comfy Cloud

즉시 사용할 수 있습니다. [API 키](/ko/development/api-development/getting-an-api-key)를 생성하여 클라이언트에 전달하세요.

<Note>
  API 액세스에는 유료 Comfy Cloud 구독이 필요합니다. 무료 티어에는 포함되지 않습니다. 동시에 실행할 수 있는 작업 수는 티어에 따라 다릅니다. [병렬 실행](/ko/development/deploy/cloud#병렬-실행-동시-작업)를 참조하세요.
</Note>

<a id="serverless-deployment" />

### Comfy API 배포

[개발자 플랫폼](https://platform.comfy.org)을 통해 배포한 워크플로에는 자체 엔드포인트가 제공됩니다. `COMFY_BASE_URL`을 해당 엔드포인트로 지정하고 Comfy Cloud와 동일하게 API 키를 사용하세요. 이 가이드의 모든 내용이 동일하게 작동합니다.

Comfy API 배포는 Build에 포함된 모델과 커스텀 노드를 사용하여 여러 워크플로를 실행할 수 있습니다. 각 작업에 대해 `get_workflow()`는 `format: "api"`를 가지며 실행된 그래프를 `.graph` 속성에 담은 워크플로 응답을 반환합니다.

### 자체 ComfyUI

베타 기간 동안 v2 API는 ComfyUI와 함께 실행되는 작은 오픈소스 서비스인 [comfy-api-proxy](https://github.com/Comfy-Org/comfy-api-proxy)가 제공합니다. 설치하고 실행한 다음 `COMFY_BASE_URL="http://127.0.0.1:8189"`를 설정하세요:

```bash theme={null}
pip install comfy-api-proxy
comfy-api-proxy
export COMFY_BASE_URL="http://127.0.0.1:8189"
```

설정, 인증, 그리고 이 프록시가 필요한 이유는 [자체 호스팅 ComfyUI용 API 프록시](/ko/development/comfyui-server/api-proxy)를 참고하세요. 이는 임시 수단이며, v2 API가 안정화되면 ComfyUI 코어로 옮겨가고 프록시는 더 이상 필요하지 않습니다.

## 제출 재시도: 멱등성 키

`submit()`과 `run()`은 제출할 때마다 `Idempotency-Key`를 전송하며, 이 키에 대한 Comfy API v2 계약은 **중복 시 거부이며, 기록 후 재생이 아닙니다**. submit을 재시도 루프로 감싸기 전에 이 내용을 먼저 읽어 보세요.

* **호출할 때마다 새 키가 발급됩니다.** 같은 워크플로로 `submit()`을 두 번 호출하면 제출 두 번, 작업 두 개, 청구 두 번입니다. `submit()`을 감싼 순진한 `for attempt in range(3)`는 재시도가 아니라 이중 청구입니다.
* **재사용한 키는 재생되지 않고 거부됩니다.** 재시도를 멱등하게 만들려면 직접 `idempotency_key`(TypeScript에서는 `idempotencyKey`)를 전달하세요. 그러면 해당 키를 사용한 두 번째 요청은 첫 번째 작업을 반환하는 대신 `422 idempotency_key_reuse`로 실패합니다. SDK는 `IdempotencyKeyReuse`를 발생시킵니다. 이는 "멱등 재시도"가 보통 의미하는 것과 반대이므로 명시적으로 처리해야 합니다.
* **복구 방법은 다시 제출하는 것이 아니라 작업을 찾아가는 것입니다.** `IdempotencyKeyReuse`가 발생하면 첫 번째 시도가 작업을 생성했을 가능성이 충분히 있습니다. `client.jobs.get(job_id)`로 해당 작업을 가져오세요. 이 조회에는 이미 저장해 둔 id가 필요하므로, 제출이 반환된 뒤 실패 전에 id를 영속화한 경우에만 복구할 수 있습니다. id가 기록되기 전에 연결이 끊어졌다면 조회할 대상도, 자동 복구도 없습니다. 아래 예제는 점유된 키로 다시 제출하는 대신 수동 처리를 위해 예외를 다시 발생시킵니다.
* **제출이 확실히 실패하면 키가 해제됩니다.** 검증 오류, 크레딧 부족으로 인한 거부, 실행 대기열 가득 참으로 인한 거부는 작업을 생성하지 않고 키를 해제하므로, 그 키로 다시 제출해도 괜찮습니다. *모호한* 실패(읽기 타임아웃, 요청 도중 끊긴 연결) 이후에는 키가 계속 점유된 상태로 남습니다. 다시 제출하지 말고 작업을 찾으세요.
* **키는 24시간 후 만료되며**, 비어 있지 않은 출력 가능 ASCII여야 하고 길이 제한을 넘지 않아야 합니다. 유효하지 않은 키는 요청이 전송되기 전에 `ValueError`를 발생시키므로, 명시적인 `""`가 조용히 발급된 키로 대체되는 일은 없습니다.

따라서 두 번 이상 실행해도 안전한 재시도는 시도 간에 두 가지를 유지해야 합니다. 키는 서버가 재시도와 새 제출을 구분할 수 있게 해 주고, 작업 ID는 점유된 키가 이미 생성한 작업을 찾을 수 있게 해 줍니다.

<CodeGroup>
  ```python Python theme={null}
  import uuid
  from comfy_sdk import IdempotencyKeyReuse

  # 두 값 모두 요청이 당신에게 의미하는 바를 기준으로 당신의 저장소에 보관합니다.
  # `key`는 첫 번째 시도에서 한 번만 발급되고, `job_id`는 submit이 반환되는 즉시
  # 채워집니다.
  state = load_submission_state()  # {"key": ..., "job_id": ...} or {}
  key = state.get("key") or str(uuid.uuid4())
  save_submission_state(key=key)

  try:
      job = client.submit(wf, idempotency_key=key)
      save_submission_state(key=key, job_id=job.id)
  except IdempotencyKeyReuse:
      # 이 키를 사용한 이전 시도가 이미 제출까지 도달했으므로 작업이 존재할 수
      # 있습니다. 다시 제출하지 말고 찾아가세요.
      job_id = state.get("job_id")
      if job_id is None:
          raise  # 조회할 기록이 없음. 사람의 개입이 필요합니다
      job = client.jobs.get(job_id)
  ```

  ```typescript TypeScript theme={null}
  import { IdempotencyKeyReuse } from "@comfyorg/sdk";

  // 두 값 모두 요청이 당신에게 의미하는 바를 기준으로 당신의 저장소에 보관합니다.
  // `key`는 첫 번째 시도에서 한 번만 발급되고, `jobId`는 submit이 반환되는 즉시
  // 채워집니다.
  const state = await loadSubmissionState(); // { key?, jobId? }
  const key = state.key ?? crypto.randomUUID();
  await saveSubmissionState({ key });

  let job;
  try {
    job = await client.submit(wf, { idempotencyKey: key });
    await saveSubmissionState({ key, jobId: job.id });
  } catch (err) {
    // 이 키를 사용한 이전 시도가 이미 제출까지 도달했으므로 작업이 존재할 수
    // 있습니다. 다시 제출하지 말고 찾아가세요.
    if (!(err instanceof IdempotencyKeyReuse) || !state.jobId) throw err;
    job = await client.jobs.get(state.jobId);
  }
  ```
</CodeGroup>

`client.jobs.get(job_id)`는 SDK의 재수화 경로이며 id가 필요합니다. 그래서 submit이 반환되는 순간 id를 기록하는 것이 이 복구를 가능하게 하는 핵심입니다. `POST /api/v2/jobs`의 전체 키 계약은 [Comfy API v2](/ko/api-reference/v2/overview)를 참고하세요.

<Note>
  Comfy Router의 `Idempotency-Key`는 **다르게** 동작합니다. Router에서 이 키는 일회용 토큰이 아니라 재생 핸들입니다. 같은 키로 대기 중인 제출을 다시 보내면 두 번째 요청을 실행 대기열에 넣는 대신 원래 요청을 반환합니다. [대기 중 멱등성 및 과금](/ko/development/comfy-router/queue#멱등성-및-과금)과 [Router 재시도 결과](/ko/development/comfy-router/errors#재시도-결과)를 참고하세요. 이 두 표면은 계약이 아니라 헤더 이름만 공유합니다.
</Note>

## 작업 실행 보기

`job.events()`는 작업 상태의 라이브 스트림을 제공합니다. 노드와 단계 진행 상황, 미리보기 프레임, 그리고 각 출력이 커밋되는 순간을 보여줍니다. 연결이 끊어지면 자동으로 다시 연결됩니다.

<CodeGroup>
  ```python Python theme={null}
  from comfy_sdk import Progress, Preview, OutputReady, StatusChange

  job = client.submit(wf)

  for event in job.events():
      match event:
          case Progress() as p:
              print(f"{p.value:.0%} {p.message}")
          case Preview() as pv:
              image = pv.to_pil()
          case OutputReady() as o:
              o.output.to_file(f"partial/{o.output.name}")
          case StatusChange(status="succeeded"):
              break

  result = job.result()
  ```

  ```typescript TypeScript theme={null}
  const job = await client.submit(wf);

  // 라벨이 필요합니다: switch 안의 일반 `break`는 루프가 아니라
  // switch만 빠져나갑니다.
  eventLoop: for await (const event of job.events()) {
    switch (event.kind) {
      case "progress":
        console.log(event.value);
        break;
      case "outputReady":
        await event.output.toFile(`${event.output.name}`);
        break;
      case "statusChange":
        if (event.status === "succeeded") break eventLoop;
    }
  }
  ```
</CodeGroup>

`Preview.to_pil()`에는 선택적 Pillow extra가 필요합니다: `pip install "comfy-sdk[pil]"`.

`result()`는 완료된 작업을 반환하거나, 실행이 실패한 경우 노드 수준의 세부 정보와 함께 `JobFailed`를 발생시킵니다. 전체 이벤트 카탈로그는 해당 언어의 [SDK README](#참조)를 참조하세요.

### `events()`는 `subscribe()`가 아닙니다

두 인터페이스에 걸쳐 이름이 비슷한 세 가지가 존재하며, 이 페이지에 나오는 것은 그중 하나뿐입니다.

| 호출                                                             | 인터페이스                                      | 제공하는 항목                                                                                                  |
| -------------------------------------------------------------- | ------------------------------------------ | -------------------------------------------------------------------------------------------------------- |
| `job.events()`                                                 | Comfy Cloud(이 페이지)                         | 워크플로 작업 하나의 라이브 SSE 스트림: `Progress`, `Preview`, `OutputReady`, `StatusChange`. 자동으로 다시 연결하고, 폴링으로 대체합니다. |
| `handle.events()`(TypeScript) / `handle.iter_events()`(Python) | [큐 전송](/ko/development/comfy-router/queue) | 하나의 Router 요청에 대한 실행 대기열 관찰: 상태와 대기열 위치. 상태 라우트를 폴링하며, 스트림이 없고 진행 상황이나 미리보기 이벤트도 없습니다.                   |
| `comfy.models.subscribe(...)`                                  | [큐 전송](/ko/development/comfy-router/queue) | 반복자가 아닙니다. 한 번의 호출로 제출하고 폴링하고 수집하며, `on_queue_update` / `onQueueUpdate` 콜백과 함께 결과를 반환합니다.                |

Comfy Cloud 클라이언트에는 `subscribe()`가 없으며, 어디에도 `job.subscribe()`는 없습니다. `subscribe`에 해당하는 클라우드 버전은 `run()`입니다: 제출하고 터미널 상태를 기다립니다.

스트림은 재생 가능한 로그가 아니라 실시간 피드입니다. 결과를 위해 의존할 수 있도록 존재하는 것이 아니라, 진행 상황을 표시하기 위해 존재합니다. 작업을 폴링하는 것이 가장 신뢰할 수 있는 정보이며, `run()`, `wait()`, `result()`는 자동으로 폴링을 사용합니다. 그 이유는 [설계 노트](/ko/development/api-development/sdks-design#폴링-우선-진행-상황은-스트리밍으로)를 참조하세요.

## 출력을 해당 워크플로까지 역추적하기

출력에는 해당 출력을 생성한 작업의 id가 담겨 있으므로, 별도의 보조 테이블을 유지하지 않고도 파일에서 시작해 작업까지 역추적할 수 있습니다.

<CodeGroup>
  ```python Python theme={null}
  output = job.outputs[0]
  output.job_id          # 이 파일을 생성한 작업
  ```

  ```typescript TypeScript theme={null}
  const output = job.outputs[0];
  output.jobId; // 이 파일을 생성한 작업
  ```
</CodeGroup>

동일한 id는 단독으로 가져온 에셋에도 존재하므로, 나중에 찾은 파일도 여전히 해당 작업까지 거슬러 올라갈 수 있습니다. 직접 업로드한 에셋의 경우 id는 `None`(TypeScript: `undefined`)이며, 이는 해당 에셋을 생성한 작업이 없기 때문입니다.

작업에서는 해당 작업의 기반이 된 워크플로를 요청할 수 있습니다. 이 기능은 이 프로세스에서 제출한 것이 아니라 id로 복원한 작업에서도 작동합니다:

<CodeGroup>
  ```python Python theme={null}
  wf = job.get_workflow()

  if wf.format == "save":
      ...  # 작성된 그대로의 워크플로, 캔버스 레이아웃과 Note 노드 유지
  else:
      ...  # 실행된 API 형식 그래프
  ```

  ```typescript TypeScript theme={null}
  const wf = await job.getWorkflow();

  if (wf.format === "save") {
    // 작성된 그대로의 워크플로, 캔버스 레이아웃과 Note 노드 유지
  } else {
    // 실행된 API 형식 그래프
  }
  ```
</CodeGroup>

**항상 `format`으로 분기하세요.** 반환되는 형태는 작업이 제출된 방식에 따라 달라지며, 요청별로 제어할 수 있는 항목에 따라 달라지지 않습니다:

| `format` | 반환되는 내용                                                       | 적용 시기                                     |
| -------- | ------------------------------------------------------------- | ----------------------------------------- |
| `save`   | 작업이 실행된 버전의 작성용 워크플로. 캔버스 레이아웃과 Note와 같은 편집기 전용 노드가 그대로 포함됩니다 | 워크플로 버전을 고정하는 Comfy Cloud 편집기에서 제출된 작업    |
| `api`    | 실행된 그래프. 편집기 전용 구성 요소는 제거되고 Get/Set 노드가 확장됩니다                 | 그 외 모든 경우. 현재 이 SDK를 통해 제출되는 모든 작업을 포함합니다 |

SDK를 통해 제출하는 작업은 항상 `api`를 반환합니다. v2 제출에는 아직 버전 고정 필드가 없기 때문입니다. 이는 변경될 예정입니다. 판별자가 있는 이유는 코드가 변경되지 않아도 되도록 하기 위해서입니다.

## 현재 SDK가 다루는 범위

첫 번째 버전은 한 가지 작업을 제대로 수행합니다. 워크플로를 실행하고 결과를 돌려받는 것입니다.

* **에셋.** 파일, 바이트, 스트림 또는 URL에서 입력 핸들을 생성합니다. 핸들은 지연(lazy) 방식이며 콘텐츠 주소 기반이므로 동일한 입력으로 다시 실행해도 다시 업로드되지 않습니다.
* **제출.** API 형식의 그래프를 제출합니다. 제출은 멱등적이며, 실행 대기열이 가득 찬 경우 제한된 예산 내에서 자동으로 재시도됩니다.
* **실행.** `wait()`으로 폴링하거나 `events()`를 통해 실시간 진행 상황을 추적합니다.
* **출력.** 디스크에 쓰거나, 메모리에 버퍼링하거나, 바이트 범위를 가져오거나, 단기 다운로드 URL을 받을 수 있습니다. `getDownloadUrl()`은 API 키 없이 누구나 읽을 수 있는 서명된 URL을 반환하며, 약 6시간 동안 유효합니다. URL을 저장하기 전에 [출력 URL과 유효 기간](/ko/api-reference/v2/overview#출력-url과-유지-기간)을 먼저 읽어보세요. 나중에도 출력을 계속 보여주려면 바이트를 다시 호스팅하거나 필요할 때 URL을 다시 발급받아야 합니다.
* **추적 가능성.** 모든 출력에는 해당 출력을 생성한 작업의 ID가 포함되며, 작업은 그 뒤에 있는 워크플로를 반환할 수 있습니다.
* **에셋 삭제.** 업로드한 에셋을 핸들이나 ID로 제거할 수 있습니다.
* **오류.** 원시 상태 코드 대신 `JobFailed`, `Unauthorized`, `InsufficientCredits`, `QueueFull`과 같은 타입화된 예외를 제공합니다.
* **취소.** 실행 중인 작업을 취소할 수 있습니다. TypeScript는 추가로 모든 호출에서 `AbortSignal`을 허용합니다.

Python은 동일한 API 표면(surface)을 가진 동기식 `Comfy` 클라이언트와 `AsyncComfy` 클라이언트를 모두 제공합니다. TypeScript는 비동기 전용입니다.

이 버전에는 포함되지 않는 것: 저장된 워크플로 관리, 모델 라이브러리, 노드 인트로스펙션, 명명된 워크플로 파라미터. [설계 노트](/ko/development/api-development/sdks-design#첫-번째-버전의-범위)에서 API 표면이 이렇게 작게 시작하는 이유를 설명합니다.

## 참조

SDK README는 인증, 에셋, 오류, 그리고 저수준 이스케이프 해치를 포함하여 각 언어에 대한 전체 참조 자료입니다.

<CardGroup cols={2}>
  <Card title="Python SDK" icon="python" href="https://github.com/Comfy-Org/comfy-python-sdk">
    PyPI의 <code>comfy-sdk</code>. 동기 및 비동기 클라이언트를 제공합니다.
  </Card>

  <Card title="TypeScript SDK" icon="js" href="https://github.com/Comfy-Org/comfy-typescript-sdk">
    npm의 <code>@comfyorg/sdk</code>. 타입이 지정된 비동기 클라이언트와 저수준 클라이언트를 제공합니다.
  </Card>

  <Card title="Comfy API v2 참조" icon="code" href="/ko/api-reference/v2/overview">
    두 SDK의 기반이 되는 HTTP API입니다. 어떤 언어에서든 직접 사용할 수 있습니다.
  </Card>

  <Card title="설계 노트" icon="compass" href="/ko/development/api-development/sdks-design">
    이 API가 존재하는 이유, 기존 ComfyUI API와의 관계, 그리고 앞으로의 계획을 설명합니다.
  </Card>

  <Card title="Comfy Router" icon="shuffle" href="/ko/development/comfy-router/quickstart">
    같은 패키지의 또 다른 표면입니다. Flux, Veo, Gemini 같은 파트너 모델에 대해 <code>comfy.models.run</code>을 실행합니다.
  </Card>
</CardGroup>

## 피드백

SDK는 아직 1.0 이전입니다. 메서드 이름, 클라이언트 형태, 이벤트 카탈로그, 오류 분류 체계, 에셋 처리 방식은 모두 여전히 바뀔 수 있으며, API 표면은 앞으로 몇 주 안에 안정화될 예정입니다. 일단 안정화되고 나면 장기 지원 약정 때문에 변경할 수 있는 범위가 제한됩니다.

어색한 부분, 기대했지만 찾지 못한 부분, 그리고 우회해서 해결해야 했던 부분을 알려주세요. [저희 Discord](https://discord.com/invite/comfyorg)의 `#developer-platform` 채널이 그런 피드백을 보내실 곳입니다.

다른 언어로 된 퍼스트파티 SDK를 원하신다면 그곳에서 말씀해 주세요. 두 SDK 모두 동일한 문서화된 HTTP 계약을 기반으로 하므로 어떤 언어든 오늘날 API와 통신할 수 있지만, 저희는 수요가 어디에 있는지 알고 싶습니다.
