> ## Documentation Index
> Fetch the complete documentation index at: https://dripart-chore-sync-comfy-api-v2-spec.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Use GPT 4.1 with Comfy Router

> Call openai/gpt-4.1 through Comfy Router: endpoint, request shape and the response Router returns.

API Reference for `openai/gpt-4.1`, served by Comfy Router from OpenAI.

## Quick start

Create a key at [platform.comfy.org/profile/api-keys](https://platform.comfy.org/profile/api-keys) and export it as `COMFY_API_KEY`. The Python and TypeScript snippets use the Comfy SDKs (`pip install comfy-sdk`, `npm install @comfyorg/sdk`); the cURL snippet is the same call over raw HTTP.

**Model ID:** `openai/gpt-4.1`

**Endpoint:** `POST https://api.comfy.org/v2/models/openai/gpt-4.1`

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

  # Reads COMFY_API_KEY from the environment. Each call sends a fresh
  # Idempotency-Key and waits up to 10 minutes for the finished result.
  with Comfy() as client:
      result = client.models.run(
          "openai/gpt-4.1",
          {
              "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. Each call sends a fresh
  // Idempotency-Key and waits up to 10 minutes for the finished result.
  const { data } = await comfy.models.run("openai/gpt-4.1", {
    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-4.1 \
    -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>

## 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-4.1/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 | object | 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 | 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 | object | object | 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 | object | object | object | object | object | 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>

## Examples

### Input

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

### Output

```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
  }
}
```

## Before you ship

The snippets above are the shortest working call. Three things are the same for every model and are documented once on the [Comfy Router headers](/development/comfy-router/headers) page: send an `Idempotency-Key` on every paid call and reuse it when you retry, expect the connection to be held up to Router's 10 minute deadline, and keep `X-Comfy-Request-Id` from every response. The SDKs do all three for you; the cURL tab does none of them. On failure, `X-Comfy-Error-Type` names the bucket, and a `422` means the body failed the model's schema and was never billed.

<CardGroup cols={3}>
  <Card title="Headers" icon="list" href="/development/comfy-router/headers">
    Authentication, idempotency, request IDs, error buckets, retry pacing, spend limits.
  </Card>

  <Card title="Quick Start" icon="rocket" href="/development/comfy-router/quickstart">
    Typed error handling in Python and TypeScript, reading the 422, walking the catalog.
  </Card>

  <Card title="Limitations" icon="triangle-exclamation" href="/development/comfy-router/limitations">
    What Router does not do today, and what to use instead.
  </Card>
</CardGroup>
