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

# Comfy Router와 함께 GPT 4o 사용하기

> Comfy Router를 통해 openai/gpt-4o를 호출합니다: 엔드포인트, 요청 형태, 그리고 Router가 반환하는 응답.

`openai/gpt-4o`에 대한 API 레퍼런스로, Comfy Router가 OpenAI로부터 제공합니다.

## 빠른 시작

[Comfy 워크스페이스](https://platform.comfy.org/profile/api-keys)에서 키를 생성하고 `COMFY_API_KEY`로 내보내세요. Python과 TypeScript 스니펫은 Comfy SDK(`pip install comfy-sdk`, `npm install @comfyorg/sdk`)를 사용하며, cURL 스니펫은 동일한 호출을 raw HTTP로 수행한 것입니다.

**모델 ID:** `openai/gpt-4o`

**엔드포인트:** `POST https://api.comfy.org/v2/models/openai/gpt-4o`

<Tabs>
  <Tab title="Wait for the result">
    <CodeGroup>
      ```python Python theme={null}
      from comfy_sdk import Comfy

      # Reads COMFY_API_KEY from the environment.
      # The SDK automatically creates an idempotency key and reuses it for automatic retries.
      with Comfy() as client:
          result = client.models.run(
              "openai/gpt-4o",
              {
                  "input": "Reply with the single word: ok",
                  "max_output_tokens": 1024,
              },
          )

      print(result)
      ```

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

      // Reads COMFY_API_KEY from the environment.
      // The SDK automatically creates an idempotency key and reuses it for automatic retries.
      const { data } = await comfy.models.run("openai/gpt-4o", {
        input: "Reply with the single word: ok",
        max_output_tokens: 1024,
      });

      console.log(data);
      ```

      ```bash cURL theme={null}
      curl https://api.comfy.org/v2/models/openai/gpt-4o \
        -H "X-API-Key: $COMFY_API_KEY" \
        -H "Idempotency-Key: $(uuidgen)" \
        -H "Content-Type: application/json" \
        -d "{\"input\": \"Reply with the single word: ok\", \"max_output_tokens\": 1024}"
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Queue and collect later">
    동일한 본문을 `POST https://api.comfy.org/v2/models/openai/gpt-4o/requests` 로 보냅니다. Router는 실행이 접수되는 즉시 `201` 과 `request_id` 를 응답하며, 결과는 준비가 되는 대로 이 프로세스나 다른 프로세스에서 수집할 수 있습니다. 상태, 취소, 수집 방법은 [Queued delivery](/ko/development/comfy-router/queue) 를 참고하세요.

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

      # Reads COMFY_API_KEY from the environment.
      # Each submit() call mints its own Idempotency-Key and reuses it for automatic retries.
      with Comfy() as client:
          handle = client.models.submit(
              "openai/gpt-4o",
              {
                  "input": "Reply with the single word: ok",
                  "max_output_tokens": 1024,
              },
          )
          print("request_id:", handle.request_id)  # with the model ID, all another process needs

          # Poll until the request completes, waiting the Retry-After the server names.
          for update in handle.iter_events():
              print(update.status, update.queue_position)

          # The provider's own payload, the same value models.run() returns.
          # A request that failed or was cancelled raises the typed Router error here.
          result = handle.get()

      print(result)
      ```

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

      // Reads COMFY_API_KEY from the environment.
      // Each submit() call mints its own Idempotency-Key and reuses it for automatic retries.
      const handle = await comfy.models.submit("openai/gpt-4o", {
        input: "Reply with the single word: ok",
        max_output_tokens: 1024,
      });
      console.log("requestId:", handle.requestId); // with the model ID, all another process needs

      // Poll until the request completes, waiting the Retry-After the server names.
      for await (const update of handle.events()) {
        console.log(update.status, update.queuePosition);
      }

      // The same result models.run() returns. A request that failed or was cancelled rejects here.
      const result = await handle.get();

      console.log(result.data);
      ```

      ```bash cURL theme={null}
      # 1. Submit. Router answers 201 with request_id, status_url, response_url and cancel_url.
      curl https://api.comfy.org/v2/models/openai/gpt-4o/requests \
        -H "X-API-Key: $COMFY_API_KEY" \
        -H "Idempotency-Key: $(uuidgen)" \
        -H "Content-Type: application/json" \
        -d "{\"input\": \"Reply with the single word: ok\", \"max_output_tokens\": 1024}"

      # 2. Poll until status is COMPLETED, waiting the Retry-After seconds each response names.
      REQUEST_ID="<request_id from the 201 body>"
      curl -i https://api.comfy.org/v2/models/openai/gpt-4o/requests/$REQUEST_ID/status \
        -H "X-API-Key: $COMFY_API_KEY"

      # 3. Collect. 200 with the model's native output, 202 with the status body while it is still running.
      curl https://api.comfy.org/v2/models/openai/gpt-4o/requests/$REQUEST_ID \
        -H "X-API-Key: $COMFY_API_KEY"
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Schema

### Input

<ParamField body="include" type="string[]">
  Additional output data to include in the model response.
</ParamField>

<ParamField body="input" type="string | object[]" required>
  Text, image or file inputs to the model, used to generate a response. The one field of this contract Router cannot supply, and the only entry in `required` below.
</ParamField>

<ParamField body="instructions" type="string">
  Inserts a system (or developer) message as the first item in the model's context.
</ParamField>

<ParamField body="max_output_tokens" type="integer">
  An upper bound for the number of tokens generated for a response, including visible output tokens and reasoning tokens. On a reasoning id this ceiling is shared with the hidden reasoning tokens, so a small value can consume the whole budget before any visible text -- which is why the reasoning smoke cases send 1024 where the chat ones send 16.

  Range: `1` to `…`
</ParamField>

<ParamField body="model" type="string">
  OpenAI model identifier. On Comfy Router this field is OPTIONAL and Router fills it from the `{model}` path segment; an explicit `null` is replaced the same way. Sending a value that disagrees with the path is refused.
</ParamField>

<ParamField body="parallel_tool_calls" type="boolean">
  Whether to allow the model to run tool calls in parallel.
</ParamField>

<ParamField body="previous_response_id" type="string">
  The ID of a previous response, for multi-turn conversations.
</ParamField>

<ParamField body="reasoning" type="object">
  REASONING TIER ONLY. Configuration for reasoning models, e.g. `{"effort": "medium"}`. Forwarded unchanged; see OpenAI's reasoning guide for the accepted keys. A chat-tier id ignores it.
</ParamField>

<ParamField body="store" type="boolean">
  Whether OpenAI stores the generated response for later retrieval.
</ParamField>

<ParamField body="stream" type="boolean">
  Declared so a caller who sends it is not refused, but INERT on this surface: Router SETTLES it to `false` before dispatch, because it captures the provider response rather than relaying a `text/event-stream` -- which openAiResponsesProxy's ModifyResponse cannot decode, so a streamed generation would be billed by OpenAI and metered by nobody. Use `POST /proxy/openai/v1/responses` if you need the stream.
</ParamField>

<ParamField body="temperature" type="number">
  Sampling temperature. CHAT TIER ONLY: the o-series reasoning ids (`o1`, `o1-pro`, `o3`, `o4-mini`) reject this parameter at OpenAI. Router does not refuse it for them -- see this component's note on why the two tiers share one schema -- so a reasoning call that sends it is answered by OpenAI's own error.

  Range: `0` to `2`
</ParamField>

<ParamField body="text" type="object">
  Output-format configuration, e.g. `{"format": {"type": "json_schema", ...}}` for Structured Outputs. Forwarded unchanged.
</ParamField>

<ParamField body="tool_choice" type="string | object">
  How the model should select which tool to use. Either a string mode or an object naming a tool.
</ParamField>

<ParamField body="tools" type="object[]">
  Tool definitions the model may call. Router does not narrow the tool taxonomy; see OpenAI's Responses API reference for the accepted shapes.
</ParamField>

<ParamField body="top_p" type="number">
  Nucleus-sampling cutoff. CHAT TIER ONLY, on the same terms as `temperature`.

  Range: `0` to `1`
</ParamField>

<ParamField body="truncation" type="string">
  Truncation strategy when the context exceeds the model's window. The enum IS enforced here, unlike the three vocabularies above, because these two values are the complete set OpenAI documents and it has not grown. An explicit `null` is still accepted, on the same terms as the fields above it.

  Possible values: `auto`, `disabled`
</ParamField>

<ParamField body="usage" type="object">
  Token-usage envelope. Present on this contract because the v1 operation declares it on the request body; OpenAI populates it on the RESPONSE, so a caller has no reason to send it.
</ParamField>

Generated from the schema Router serves at `GET /v2/models/openai/gpt-4o/openapi.json`, the same document it validates a call against before the request reaches the provider.

### Output

<ResponseField name="instructions" type="string">
  Inserts a system (or developer) message as the first item in the model's context.

  When using along with `previous_response_id`, the instructions from a previous
  response will not be carried over to the next response. This makes it simple
  to swap out system (or developer) messages in new responses.
</ResponseField>

<ResponseField name="max_output_tokens" type="integer">
  An upper bound for the number of tokens that can be generated for a response, including visible output tokens and [reasoning tokens](https://platform.openai.com/docs/guides/reasoning).
</ResponseField>

<ResponseField name="model" type="string">
  The model used to generate the response
</ResponseField>

<ResponseField name="temperature" type="number" default="1">
  Controls randomness in the response

  Range: `0` to `2`
</ResponseField>

<ResponseField name="top_p" type="number" default="1">
  Controls diversity of the response via nucleus sampling

  Range: `0` to `1`
</ResponseField>

<ResponseField name="truncation" type="string" default="&#x22;disabled&#x22;">
  The truncation strategy to use for the model response.

  * `auto`: If the context of this response and previous ones exceeds
    the model's context window size, the model will truncate the
    response to fit the context window by dropping input items in the
    middle of the conversation.
  * `disabled` (default): If a model response will exceed the context window
    size for a model, the request will fail with a 400 error.

    Possible values: `auto`, `disabled`
</ResponseField>

<ResponseField name="previous_response_id" type="string">
  The unique ID of the previous response to the model. Use this to
  create multi-turn conversations. Learn more about
  [conversation state](https://platform.openai.com/docs/guides/conversation-state).
</ResponseField>

<ResponseField name="reasoning" type="object">
  **o-series models only**

  Configuration options for
  [reasoning models](https://platform.openai.com/docs/guides/reasoning).
</ResponseField>

<ResponseField name="reasoning.context" type="string">
  Controls which reasoning items are rendered back to the model on later turns, e.g. `auto`, `current_turn`, or `all_turns`.
</ResponseField>

<ResponseField name="reasoning.effort" type="string" default="&#x22;medium&#x22;">
  **o-series models only**

  Constrains effort on reasoning for
  [reasoning models](https://platform.openai.com/docs/guides/reasoning).
  Currently supported values are `low`, `medium`, and `high`. Reducing
  reasoning effort can result in faster responses and fewer tokens used
  on reasoning in a response.

  Possible values: `low`, `medium`, `high`
</ResponseField>

<ResponseField name="reasoning.generate_summary" type="string">
  **Deprecated:** use `summary` instead.

  A summary of the reasoning performed by the model. This can be
  useful for debugging and understanding the model's reasoning process.
  One of `auto`, `concise`, or `detailed`.

  Possible values: `auto`, `concise`, `detailed`
</ResponseField>

<ResponseField name="reasoning.mode" type="string">
  The reasoning mode used for the response.
</ResponseField>

<ResponseField name="reasoning.summary" type="string">
  A summary of the reasoning performed by the model. This can be
  useful for debugging and understanding the model's reasoning process.
  One of `auto`, `concise`, or `detailed`.

  Possible values: `auto`, `concise`, `detailed`
</ResponseField>

<ResponseField name="text" type="object" />

<ResponseField name="text.format" type="object">
  An object specifying the format that the model must output.

  Configuring `{ "type": "json_schema" }` enables Structured Outputs,
  which ensures the model will match your supplied JSON schema. Learn more in the
  [Structured Outputs guide](https://platform.openai.com/docs/guides/structured-outputs).

  The default format is `{ "type": "text" }` with no additional options.

  **Not recommended for gpt-4o and newer models:**

  Setting to `{ "type": "json_object" }` enables the older JSON mode, which
  ensures the message the model generates is valid JSON. Using `json_schema`
  is preferred for models that support it.
</ResponseField>

<ResponseField name="text.verbosity" type="string">
  Constrains the verbosity of the model's response. One of `low`, `medium`, or `high`.
</ResponseField>

<ResponseField name="tool_choice" type="`none`, `auto`, `required` | object">
  How the model should select which tool (or tools) to use when generating
  a response. See the `tools` parameter to see how to specify which tools
  the model can call.
</ResponseField>

<ResponseField name="tools" type="object[]" />

<ResponseField name="background" type="boolean">
  Whether the model response runs in the background.
</ResponseField>

<ResponseField name="billing" type="object">
  Billing information for the response.
</ResponseField>

<ResponseField name="billing.payer" type="string">
  The party responsible for paying for the response.
</ResponseField>

<ResponseField name="completed_at" type="number">
  Unix timestamp (in seconds) of when this Response was completed. Only present when the status is `completed`.
</ResponseField>

<ResponseField name="created_at" type="number">
  Unix timestamp (in seconds) of when this Response was created.
</ResponseField>

<ResponseField name="error" type="object">
  An error object returned when the model fails to generate a Response.
</ResponseField>

<ResponseField name="error.code" type="string" required>
  The error code for the response.

  Possible values: `server_error`, `rate_limit_exceeded`, `invalid_prompt`, `vector_store_timeout`, `invalid_image`, `invalid_image_format`, `invalid_base64_image`, `invalid_image_url`, `image_too_large`, `image_too_small`, `image_parse_error`, `image_content_policy_violation`, `invalid_image_mode`, `image_file_too_large`, `unsupported_image_media_type`, `empty_image_file`, `failed_to_download_image`, `image_file_not_found`
</ResponseField>

<ResponseField name="error.message" type="string" required>
  A human-readable description of the error.
</ResponseField>

<ResponseField name="frequency_penalty" type="number">
  Penalizes new tokens based on their existing frequency in the text so far.
</ResponseField>

<ResponseField name="id" type="string">
  Unique identifier for this Response.
</ResponseField>

<ResponseField name="incomplete_details" type="object">
  Details about why the response is incomplete.
</ResponseField>

<ResponseField name="incomplete_details.reason" type="string">
  The reason why the response is incomplete.

  Possible values: `max_output_tokens`, `content_filter`
</ResponseField>

<ResponseField name="max_tool_calls" type="integer">
  The maximum number of total calls to built-in tools that can be processed in a response.
</ResponseField>

<ResponseField name="metadata" type="object">
  Set of key-value pairs that can be attached to the response.
</ResponseField>

<ResponseField name="moderation" type="object">
  Moderation results for the response input and output, if moderated completions were requested.
</ResponseField>

<ResponseField name="object" type="string">
  The object type of this resource - always set to `response`.

  Possible values: `response`
</ResponseField>

<ResponseField name="output" type="object[]">
  An array of content items generated by the model.

  * The length and order of items in the `output` array is dependent
    on the model's response.
  * Rather than accessing the first item in the `output` array and
    assuming it's an `assistant` message with the content generated by
    the model, you might consider using the `output_text` property where
    supported in SDKs.
</ResponseField>

<ResponseField name="output_text" type="string">
  SDK-only convenience property that contains the aggregated text output
  from all `output_text` items in the `output` array, if any are present.
  Supported in the Python and JavaScript SDKs.
</ResponseField>

<ResponseField name="parallel_tool_calls" type="boolean" default="true">
  Whether to allow the model to run tool calls in parallel.
</ResponseField>

<ResponseField name="presence_penalty" type="number">
  Penalizes new tokens based on whether they appear in the text so far.
</ResponseField>

<ResponseField name="prompt_cache_key" type="string">
  Used by OpenAI to cache responses for similar requests to optimize cache hit rates. Replaces the `user` field.
</ResponseField>

<ResponseField name="prompt_cache_retention" type="string">
  The retention policy for the prompt cache, e.g. `in_memory` or `24h`.
</ResponseField>

<ResponseField name="safety_identifier" type="string">
  A stable identifier used to help detect users of your application that may be violating OpenAI's usage policies.
</ResponseField>

<ResponseField name="service_tier" type="string">
  The processing tier used to serve the request, e.g. `auto`, `default`, `flex`, `scale`, or `priority`.
</ResponseField>

<ResponseField name="status" type="string">
  The status of the response generation. One of `completed`, `failed`, `in_progress`, `cancelled`, `queued`, or `incomplete`.

  Possible values: `completed`, `failed`, `in_progress`, `cancelled`, `queued`, `incomplete`
</ResponseField>

<ResponseField name="store" type="boolean">
  Whether the response is stored for later retrieval via the API.
</ResponseField>

<ResponseField name="tool_usage" type="object">
  Token and request usage broken down by built-in tool.
</ResponseField>

<ResponseField name="tool_usage.image_gen" type="object">
  Image generation tool token usage.
</ResponseField>

<ResponseField name="tool_usage.image_gen.input_tokens" type="integer" />

<ResponseField name="tool_usage.image_gen.input_tokens_details" type="object" />

<ResponseField name="tool_usage.image_gen.input_tokens_details.image_tokens" type="integer" />

<ResponseField name="tool_usage.image_gen.input_tokens_details.text_tokens" type="integer" />

<ResponseField name="tool_usage.image_gen.output_tokens" type="integer" />

<ResponseField name="tool_usage.image_gen.output_tokens_details" type="object" />

<ResponseField name="tool_usage.image_gen.output_tokens_details.image_tokens" type="integer" />

<ResponseField name="tool_usage.image_gen.output_tokens_details.text_tokens" type="integer" />

<ResponseField name="tool_usage.image_gen.total_tokens" type="integer" />

<ResponseField name="tool_usage.web_search" type="object">
  Web search tool usage.
</ResponseField>

<ResponseField name="tool_usage.web_search.num_requests" type="integer" />

<ResponseField name="top_logprobs" type="integer">
  The maximum number of most likely tokens to return at each token position, each with an associated log probability.
</ResponseField>

<ResponseField name="usage" type="object">
  Represents token usage details including input tokens, output tokens,
  a breakdown of output tokens, and the total tokens used.
</ResponseField>

<ResponseField name="usage.input_tokens" type="integer" required>
  The number of input tokens.
</ResponseField>

<ResponseField name="usage.input_tokens_details" type="object" required>
  A detailed breakdown of the input tokens.
</ResponseField>

<ResponseField name="usage.input_tokens_details.cache_write_tokens" type="integer">
  The number of input tokens that were written to the cache.
</ResponseField>

<ResponseField name="usage.input_tokens_details.cached_tokens" type="integer" required>
  The number of tokens that were retrieved from the cache.
  [More on prompt caching](https://platform.openai.com/docs/guides/prompt-caching).
</ResponseField>

<ResponseField name="usage.output_tokens" type="integer" required>
  The number of output tokens.
</ResponseField>

<ResponseField name="usage.output_tokens_details" type="object" required>
  A detailed breakdown of the output tokens.
</ResponseField>

<ResponseField name="usage.output_tokens_details.reasoning_tokens" type="integer" required>
  The number of reasoning tokens.
</ResponseField>

<ResponseField name="usage.total_tokens" type="integer" required>
  The total number of tokens used.
</ResponseField>

<ResponseField name="user" type="string">
  Deprecated identifier for the end-user. Replaced by `safety_identifier` and `prompt_cache_key`.
</ResponseField>

## 예시

### 입력

```json theme={null}
{
  "input": "Reply with the single word: ok",
  "max_output_tokens": 1024
}
```

### 출력

```json theme={null}
{
  "completed_at": 1767225601,
  "created_at": 1767225600,
  "id": "resp_0a1b2c3d4e5f6a7b8c9d0e1f",
  "object": "response",
  "output": [
    {
      "content": [
        {
          "annotations": [],
          "text": "ok",
          "type": "output_text"
        }
      ],
      "id": "msg_0a1b2c3d4e5f6a7b8c9d0e1f",
      "role": "assistant",
      "status": "completed",
      "type": "message"
    }
  ],
  "output_text": "ok",
  "status": "completed",
  "usage": {
    "input_tokens": 14,
    "input_tokens_details": {
      "cached_tokens": 0
    },
    "output_tokens": 2,
    "output_tokens_details": {
      "reasoning_tokens": 0
    },
    "total_tokens": 16
  }
}
```

## 배포 전 확인

SDK는 `Idempotency-Key`를 생성하고 자동 재시도에서 재사용합니다. 수동 재시도 시에는 원래 키를 재사용하세요. Router는 연결을 최대 10분간 유지할 수 있습니다.

요청이 실패하면 Router는 이유를 설명하는 `X-Comfy-Error-Type` 응답 헤더를 보냅니다. `422`는 Router가 프로바이더를 호출하기 전에 입력을 거부했음을 의미합니다. 생성된 에셋은 [결과 URL이 만료](/ko/development/comfy-router/reference#결과-에셋)될 수 있으므로 즉시 다운로드하세요.

<CardGroup cols={3}>
  <Card title="헤더" icon="list" href="/ko/development/comfy-router/quickstart">
    인증, 멱등성, 요청 ID, 오류 분류, 재시도 간격, 지출 한도.
  </Card>

  <Card title="Router API 사용" icon="code" href="/ko/development/comfy-router/quickstart">
    모델 검색, 유효성 검사 오류, 재시도, 과금.
  </Card>

  <Card title="제한 사항" icon="triangle-exclamation" href="/ko/development/comfy-router/limitations">
    Router가 현재 지원하지 않는 기능과 대체 방법.
  </Card>
</CardGroup>
