1
0
mirror of https://github.com/comfyanonymous/ComfyUI.git synced 2026-10-24 02:49:04 +03:00
Files
ComfyUI/openapi.yaml

9446 lines
426 KiB
YAML
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
components:
responses:
SessionForbidden:
content:
application/json:
schema:
$ref: '#/components/schemas/ForbiddenError'
description: A refused request. For a web session, `code` is `workspace_access_denied` (the selected workspace is unknown, deleted, or the user is not a member; the three look the same), `no_workspace_access` (the account has no personal workspace and is a member of no live workspace), `origin_not_allowed` or `cross_site_request`; see the `WebSessionAuth` scheme. For any credential, `sso_required` means an SSO organization holds the account (its email is on the organization's verified domains) and the credential is not an SSO sign-in, or the workspace is an SSO organization's and the account is not on its domains or the credential is not an SSO sign-in; `organization_id`, when present, names the organization to sign in with. `account_outside_organization` means the workspace is an SSO organization's and the account is on none of its domains, so no sign-in admits it; `organization_id` names the workspace's organization. `FORBIDDEN` is the route's own authorization check failing, such as an unverified email. On `GET /api/billing/churnkey/auth`, `NOT_ORIGINAL_OWNER` means the caller is not the workspace's creator; it is returned only when the rollout mode is `creator`. A credential this route does not take gets AuthTypeNotAllowedError instead, and so does the session while `web_session_enabled` is off for the user, unless the operation says it takes the session whatever `web_session_enabled` says.
SessionUnauthorized:
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: No valid credential, or an `Authorization` header, `X-API-Key` header or `?token=` next to the session cookie that could not be read, which is refused rather than answered with the session. `code` is `UNAUTHORIZED`.
SessionWorkspaceAccessDenied:
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: '`code` is `workspace_access_denied`: the selected workspace is unknown, deleted, or the user is not a member; the three look the same. This route also serves anonymous callers, so the session''s other refusals fall back to an anonymous request. See the `WebSessionAuth` scheme.'
SessionWorkspaceIDInvalid:
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: '`code` is `workspace_id_invalid`: the `X-Comfy-Workspace-ID` header or `workspace_id` query value is malformed, or conflicts with another value or with the workspace the credential resolves to. Answered only while `web_session_enabled` is on for the user. See the `WebSessionAuth` scheme.'
SessionWriteForbidden:
content:
application/json:
schema:
$ref: '#/components/schemas/ForbiddenError'
description: A refused request that changes data. For a web session, `code` is `csrf_invalid` (no `X-CSRF-Token`, or not the session's), `workspace_access_denied` (the selected workspace is unknown, deleted, or the user is not a member; the three look the same), `no_workspace_access` (the account has no personal workspace and is a member of no live workspace), `origin_not_allowed` or `cross_site_request`; see the `WebSessionAuth` scheme. For any credential, `sso_required` means an SSO organization holds the account (its email is on the organization's verified domains) and the credential is not an SSO sign-in, or the workspace is an SSO organization's and the account is not on its domains or the credential is not an SSO sign-in; `organization_id`, when present, names the organization to sign in with. `account_outside_organization` means the workspace is an SSO organization's and the account is on none of its domains, so no sign-in admits it; `organization_id` names the workspace's organization. `FORBIDDEN` is the route's own authorization check failing, such as an unverified email, or, on `POST /api/workspaces`, an account an SSO organization holds (its organization manages its workspaces; signing in again does not change it). On the plan-lifecycle writes (`POST /api/billing/subscribe`, `POST /api/billing/subscription/cancel`, `POST /api/billing/subscription/resubscribe`, `POST /api/billing/subscription/revert-scheduled-change`, `POST /api/billing/ops/{id}/cancel` and the `/api/billing/retention/*` routes), `NOT_ORIGINAL_OWNER` means the caller is an owner but not the workspace's creator, and only the creator may change the plan; it is returned only when the rollout mode is `creator`. A credential this route does not take gets AuthTypeNotAllowedError instead, and so does the session while `web_session_enabled` is off for the user, unless the operation says it takes the session whatever the flag.
schemas:
Asset:
description: Represents a user-owned asset (image, video, or other generated output).
properties:
created_at:
description: Timestamp when the asset was created
format: date-time
type: string
display_name:
description: Display name of the asset. Mirrors name for backwards compatibility.
nullable: true
type: string
file_path:
description: Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors")
nullable: true
type: string
hash:
description: Blake3 hash of the asset content.
pattern: ^blake3:[a-f0-9]{64}$
type: string
id:
description: Unique identifier for the asset
format: uuid
type: string
is_immutable:
description: Whether this asset is immutable (cannot be modified or deleted)
type: boolean
job_id:
description: ID of the job that created this asset, if available
format: uuid
nullable: true
type: string
last_access_time:
description: Timestamp when the asset was last accessed
format: date-time
type: string
loader_path:
description: The bare value a loader widget consumes for this asset. For models it is the path inside the category folder (e.g. "flux.safetensors" for "models/checkpoints/flux.safetensors"), which is what the model resolver matches. For input/output/temp it is the content hash, because those assets are fetched by hash rather than staged by name — that is the value LoadImage-style widgets must carry. Clients add the "[output]"/"[temp]" annotation from the asset's own type, so it is never included here. Null when no such value can be derived.
nullable: true
type: string
metadata:
additionalProperties: true
description: System-managed metadata from download sources (HuggingFace, CivitAI, etc.) - read-only, not user-modifiable
readOnly: true
type: object
mime_type:
description: MIME type of the asset
type: string
name:
description: Name of the asset file
type: string
preview_id:
description: ID of the preview asset if available
format: uuid
nullable: true
type: string
preview_url:
description: URL for asset preview/thumbnail
format: uri
type: string
short_url:
description: Durable, owner-gated short link to this asset's content (relative `/api/s/{id}` path). Stable across the underlying signed URL's expiry — resolving it re-mints a fresh signed URL on every request — so it is safe to persist or share into chat, unlike `preview_url`. Only the minting user can resolve it. Omitted when the short-link surface is disabled or the asset has no resolvable content hash.
nullable: true
type: string
x-runtime:
- cloud
size:
description: Size of the asset in bytes
format: int64
type: integer
tags:
description: Tags associated with the asset
items:
type: string
type: array
updated_at:
description: Timestamp when the asset was last updated
format: date-time
type: string
user_metadata:
additionalProperties: true
description: Custom user metadata for the asset
type: object
required:
- id
- name
- created_at
- updated_at
type: object
AssetCreated:
allOf:
- $ref: '#/components/schemas/Asset'
- properties:
created_new:
description: Whether this was a new asset creation (true) or returned existing (false)
type: boolean
required:
- created_new
type: object
description: Response returned when a new asset is successfully created.
AssetInfo:
description: Lightweight asset reference used in workflow publishing payloads.
properties:
id:
description: Asset identifier.
type: string
in_library:
description: Whether the caller already owns this asset.
type: boolean
model:
description: Whether this asset is a model.
type: boolean
name:
type: string
preview_url:
description: Signed URL for previewing the asset.
type: string
public:
description: Whether this is a public (platform-provided) asset.
type: boolean
storage_url:
type: string
required:
- id
- name
- preview_url
- storage_url
- model
- public
- in_library
type: object
AssetTagHistogramResponse:
description: Histogram of tag counts used for refining asset search results.
properties:
tag_counts:
additionalProperties:
type: integer
description: Map of tag names to their occurrence counts on matching assets
example:
checkpoint: 32
lora: 193
vae: 6
type: object
required:
- tag_counts
type: object
AssetUpdated:
description: Response returned when an existing asset is successfully updated.
properties:
display_name:
description: Display name of the asset. Mirrors name for backwards compatibility.
nullable: true
type: string
file_path:
description: Relative path in global-namespace-root form (e.g. "models/checkpoints/flux.safetensors")
nullable: true
type: string
hash:
description: Blake3 hash of the asset content.
pattern: ^blake3:[a-f0-9]{64}$
type: string
id:
description: Asset ID
format: uuid
type: string
job_id:
description: ID of the job that created this asset, if available
format: uuid
nullable: true
type: string
loader_path:
description: The bare value a loader widget consumes for this asset. For models it is the path inside the category folder (e.g. "flux.safetensors" for "models/checkpoints/flux.safetensors"), which is what the model resolver matches. For input/output/temp it is the content hash, because those assets are fetched by hash rather than staged by name — that is the value LoadImage-style widgets must carry. Clients add the "[output]"/"[temp]" annotation from the asset's own type, so it is never included here. Null when no such value can be derived.
nullable: true
type: string
mime_type:
description: Updated MIME type of the asset
type: string
name:
description: Updated name of the asset
type: string
tags:
description: Tags associated with the asset
items:
type: string
type: array
updated_at:
description: Timestamp of the update
format: date-time
type: string
user_metadata:
additionalProperties: true
description: Updated custom metadata
type: object
required:
- id
- updated_at
type: object
AuthTypeNotAllowedError:
description: 403 for a credential the route does not take. `accepted` names the ones it does, as `WWW-Authenticate` does.
properties:
accepted:
items:
type: string
type: array
error:
properties:
message:
type: string
type:
enum:
- auth_type_not_allowed
type: string
required:
- message
- type
type: object
required:
- error
- accepted
type: object
CCCAuthoringContext:
additionalProperties: false
properties:
actor_uid:
minLength: 1
type: string
can_apply:
type: boolean
can_edit:
type: boolean
owner_uid:
minLength: 1
type: string
state:
$ref: '#/components/schemas/CCCCatalogState'
required:
- actor_uid
- owner_uid
- can_edit
- can_apply
- state
type: object
CCCCatalogState:
additionalProperties: false
properties:
draft_generation:
format: int64
minimum: 0
type: integer
draft_rev:
format: int64
minimum: 1
type: integer
live_rev:
format: int64
minimum: 1
type: integer
next_rev:
format: int64
minimum: 1
type: integer
previous_live_rev:
format: int64
minimum: 1
nullable: true
type: integer
required:
- live_rev
- draft_rev
- previous_live_rev
- draft_generation
- next_rev
type: object
CCCCheckedReviewReceipt:
additionalProperties: false
properties:
publish_enabled:
type: boolean
receipt_version:
enum:
- 1
type: integer
selected_count:
maximum: 5000
minimum: 1
type: integer
selected_versions_digest:
pattern: ^[0-9a-f]{64}$
type: string
selection_digest:
pattern: ^[0-9a-f]{64}$
type: string
state:
$ref: '#/components/schemas/CCCCatalogState'
unchecked_count:
maximum: 5000
minimum: 0
type: integer
required:
- receipt_version
- state
- selected_count
- unchecked_count
- selected_versions_digest
- selection_digest
- publish_enabled
type: object
CCCCreatorLink:
additionalProperties: false
properties:
label:
type: string
url:
description: An https URL
format: uri
type: string
required:
- label
- url
type: object
CCCCreatorProfile:
additionalProperties: false
properties:
avatar_url:
description: Empty when the creator has no safe https avatar
type: string
bio:
maxLength: 5000
type: string
display_name:
type: string
links:
items:
$ref: '#/components/schemas/CCCCreatorLink'
maxItems: 8
type: array
username:
type: string
required:
- username
- display_name
- bio
- avatar_url
- links
type: object
CCCCreatorSummary:
additionalProperties: false
properties:
avatar_url:
type: string
display_name:
type: string
username:
type: string
workflow_count:
minimum: 1
type: integer
required:
- username
- display_name
- avatar_url
- workflow_count
type: object
CCCCreatorsPage:
additionalProperties: false
properties:
items:
items:
$ref: '#/components/schemas/CCCCreatorSummary'
maxItems: 100
type: array
next_cursor:
maxLength: 200
type: string
required:
- items
type: object
CCCJSON:
additionalProperties: true
description: Flat type-versioned CCC JSON. Domain schemas (/api/v1/catalog/schemas/{type}/{version}) constrain authored fields. The readOnly properties are server metadata returned by reads; a save may send them back unchanged and they are ignored, never applied. expected_draft_rev and expected_revision_uid are the save concurrency tokens.
properties:
catalog_rev:
description: Catalog revision of this edit; may be older than the working Draft.
format: int64
readOnly: true
type: integer
creator_uid:
description: Immutable account that created the resource.
readOnly: true
type: string
digest:
description: SHA-256 of the canonical authored document.
readOnly: true
type: string
draft_generation:
format: int64
readOnly: true
type: integer
edit_sequence:
format: int64
readOnly: true
type: integer
is_deleted:
description: Tombstone flag. false may be sent back; true is refused (use restore).
readOnly: true
type: boolean
owner_uid:
description: Fixed organization owner; never transferred by a save.
readOnly: true
type: string
revision_uid:
description: This immutable edit; send it back as expected_revision_uid.
format: uuid
readOnly: true
type: string
saved_at:
description: RFC3339 UTC save time of this exact edit.
format: date-time
readOnly: true
type: string
saved_by_uid:
description: Account that saved this edit.
readOnly: true
type: string
uid:
description: Server-assigned logical resource UID.
format: uuid
readOnly: true
type: string
type: object
x-go-type: map[string]interface{}
CCCLegacyTarget:
description: Current Hub page that replaces an old public URL
properties:
path:
description: Website path of the Hub page, for example /hub/workflows/<slug>/
type: string
slug:
description: Current slug of the record
type: string
type:
enum:
- workflow
- app
- model
type: string
required:
- type
- slug
- path
type: object
CCCPublicItemsPage:
allOf:
- $ref: '#/components/schemas/ContentCatalogProjection'
- properties:
has_more:
type: boolean
next_cursor:
description: Opaque continuation bound to this query and publication identity; omitted on the last page.
type: string
page_size:
maximum: 100
minimum: 1
type: integer
required:
- page_size
- has_more
type: object
CCCWebsiteCardFacet:
additionalProperties: false
properties:
count:
description: Staff-only eligible facet count
minimum: 0
type: integer
label:
type: string
value:
type: string
required:
- value
- label
type: object
CCCWebsiteCardFacets:
additionalProperties: false
properties:
categories:
items:
$ref: '#/components/schemas/CCCWebsiteCardFacet'
maxItems: 100
type: array
models:
items:
$ref: '#/components/schemas/CCCWebsiteCardFacet'
maxItems: 100
type: array
use_cases:
items:
$ref: '#/components/schemas/CCCWebsiteCardFacet'
maxItems: 100
type: array
required:
- categories
- models
- use_cases
type: object
CCCWebsiteCardsPage:
additionalProperties: false
properties:
available_kinds:
items:
enum:
- MODEL
- WORKFLOW
- APP
type: string
maxItems: 3
type: array
facets:
$ref: '#/components/schemas/CCCWebsiteCardFacets'
generation:
description: Staff-only Draft generation
format: int64
type: integer
has_more:
type: boolean
items:
items:
$ref: '#/components/schemas/ContentCatalogRecord'
maxItems: 24
type: array
next_cursor:
maxLength: 4096
type: string
page_size:
maximum: 24
minimum: 1
type: integer
previous_cursor:
maxLength: 4096
type: string
revision_id:
format: int64
type: integer
sort_orders:
items:
enum:
- popular
- name
- priceAsc
- priceDesc
type: string
maxItems: 4
type: array
total:
description: Staff-only filtered count; omitted for anonymous callers
minimum: 0
type: integer
required:
- revision_id
- items
- page_size
- has_more
- facets
- available_kinds
- sort_orders
type: object
CCCWebsiteModelDirectory:
additionalProperties: false
properties:
generation:
description: Staff-only Draft generation
format: int64
type: integer
items:
items:
additionalProperties: false
properties:
provider:
description: Authored provider label; empty when not set
type: string
slug:
description: Canonical /hub/models path without a trailing slash
type: string
title:
description: Localized title when reviewed, otherwise source title
type: string
uid:
format: uuid
type: string
required:
- uid
- slug
- title
- provider
type: object
maxItems: 5000
type: array
revision_id:
format: int64
type: integer
required:
- revision_id
- items
type: object
CCCWebsiteRootPageInfo:
additionalProperties: false
properties:
has_more:
type: boolean
page_size:
enum:
- 24
type: integer
required:
- page_size
- has_more
type: object
CCCWebsiteRootPresentation:
additionalProperties: false
properties:
as_of:
description: Database observation clock for this complete presentation.
format: date-time
type: string
items:
items:
$ref: '#/components/schemas/ContentCatalogRecord'
maxItems: 5000
type: array
model_directory:
$ref: '#/components/schemas/CCCWebsiteModelDirectory'
next_visibility_at:
description: Never reuse the artifact at or after this scheduled visibility boundary. Null means no pending boundary.
format: date-time
nullable: true
type: string
revision_id:
format: int64
type: integer
tabs:
$ref: '#/components/schemas/CCCWebsiteRootTabs'
required:
- revision_id
- as_of
- next_visibility_at
- items
- model_directory
- tabs
type: object
CCCWebsiteRootTab:
additionalProperties: false
properties:
facets:
$ref: '#/components/schemas/CCCWebsiteCardFacets'
page:
$ref: '#/components/schemas/CCCWebsiteRootPageInfo'
sort_orders:
items:
enum:
- popular
- name
- priceAsc
- priceDesc
type: string
maxItems: 4
type: array
required:
- facets
- sort_orders
- page
type: object
CCCWebsiteRootTabs:
additionalProperties: false
properties:
apps:
$ref: '#/components/schemas/CCCWebsiteRootTab'
models:
$ref: '#/components/schemas/CCCWebsiteRootTab'
workflows:
$ref: '#/components/schemas/CCCWebsiteRootTab'
required:
- models
- workflows
- apps
type: object
ChurnkeyAuthResponse:
description: |
Credentials the Churnkey embed requires to launch the cancel flow.
`auth_hash` is hex-encoded HMAC-SHA256 of `customer_id` signed with the
server's CHURNKEY_HMAC_SECRET; it is bound to that single customer ID
and must not be reused for other customers.
properties:
auth_hash:
description: Hex-encoded HMAC-SHA256(customer_id, CHURNKEY_HMAC_SECRET)
type: string
customer_id:
description: Stripe customer ID for the workspace
type: string
mode:
description: Churnkey environment matching the configured app
enum:
- live
- test
- sandbox
type: string
offer_subscription_id:
description: |
Stripe subscription a native Churnkey retention offer may apply to.
Present only when the caller is in the native-offer rollout and owns
a Personal workspace on an active paid monthly plan with no billing
change in flight; absent otherwise, and the client then keeps offers
disabled. Present in any mode. Not a signed authorization: the HMAC
covers only the customer ID.
minLength: 1
type: string
required:
- customer_id
- auth_hash
- mode
type: object
ContentCatalogProjection:
properties:
generation:
format: int64
type: integer
items:
items:
$ref: '#/components/schemas/ContentCatalogRecord'
type: array
revision_id:
format: int64
minimum: 1
type: integer
required:
- revision_id
- generation
- items
type: object
ContentCatalogRecord:
properties:
data:
additionalProperties: true
type: object
deleted:
type: boolean
edit_version:
type: string
enabled:
type: boolean
kind:
enum:
- MODEL
- WORKFLOW
- APP
- TEMPLATE_SET
type: string
revision:
description: Integer revision supplying this entity; may precede the requested catalog revision.
format: int64
minimum: 1
type: integer
slug:
description: Canonical website pathname for page content; native slug for template sets. Identity is always UID.
type: string
uid:
type: string
visibility:
enum:
- PUBLIC
- STAFF
type: string
visible_from:
format: date-time
type: string
required:
- uid
- revision
- edit_version
- kind
- slug
- enabled
- visibility
- deleted
- data
type: object
CreateWorkflowRequest:
description: Request body for creating a new saved workflow.
properties:
default_view:
description: Default view mode
enum:
- workflow
- app
type: string
description:
description: Description of the workflow
type: string
forked_from_workflow_id:
description: ID of the source workflow if forked
type: string
forked_from_workflow_version_id:
description: ID of the source workflow version if forked
type: string
name:
description: Display name for the workflow
type: string
workflow_json:
additionalProperties: true
description: The ComfyUI workflow JSON
type: object
required:
- workflow_json
type: object
CreateWorkflowVersionRequest:
description: Request body for creating a new version of a saved workflow.
properties:
base_version:
description: The version number this change is based on (for optimistic concurrency)
type: integer
workflow_json:
additionalProperties: true
description: The updated ComfyUI workflow JSON
type: object
required:
- base_version
- workflow_json
type: object
DeployToCloudError:
description: Error body of local ComfyUI's /api/deploy/* routes. Branch on `error`, never on `message`.
properties:
error:
enum:
- offline
- multiple_credentials
- invalid_api_key_format
- invalid_body
- missing_credentials
- unauthorized
- too_large
- too_many_bundles
- builder_rejected
- builder_unavailable
- builder_busy
type: string
message:
description: Human-readable detail, present for invalid_body and builder_rejected.
type: string
required:
- error
type: object
ErrorResponse:
description: Standard error response with a machine-readable code and human-readable message.
properties:
code:
type: string
details:
additionalProperties: true
description: Optional open object carrying structured, machine-readable context about the error (e.g. offending field names, validation specifics). Absent for most errors; consumers must not assume any particular shape.
type: object
message:
type: string
organization_id:
description: 'On `sso_required`: the SSO organization the caller must sign in with (its WorkOS id, `org_...`), the value `GET /api/auth/sso/start?organization=` takes: the organization that owns the account''s email domain, else the workspace''s. Absent when no sign-in would admit the caller (an account another organization holds, in an SSO organization''s workspace), when unknown, and on every other code but `account_outside_organization`, where it is the workspace''s organization, which no sign-in of the account joins.'
type: string
required:
- code
- message
type: object
ExecutionError:
description: Detailed execution error information from ComfyUI
properties:
current_inputs:
additionalProperties: true
description: Input values at time of failure (empty object if not available)
type: object
current_outputs:
additionalProperties: true
description: Output values at time of failure (empty object if not available)
type: object
exception_message:
description: Human-readable error message
type: string
exception_type:
description: Python exception type (e.g., "RuntimeError")
type: string
node_id:
description: ID of the node that failed
type: string
node_type:
description: Type name of the node (e.g., "KSampler")
type: string
traceback:
description: Array of traceback lines (empty array if not available)
items:
type: string
type: array
required:
- node_id
- node_type
- exception_message
- exception_type
- traceback
- current_inputs
- current_outputs
type: object
FeedbackRequest:
description: Request to submit user feedback
properties:
content:
description: The feedback content or message
type: string
metadata:
additionalProperties: true
description: Additional metadata about the feedback
type: object
rating:
description: User's rating of ComfyUI Cloud experience (1-5 stars)
maximum: 5
minimum: 1
type: integer
type:
description: Type of feedback being submitted
enum:
- missing_nodes
- general
- missing_models
type: string
required:
- type
type: object
FeedbackResponse:
description: Response after submitting feedback
type: object
ForbiddenError:
description: 'A 403 body: ErrorResponse, or AuthTypeNotAllowedError for a credential the route does not take.'
oneOf:
- $ref: '#/components/schemas/ErrorResponse'
- $ref: '#/components/schemas/AuthTypeNotAllowedError'
ForkWorkflowRequest:
description: Request body for forking an existing workflow into the user's account.
properties:
name:
description: Name for the forked workflow
type: string
source_version:
description: Version number to fork from
type: integer
required:
- source_version
type: object
GetUserDataResponseFull:
description: List of user data file entries (each with path, size, and modification time) returned when full_info=true.
items:
$ref: '#/components/schemas/GetUserDataResponseFullFile'
type: array
GetUserDataResponseFullFile:
description: Individual file entry within a full user data response.
properties:
modified:
description: UNIX timestamp of the last modification in milliseconds.
format: int64
type: integer
path:
description: File name or path relative to the user directory.
type: string
size:
description: File size in bytes.
type: integer
type: object
GlobalSubgraphData:
description: Full data for a global subgraph blueprint
properties:
data:
description: The full subgraph JSON data as a string
type: string
info:
description: Additional information about the subgraph
properties:
node_pack:
description: The node pack/module that provides this subgraph
type: string
required:
- node_pack
type: object
name:
description: Display name of the subgraph blueprint
type: string
source:
description: Source type of the subgraph - "templates" for workflow templates or "custom_node" for custom node subgraphs
type: string
required:
- source
- name
- info
- data
type: object
GlobalSubgraphInfo:
description: Metadata for a global subgraph blueprint (without full data)
properties:
data:
description: The full subgraph JSON data (may be empty in list view)
type: string
info:
description: Additional information about the subgraph
properties:
node_pack:
description: The node pack/module that provides this subgraph
type: string
required:
- node_pack
type: object
name:
description: Display name of the subgraph blueprint
type: string
source:
description: Source type of the subgraph - "templates" for workflow templates or "custom_node" for custom node subgraphs
type: string
required:
- source
- name
- info
type: object
HistoryDetailEntry:
description: History entry with full prompt data. The workflow graph (extra_data.extra_pnginfo) is omitted from records persisted after it stopped being stored; older records may still contain it.
properties:
meta:
additionalProperties: true
description: Metadata about the execution and nodes
type: object
outputs:
additionalProperties: true
description: Output data from execution (generated images, files, etc.)
type: object
prompt:
description: Full prompt execution data
properties:
extra_data:
additionalProperties: true
description: Additional execution data. extra_pnginfo (the workflow graph) is omitted from records persisted after it stopped being stored; older records may still contain it.
type: object
outputs_to_execute:
description: Output nodes to execute
items:
type: string
type: array
priority:
description: Execution priority
format: double
type: number
prompt:
additionalProperties: true
description: The workflow nodes
type: object
prompt_id:
description: The prompt ID
type: string
type: object
status:
additionalProperties: true
description: Execution status and timeline information
type: object
type: object
HistoryDetailResponse:
additionalProperties:
$ref: '#/components/schemas/HistoryDetailEntry'
description: |
Detailed execution history response for a specific prompt.
Returns a dictionary with prompt_id as key and full history data as value.
type: object
HistoryEntry:
description: History entry with prompt_id and execution data
properties:
create_time:
description: Job creation timestamp (Unix timestamp in milliseconds)
format: int64
type: integer
meta:
additionalProperties: true
description: Metadata about the execution and nodes
type: object
outputs:
additionalProperties: true
description: Output data from execution (generated images, files, etc.)
type: object
prompt:
description: Filtered prompt execution data (lightweight format)
properties:
extra_data:
additionalProperties: true
description: Additional execution data (workflow removed from extra_pnginfo)
type: object
priority:
description: Execution priority
format: double
type: number
prompt_id:
description: The prompt ID
type: string
type: object
prompt_id:
description: Unique identifier for this prompt execution
type: string
status:
additionalProperties: true
description: Execution status and timeline information
type: object
workflow_id:
description: UUID identifying the workflow graph definition
type: string
required:
- prompt_id
type: object
HistoryManageRequest:
additionalProperties: false
description: Request to manage history operations
properties:
clear:
description: If true, clear all history for the authenticated user
type: boolean
delete:
description: Array of job IDs to delete from history
items:
type: string
type: array
type: object
HistoryResponse:
description: |
Execution history response with history array.
Returns an object with a "history" key containing an array of history entries.
Each entry includes prompt_id as a property along with execution data.
properties:
history:
description: Array of history entries ordered by creation time (newest first)
items:
$ref: '#/components/schemas/HistoryEntry'
type: array
required:
- history
type: object
JobAssetsResponse:
description: Paginated list of the assets produced by a single job.
properties:
assets:
description: The job's output assets for the requested page (empty when the job produced none)
items:
$ref: '#/components/schemas/JobOutputAsset'
type: array
job_id:
description: ID of the job these assets belong to
format: uuid
type: string
pagination:
$ref: '#/components/schemas/PaginationInfo'
required:
- job_id
- assets
- pagination
type: object
JobCancelResponse:
description: Response for POST /api/jobs/{job_id}/cancel. Returned on both fresh cancels and idempotent no-ops.
properties:
cancelled:
description: |
True when a cancel event was successfully dispatched by this call.
False when the job was already in a terminal or cancelling state,
in which case the call is a no-op (still 200 — idempotent).
type: boolean
required:
- cancelled
type: object
JobDeployment:
description: 'The deployment a job ran on and the Release it ran, as they were when the job was sent: deployment_id and release_id stay the same after the deployment is updated to another Release or deleted. build_name and release_version are read from comfy-builder when the job is read, so a renamed Build shows its new name within a few minutes.'
properties:
build_name:
description: 'The name of the Build the Release was cut from, as comfy-builder names it now. Absent when it is not named for this caller: an API-key caller, a caller reading a job outside their active workspace (an admin reading another workspace''s job), comfy-builder not configured on this server, minting the token to ask comfy-builder failing, comfy-builder failing or not answering in time, or a Release or Build since deleted.'
type: string
deployment_id:
description: Developer-platform deployment id.
type: string
name:
description: The deployment's own name from comfy-deploy, including for a deleted deployment. Read when the job is read and cached for five minutes, so a rename appears after the cache expires; not a job-time snapshot. Absent for unnamed or unavailable deployments, API-key callers, jobs outside the caller's active workspace, or when the service or token mint is unavailable. Does not replace build_name or the stable IDs.
type: string
release_id:
description: The Release the job ran.
type: string
release_version:
description: The Release's version number within its Build. Absent whenever build_name is.
type: integer
required:
- deployment_id
- release_id
type: object
JobDetailResponse:
description: Full job details including workflow and outputs
properties:
create_time:
description: Job creation timestamp (Unix timestamp in milliseconds)
format: int64
type: integer
deployment:
allOf:
- $ref: '#/components/schemas/JobDeployment'
description: 'Where a platform_gateway job ran. Absent for cloud_inference jobs. Also absent when the platform has not taken the job, refused it, failed before dispatch, or removed its platform record; when the record names no deployment; or when that record could not be read. Absence does not mean the job is pending: use status for its state. A failed job can retain executor=platform_gateway without a known deployment. No deployment is inferred from the caller''s current pick.'
execution_end_time:
description: Workflow execution completion timestamp (Unix milliseconds, only present for terminal states)
format: int64
type: integer
execution_error:
allOf:
- $ref: '#/components/schemas/ExecutionError'
description: Detailed execution error from ComfyUI (only for failed jobs with structured error data)
execution_meta:
additionalProperties: true
description: Node-level execution metadata (only for terminal states)
type: object
execution_start_time:
description: Workflow execution start timestamp (Unix milliseconds, only present once execution has started)
format: int64
type: integer
execution_status:
additionalProperties: true
description: ComfyUI execution status and timeline (only for terminal states)
type: object
executor:
description: 'What ran the job: cloud_inference is Comfy Cloud''s own GPUs; platform_gateway is a deployment of the workspace''s own Build, which deployment names.'
enum:
- cloud_inference
- platform_gateway
type: string
id:
description: Unique job identifier
format: uuid
type: string
outputs:
additionalProperties: true
description: Full outputs object from ComfyUI (only for terminal states)
type: object
outputs_count:
description: Total number of output files (omitted for non-terminal states)
type: integer
preview_output:
additionalProperties: true
description: Primary preview output (only for terminal states)
type: object
previewable_outputs_count:
description: Count of outputs classified as previewable media types (images, video, audio, 3D, text) — a subset of outputs_count (omitted for non-terminal states)
type: integer
queue_position:
description: |
1-based position of this job among the caller's OWN jobs held
behind the same concurrency cap (same user, workspace and auth
method), in the dispatcher's admission order — i.e. the number of
the caller's own capped jobs that will be admitted before this
one, plus one. It is NOT a fleet-wide queue position and says
nothing about other users' jobs. (For an admin reading someone
else's job, the set is that job owner's, not the admin's — the
same scoping `workspace_id`/`user_id` already describe.)
Null unless `queue_reason` is `concurrency_limit`. May also be
null in that state on the rare rows whose admission ordering
cannot be determined (no recorded state-change timestamp), or if
the count query fails — a missing position never fails the
request.
minimum: 1
nullable: true
type: integer
queue_reason:
description: |
Why a still-queued job has not started yet. Present only while
`status` is `pending`; null for every other status.
`status` deliberately folds every waiting state into `pending`
(the frontend's filter categories depend on that), so this field
is the one that tells the two kinds of waiting apart:
- `concurrency_limit` — the job is awaiting admission under the
per-user/per-auth-method or aggregate workspace concurrent-job
cap. Other members' running jobs can fill the workspace cap
even when this job's owner has no running jobs. This field
does not distinguish which cap is full.
- `capacity` — the job has passed concurrency admission and is
waiting for an inference worker to become free.
Detail-only: this field is NOT present on the list view's
`JobEntry`, because deriving `queue_position` for a page of jobs
would cost one extra query per row.
enum:
- concurrency_limit
- capacity
nullable: true
type: string
status:
description: User-friendly job status
enum:
- pending
- in_progress
- completed
- failed
- cancelled
type: string
update_time:
description: Last update timestamp (Unix timestamp in milliseconds)
format: int64
type: integer
user_id:
description: |
ID of the user that owns this job (see the `workspace_id`
description above for why this is always the caller's own id
on a successful response).
type: string
workflow:
additionalProperties: true
description: |
Full ComfyUI workflow (10-100KB, omitted if not available).
Sensitive credentials are redacted before the response is returned:
`extra_data.api_key_comfy_org`, when present, is replaced with the
literal string `"[REDACTED]"`. The field is preserved (not removed)
so existence checks still pass, but the value is not usable.
type: object
workflow_id:
description: UUID identifying the workflow graph definition
type: string
workflow_version_id:
description: |
UUID of the cloud workflow version this job is pinned to, if the
submission carried one (see PromptRequest's workflow_version_id).
Absent for jobs submitted without that association, including
every job submitted through the public API v2 today.
type: string
workspace_id:
description: |
ID of the workspace that owns this job. A successful (200)
response from this operation is only ever returned for the
caller's own job (see this operation's ownership-scoped
query), so this is always the caller's own workspace —
consumers that also need to correlate this job to its
live-progress broadcast channel (workspace+user scoped; see
the internal common/gateways/broadcast package) can use this
value directly rather than resolving their own identity a
second way.
type: string
required:
- id
- status
- create_time
- update_time
type: object
JobEntry:
description: Lightweight job data for list views (workflow and full outputs excluded)
properties:
create_time:
description: Job creation timestamp (Unix timestamp in milliseconds)
format: int64
type: integer
deployment:
allOf:
- $ref: '#/components/schemas/JobDeployment'
description: 'Where a platform_gateway job ran. Absent for cloud_inference jobs. Also absent when the platform has not taken the job, refused it, failed before dispatch, or removed its platform record; when the record names no deployment; or when that record could not be read. Absence does not mean the job is pending: use status for its state. A failed job can retain executor=platform_gateway without a known deployment. No deployment is inferred from the caller''s current pick.'
execution_end_time:
description: Workflow execution completion timestamp (Unix milliseconds, only present for terminal states)
format: int64
type: integer
execution_error:
allOf:
- $ref: '#/components/schemas/ExecutionError'
description: Detailed execution error from ComfyUI (only for failed jobs with structured error data)
execution_start_time:
description: Workflow execution start timestamp (Unix milliseconds, only present for terminal states)
format: int64
type: integer
executor:
description: 'What ran the job: cloud_inference is Comfy Cloud''s own GPUs; platform_gateway is a deployment of the workspace''s own Build, which deployment names.'
enum:
- cloud_inference
- platform_gateway
type: string
id:
description: Unique job identifier
format: uuid
type: string
outputs_count:
description: Total number of output files (omitted for non-terminal states)
type: integer
preview_output:
additionalProperties: true
description: Primary preview output (only present for terminal states)
type: object
previewable_outputs_count:
description: Count of outputs classified as previewable media types (images, video, audio, 3D, text) — a subset of outputs_count (omitted for non-terminal states)
type: integer
status:
description: User-friendly job status
enum:
- pending
- in_progress
- completed
- failed
- cancelled
type: string
workflow_id:
description: UUID identifying the workflow graph definition
type: string
required:
- id
- status
- create_time
type: object
JobOutputAsset:
description: |
An asset produced by a job, enriched with the per-output node context
(`node_id`, `output_key`, `output_index`) correlated from the job's
execution outputs by content hash. The node-context fields are null
when the asset cannot be matched to an output entry.
properties:
created_at:
description: Timestamp when the asset was created
format: date-time
type: string
hash:
description: Blake3 hash of the asset content.
pattern: ^blake3:[a-f0-9]{64}$
type: string
id:
description: Unique identifier for the asset
format: uuid
type: string
mime_type:
description: MIME type of the asset
type: string
name:
description: Name of the asset file
type: string
node_id:
description: ID of the workflow node that produced this asset, if known
nullable: true
type: string
output_index:
description: Zero-based index of this asset within the node's output slot, if known
nullable: true
type: integer
output_key:
description: Output slot key under the producing node (e.g. "images"), if known
nullable: true
type: string
preview_url:
description: Relative URL for asset preview/thumbnail
format: uri-reference
type: string
size:
description: Size of the asset in bytes
format: int64
type: integer
required:
- id
- name
- created_at
type: object
JobStatusResponse:
description: Job status information
properties:
assigned_inference:
description: The inference instance assigned to this job (if any)
nullable: true
type: string
created_at:
description: When the job was created
format: date-time
type: string
error_message:
description: Error message if the job failed
nullable: true
type: string
id:
description: The job ID
format: uuid
type: string
last_state_update:
description: When the job status was last changed
format: date-time
type: string
status:
description: Current job status
enum:
- waiting_to_dispatch
- pending
- in_progress
- completed
- error
- cancelled
type: string
updated_at:
description: When the job was last updated
format: date-time
type: string
required:
- id
- status
- created_at
- updated_at
type: object
JobsCancelRequest:
additionalProperties: false
description: Request to cancel multiple jobs by ID.
properties:
job_ids:
description: Job identifiers (UUIDs) to cancel.
items:
format: uuid
type: string
maxItems: 100
minItems: 1
type: array
required:
- job_ids
type: object
JobsCancelResponse:
description: Response for POST /api/jobs/cancel.
properties:
cancelled:
description: |
Job IDs for which a cancel event was successfully dispatched by this
call. Jobs already in a terminal or cancelling state are idempotently
skipped and will not appear here.
items:
type: string
type: array
required:
- cancelled
type: object
JobsListResponse:
description: Paginated list of jobs for the authenticated user.
properties:
jobs:
description: Array of jobs ordered by specified sort field
items:
$ref: '#/components/schemas/JobEntry'
type: array
pagination:
$ref: '#/components/schemas/PaginationInfo'
required:
- jobs
- pagination
type: object
ListAssetsResponse:
description: Paginated list of assets belonging to the authenticated user.
properties:
assets:
description: List of assets matching the query
items:
$ref: '#/components/schemas/Asset'
type: array
has_more:
description: Whether more assets are available beyond this page
type: boolean
next_cursor:
description: |
Opaque cursor to pass as the `after` query parameter to fetch the
next page. Omitted from the response when there are no more results.
type: string
total:
description: Total number of assets matching the filters
type: integer
required:
- assets
- total
- has_more
type: object
ListTagsResponse:
description: Paginated list of available asset tags.
properties:
has_more:
description: Whether more tags are available
type: boolean
tags:
description: List of tags
items:
$ref: '#/components/schemas/TagInfo'
type: array
total:
description: Total number of tags
type: integer
required:
- tags
- total
- has_more
type: object
ModelFile:
description: Represents a model file with metadata
properties:
name:
description: The filename of the model
example: model.safetensors
type: string
pathIndex:
description: Index of the path where this model is located
example: 0
type: integer
required:
- name
- pathIndex
type: object
ModelFolder:
description: Represents a folder containing models
properties:
folders:
description: List of paths where models of this type are stored
example:
- checkpoints
items:
type: string
type: array
name:
description: The name of the model folder
example: checkpoints
type: string
required:
- name
- folders
type: object
NodeInfo:
description: Metadata describing a single ComfyUI node type and its inputs/outputs.
properties:
api_node:
description: Whether this is an API node
type: boolean
category:
description: Category of the node
type: string
deprecated:
description: Whether the node is deprecated
type: boolean
description:
description: Description of the node
type: string
display_name:
description: Display name of the node
type: string
experimental:
description: Whether the node is experimental
type: boolean
input:
additionalProperties: true
description: Input specifications for the node
type: object
input_order:
additionalProperties:
items:
type: string
type: array
description: Order of inputs for display
type: object
name:
description: Internal name of the node
type: string
output:
description: Output types of the node
items:
type: string
type: array
output_is_list:
description: Whether each output is a list
items:
type: boolean
type: array
output_name:
description: Names of the outputs
items:
type: string
type: array
output_node:
description: Whether this is an output node
type: boolean
output_tooltips:
description: Tooltips for outputs
items:
type: string
type: array
python_module:
description: Python module implementing the node
type: string
type: object
PaginationInfo:
description: |
Pagination metadata included in list responses. Supports both legacy
offset/limit pagination and cursor-based pagination. When cursor-based
pagination is used, `next_cursor` is the primary pagination token and
`offset`/`total` may be zero.
properties:
has_more:
description: Whether more items are available beyond this page
type: boolean
limit:
description: Items per page
minimum: 1
type: integer
next_cursor:
description: |
Opaque cursor for the next page. Pass this value as the `after`
query parameter on the next request. Empty or absent when there
are no more results.
type: string
offset:
deprecated: true
description: 'Current offset (0-based). Deprecated: use cursor-based pagination.'
minimum: 0
type: integer
total:
description: Total number of items matching filters (may be 0 when using cursor pagination)
minimum: 0
type: integer
required:
- offset
- limit
- total
- has_more
type: object
PromptErrorResponse:
additionalProperties: true
description: Error response for ComfyUI prompt execution.
type: object
PromptInfo:
description: Metadata about the currently running and queued prompts.
properties:
exec_info:
properties:
queue_remaining:
description: Number of items remaining in the queue
type: integer
type: object
type: object
PromptRequest:
description: Request body for submitting a ComfyUI workflow prompt for execution.
properties:
extra_data:
additionalProperties: true
description: Extra data to be associated with the prompt
type: object
front:
description: If true, adds the prompt to the front of the queue
type: boolean
number:
description: Priority number for the queue (lower numbers have higher priority)
type: number
partial_execution_targets:
description: List of node names to execute
items:
type: string
type: array
prompt:
additionalProperties: true
description: The workflow graph to execute
type: object
workflow_id:
description: UUID identifying the cloud workflow entity to associate with this job
type: string
workflow_version_id:
description: UUID identifying the workflow version to associate with this job
type: string
required:
- prompt
type: object
PromptResponse:
description: Response returned after successfully queuing a workflow prompt.
properties:
node_errors:
additionalProperties: true
description: Any errors in the nodes of the prompt
type: object
number:
description: Priority number in the queue
type: number
prompt_id:
description: Unique identifier for the prompt execution
format: uuid
type: string
type: object
PublishWorkflowAssetsRequest:
description: Request body for publishing workflow assets to the Hub.
properties:
asset_ids:
description: IDs of assets (inputs and models) to snapshot.
items:
type: string
type: array
required:
- asset_ids
type: object
PublishedWorkflowDetail:
description: Full detail of a publicly published workflow on the Hub.
properties:
assets:
description: Published assets with their library status for the caller.
items:
$ref: '#/components/schemas/AssetInfo'
type: array
listed:
type: boolean
name:
description: Human-readable workflow name.
type: string
publish_time:
format: date-time
nullable: true
type: string
share_id:
type: string
workflow_id:
type: string
workflow_json:
additionalProperties: true
description: The workflow JSON content at publish time.
type: object
required:
- share_id
- workflow_id
- name
- listed
- workflow_json
- assets
type: object
QueueInfo:
description: Queue information with pending and running jobs
properties:
queue_pending:
description: Array of pending job items (ordered by creation time, oldest first)
items:
description: |
Queue item tuple format: [job_number, prompt_id, workflow_json, output_node_ids, metadata]
- [0] job_number (integer): Position in queue (1-based)
- [1] prompt_id (string): Job UUID
- [2] workflow_json (object): Full ComfyUI workflow
- [3] output_node_ids (array): Node IDs to return results from
- [4] metadata (object): Contains {create_time: <milliseconds>}
items: {}
maxItems: 5
minItems: 5
type: array
type: array
queue_running:
description: Array of currently running job items
items:
description: |
Queue item tuple format: [job_number, prompt_id, workflow_json, output_node_ids, metadata]
- [0] job_number (integer): Position in queue (1-based)
- [1] prompt_id (string): Job UUID
- [2] workflow_json (object): Full ComfyUI workflow
- [3] output_node_ids (array): Node IDs to return results from
- [4] metadata (object): Contains {create_time: <milliseconds>}
items: {}
maxItems: 5
minItems: 5
type: array
type: array
type: object
QueueManageRequest:
additionalProperties: false
description: Request to manage queue operations
properties:
clear:
description: If true, clear all pending jobs from the queue
type: boolean
delete:
description: Array of job IDs to cancel; pending and running jobs transition to cancelled
items:
type: string
type: array
type: object
QueueManageResponse:
description: Response after a queue management action (delete or clear).
properties:
cleared:
description: Whether the queue was cleared
type: boolean
deleted:
description: Array of job IDs that were successfully cancelled
items:
type: string
type: array
type: object
RetentionAcceptRequest:
additionalProperties: false
properties:
session_id:
description: Server-issued session; carries no client-selected coupon or variant.
format: uuid
type: string
required:
- session_id
type: object
RetentionAcceptance:
properties:
billing_op_id:
type: string
status:
description: Show success only once this is succeeded; otherwise poll the billing operation.
enum:
- pending
- succeeded
type: string
required:
- billing_op_id
- status
type: object
RetentionFlowEventRequest:
additionalProperties: false
properties:
event:
description: flow_opened is reported at the same point for every arm.
enum:
- flow_opened
- offer_shown
type: string
session_id:
format: uuid
type: string
required:
- session_id
- event
type: object
RetentionFlowResponse:
properties:
experiment_variant:
description: |
The PostHog arm: control or a retention offer ID. Absent when the
subscription is ineligible or the owner is outside the experiment.
type: string
expires_at:
description: Unix seconds; reopen cancellation to refresh the offer after expiry.
maximum: 9007199254740991
type: integer
x-go-type: int64
offer:
$ref: '#/components/schemas/RetentionOffer'
session_id:
format: uuid
type: string
subscription:
$ref: '#/components/schemas/RetentionFlowSubscription'
required:
- session_id
- expires_at
- subscription
type: object
RetentionFlowSubscription:
properties:
currency:
type: string
period_end:
description: Unix seconds of the next renewal.
maximum: 9007199254740991
type: integer
x-go-type: int64
quantity:
maximum: 9007199254740991
type: integer
x-go-type: int64
unit_amount:
description: Recurring unit price in the currency's smallest unit.
maximum: 9007199254740991
type: integer
x-go-type: int64
required:
- currency
- unit_amount
- quantity
- period_end
type: object
RetentionOffer:
description: Present only when the session's arm is an offer. Terms come from the server catalog.
properties:
duration_in_months:
maximum: 9007199254740991
type: integer
x-go-type: int64
id:
type: string
percent_off:
maximum: 9007199254740991
type: integer
x-go-type: int64
required:
- id
- percent_off
- duration_in_months
type: object
SystemStatsResponse:
description: System statistics response
properties:
devices:
items:
properties:
name:
description: Device name
type: string
type:
description: Device type
type: string
vram_free:
description: Free VRAM in bytes
type: number
vram_total:
description: Total VRAM in bytes
type: number
required:
- name
- type
type: object
type: array
system:
properties:
argv:
description: Command line arguments
items:
type: string
type: array
cloud_version:
description: Cloud ingest service version (commit hash)
type: string
comfyui_frontend_version:
description: ComfyUI frontend version (commit hash or tag)
type: string
comfyui_version:
description: ComfyUI version
type: string
deploy_environment:
description: How this ComfyUI instance is deployed (e.g. cloud, local-git, local-portable, local-desktop)
type: string
embedded_python:
description: Whether using embedded Python
type: boolean
os:
description: Operating system
type: string
python_version:
description: Python version
type: string
pytorch_version:
description: PyTorch version
type: string
ram_free:
description: Free RAM in bytes
type: number
ram_total:
description: Total RAM in bytes
type: number
workflow_templates_version:
description: Workflow templates version
type: string
required:
- os
- python_version
- embedded_python
- comfyui_version
- pytorch_version
- argv
- ram_total
- ram_free
type: object
required:
- system
- devices
type: object
TagInfo:
description: Metadata for a single tag that can be applied to assets.
properties:
count:
description: Number of assets using this tag
type: integer
name:
description: Tag name
type: string
required:
- name
- count
type: object
TagsModificationResponse:
description: Response after adding, updating, or removing tags on an asset.
properties:
added:
description: Tags that were successfully added (for add operation)
items:
type: string
type: array
already_present:
description: Tags that were already present (for add operation)
items:
type: string
type: array
not_present:
description: Tags that were not present (for remove operation)
items:
type: string
type: array
removed:
description: Tags that were successfully removed (for remove operation)
items:
type: string
type: array
total_tags:
description: All tags on the asset after the operation
items:
type: string
type: array
required:
- total_tags
type: object
TaskEntry:
description: Task data for list views
properties:
completed_at:
description: When task completed, failed, or was cancelled (null if not finished)
format: date-time
type: string
create_time:
description: Task creation timestamp
format: date-time
type: string
id:
description: Unique task identifier
format: uuid
type: string
started_at:
description: When task execution started (null if not started)
format: date-time
type: string
status:
description: Current task status
enum:
- created
- running
- completed
- failed
- cancelled
type: string
task_name:
description: Task type name (e.g., model_upload)
type: string
required:
- id
- task_name
- status
- create_time
type: object
TaskResponse:
description: Full task details including payload and result
properties:
completed_at:
description: When task completed or failed (null if not finished)
format: date-time
type: string
create_time:
description: Task creation timestamp
format: date-time
type: string
error_message:
description: Error message on failure (null if not failed)
type: string
id:
description: Unique task identifier
format: uuid
type: string
idempotency_key:
description: Caller-provided key for idempotent task creation
type: string
payload:
additionalProperties: true
description: Task input data
type: object
result:
additionalProperties: true
description: Task output data (null if not completed)
type: object
started_at:
description: When task execution started (null if not started)
format: date-time
type: string
status:
description: Current task status
enum:
- created
- running
- completed
- failed
- cancelled
type: string
task_name:
description: Task type name (e.g., model_upload)
type: string
update_time:
description: Task last update timestamp
format: date-time
type: string
required:
- id
- idempotency_key
- task_name
- payload
- status
- create_time
- update_time
type: object
TasksListResponse:
description: Paginated list of background tasks for the authenticated user.
properties:
pagination:
$ref: '#/components/schemas/PaginationInfo'
tasks:
description: Array of tasks ordered by create_time
items:
$ref: '#/components/schemas/TaskEntry'
type: array
required:
- tasks
- pagination
type: object
UpdateWorkflowRequest:
description: Request body for updating an existing saved workflow.
properties:
default_view:
description: New default view mode
enum:
- workflow
- app
type: string
description:
description: New description
type: string
name:
description: New display name
type: string
type: object
UserDataResponseFull:
description: User data listing entry with file metadata (path, size, modification time).
properties:
modified:
description: UNIX timestamp of the last modification in milliseconds.
format: int64
type: integer
path:
type: string
size:
type: integer
type: object
UserResponse:
description: User information response
properties:
id:
description: Firebase UID of the authenticated user
type: string
status:
description: User status (always "active" for authenticated users)
type: string
required:
- id
- status
type: object
WorkflowForkedFrom:
description: Reference to the parent workflow from which this workflow was forked.
properties:
workflow_id:
type: string
workflow_version_id:
type: string
type: object
WorkflowListResponse:
description: Paginated list of saved workflows.
properties:
data:
items:
$ref: '#/components/schemas/WorkflowResponse'
type: array
pagination:
$ref: '#/components/schemas/PaginationInfo'
required:
- data
- pagination
type: object
WorkflowPublishInfo:
description: Publishing metadata for a workflow shared to the Hub.
properties:
assets:
description: Published assets (inputs and models).
items:
$ref: '#/components/schemas/AssetInfo'
type: array
listed:
type: boolean
publish_time:
format: date-time
nullable: true
type: string
share_id:
type: string
workflow_id:
type: string
required:
- workflow_id
- share_id
- listed
- assets
type: object
WorkflowResponse:
description: Full workflow entity including metadata and version history.
properties:
created_at:
format: date-time
type: string
created_by:
type: string
default_view:
enum:
- workflow
- app
type: string
description:
type: string
forked_from:
$ref: '#/components/schemas/WorkflowForkedFrom'
id:
type: string
latest_version:
type: integer
name:
type: string
updated_at:
format: date-time
type: string
required:
- id
- latest_version
- created_by
- created_at
- updated_at
type: object
WorkflowVersionContentResponse:
description: Full workflow version including the serialized workflow JSON.
properties:
created_at:
format: date-time
type: string
created_by:
type: string
dependency_asset_ids:
items:
type: string
type: array
id:
type: string
version:
type: integer
workflow_json:
additionalProperties: true
type: object
required:
- id
- version
- workflow_json
- created_by
- created_at
type: object
WorkflowVersionResponse:
description: Metadata for a single workflow version.
properties:
created_at:
format: date-time
type: string
created_by:
type: string
id:
type: string
latest_version:
type: integer
version:
type: integer
required:
- id
- version
- latest_version
- created_by
- created_at
type: object
securitySchemes:
ApiKeyAuth:
description: |
API key authentication. Keys are prefixed with 'comfyui-' and can be
generated from user account settings. Example: 'comfyui-abc123...'
in: header
name: X-API-Key
type: apiKey
BearerAuth:
bearerFormat: JWT
description: |
A token in the `Authorization: Bearer` header: a Firebase ID token, a
Cloud JWT from `POST /api/auth/token`, or an access token that
`POST /oauth/token` minted for a resource served here. A `comfyui-` key sent
here counts as `ApiKeyAuth`.
scheme: bearer
type: http
CookieAuth:
description: |
Session cookie authentication. Set automatically after successful
login via the /api/auth/session endpoint.
A POST, PUT, PATCH or DELETE with it is refused with 403 before the
handler runs unless the browser labels it same-origin, its `Origin`
is on the trusted-origins list, or, with no `Sec-Fetch-Site`, its
`Origin` is this host's own: `cross_site_request` for a cross-site
label, `origin_not_allowed` otherwise. The OAuth consent POST takes
it only with an `Origin` that is this host's own, never a trusted
one. This is not behind `web_session_enabled`.
in: cookie
name: session
type: apiKey
WebSessionAuth:
description: |
Server-side web session, set by `POST /api/auth/session`. The media
routes, the short-link redirect, OAuth consent, the custom-node proxy
and the admins' asynqmon UI accept it whatever `web_session_enabled`
says. The user-facing API groups accept it too, for users with the
flag on; machine, admin API and service-token routes never do. A credential in a header always wins and never falls back to
the cookie.
Wherever the cookie is accepted, the request is checked before the
handler runs (403 with the `code` shown):
- `cross_site_request`: the browser labels it `Sec-Fetch-Site:
cross-site`, other than a top-level GET navigation to the short-link
redirect or OAuth consent.
- `origin_not_allowed`: an `Origin` that is not on the trusted-origins
list, unless the call is labelled same-origin; a POST, PUT, PATCH or
DELETE with no `Origin`; or, on API routes, a request without
`X-Comfy-Client`, which SDK clients send with their name and version.
The OAuth consent POST takes the session only from this host's own
origin, so a trusted `Origin` is refused there too.
- `csrf_invalid`: a POST, PUT, PATCH or DELETE without the session's
CSRF token in `X-CSRF-Token`, except on OAuth consent, which checks
its own token, and the asynqmon UI, which cannot send one and is
not checked for it today.
With the flag on, `X-Comfy-Workspace-ID` (or `?workspace_id=` where a
header cannot go) selects the workspace; absent means the personal
workspace. A malformed or conflicting id is 400 `workspace_id_invalid`.
An unknown or deleted workspace, or one the user is not a member of, is
403 `workspace_access_denied`. An account with no personal workspace
(one SSO created) that is no longer a member of any live workspace,
for example after its directory removed its last membership, is 403
`no_workspace_access` on every route that reads the session. All
three are answered on routes that also
serve anonymous callers; there, the other refusals fall back to an
anonymous request, except on the OAuth consent POST, which answers
`origin_not_allowed` and `cross_site_request` too. Today the
short-link redirect and the OAuth consent GET, which a link may
open, do not select a workspace for the session.
A token or API key whose workspace selector names another workspace
than the one it resolves to is 400 `workspace_id_invalid` on these
routes, while the flag is on for its user. A service token, which has
no workspace, ignores the selector.
in: cookie
name: __Host-comfy_session
type: apiKey
info:
description: |
API for ComfyUI - A powerful and modular UI for Stable Diffusion.
This API allows you to interact with ComfyUI programmatically, including:
- Retrieving prompt information
- Retrieving node information
license:
name: GNU General Public License v3.0
url: https://github.com/Comfy-Org/ComfyUI/blob/master/LICENSE
title: ComfyUI API
version: 1.0.0
openapi: 3.0.3
paths:
/api/assets:
get:
description: |
Retrieves a paginated list of assets belonging to the authenticated user.
Supports filtering by tags, name, metadata, and sorting options.
operationId: listAssets
parameters:
- deprecated: true
description: |
Deprecated alias for `tags_all`, kept permanently for existing
callers. Filter assets that have ALL of these tags. Combining it
with `tags_all`, or exceeding 100 tags (counted after removing
empty values and duplicates), returns 400 `INVALID_TAG_FILTER`.
explode: false
in: query
name: include_tags
schema:
items:
type: string
type: array
style: form
- deprecated: true
description: |
Deprecated alias for `tags_none`, kept permanently for existing
callers. Exclude assets that have ANY of these tags. Combining it
with `tags_none`, or exceeding 100 tags (counted after removing
empty values and duplicates), returns 400 `INVALID_TAG_FILTER`.
explode: false
in: query
name: exclude_tags
schema:
items:
type: string
type: array
style: form
- description: |
Filter assets that have ALL of these tags. Tag values are opaque
byte-strings compared exactly and case-sensitively; unknown tags
are not an error — they simply match nothing. Replaces the
deprecated `include_tags`. Sending both spellings, listing the
same tag here and in `tags_none`, or exceeding 100 tags per list
(counted after removing empty values and duplicates) returns 400
`INVALID_TAG_FILTER`.
explode: false
in: query
name: tags_all
schema:
items:
type: string
type: array
style: form
- description: |
Filter assets that have AT LEAST ONE of these tags. Combines with
`tags_all`/`tags_none` by intersection (`tags_none` always wins;
overlap with `tags_none` is allowed and leaves a dead term).
Supplying a positive tag filter (`tags_any`, `tags_all`, or
`include_tags`) replaces the default category filter that is
otherwise applied. Lists over 100 tags (counted after removing
empty values and duplicates) return 400 `INVALID_TAG_FILTER`.
explode: false
in: query
name: tags_any
schema:
items:
type: string
type: array
style: form
- description: |
Exclude assets that have ANY of these tags. Replaces the
deprecated `exclude_tags`. Sending both spellings, or exceeding
100 tags per list (counted after removing empty values and
duplicates), returns 400 `INVALID_TAG_FILTER`.
explode: false
in: query
name: tags_none
schema:
items:
type: string
type: array
style: form
- description: Filter assets where name contains this substring (case-insensitive)
in: query
name: name_contains
schema:
type: string
- description: JSON object for filtering by metadata fields
in: query
name: metadata_filter
schema:
type: string
- description: Maximum number of assets to return (1-500)
in: query
name: limit
schema:
default: 20
maximum: 500
minimum: 1
type: integer
- description: Number of assets to skip for pagination
in: query
name: offset
schema:
default: 0
minimum: 0
type: integer
- description: Field to sort by
in: query
name: sort
schema:
default: created_at
enum:
- name
- created_at
- updated_at
- size
- last_access_time
type: string
- description: Sort order
in: query
name: order
schema:
default: desc
enum:
- asc
- desc
type: string
- description: Whether to include public/shared assets in results
in: query
name: include_public
schema:
default: true
type: boolean
- description: |
Filter assets by content hash, in the canonical `blake3:<hex>`
form. Matches regardless of which of this asset store's two
internal hash storage formats the matching row was written
under (the canonical form used by from-hash-created references,
or the raw `<hex>.<ext>`/bare `<hex>` storage key used by direct
uploads) — both represent the same content hash.
in: query
name: hash
schema:
type: string
- description: |
Opaque cursor for keyset pagination. Pass the `next_cursor` value
from the previous response to fetch the next page. When provided,
`offset` is ignored. Cursor pagination is only supported with
`sort` values `created_at`, `updated_at`, `name`, or `size`;
requests combining `after` with other sort fields return 400.
The cursor must have been minted under the same `sort` value used
in the follow-up request.
in: query
name: after
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/ListAssetsResponse'
description: Success - Assets returned
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request parameters
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: List user assets
tags:
- file
post:
description: |
Creates a new asset from a direct file upload (multipart/form-data) with associated metadata.
If an asset with the same hash already exists, returns the existing asset.
Location metadata is removed, best effort, from JPEG, PNG, WebP and
TIFF files (detected from the file's bytes, not its name) before they
are stored: the EXIF GPS block and whole XMP packets from all four, the
Photoshop/IPTC block from JPEG and TIFF, and PNG "Raw profile" text
chunks. Only a JPEG's first image is kept: everything after its end,
including MPO secondary images (whose MPF index is dropped) and a
motion-photo video, is dropped, as are bytes after a PNG's IEND or
past a WebP's RIFF end.
Dropping a whole XMP or Photoshop block also drops the non-location
fields in it (for example creator, copyright, an AI-generation label or
an XMP-only orientation) and breaks a C2PA signature. Pixels, the EXIF
orientation tag and ComfyUI workflow metadata are kept. A file whose
structure cannot be parsed is stored unchanged, as are other formats (for example HEIC,
AVIF, GIF, BMP and BigTIFF). The returned hash is the hash of the stored
bytes. A JPEG, PNG, WebP or TIFF file over 50 MiB is rejected with 413.
operationId: createAsset
requestBody:
content:
multipart/form-data:
schema:
properties:
file:
description: The asset file to upload
format: binary
type: string
hash:
description: Content hash of the file.
pattern: ^(blake3|sha256):[a-f0-9]{64}$
type: string
id:
description: Optional caller-chosen asset ID. If the upload's content matches an asset you already own in this workspace, that asset is returned and its `id` may differ from the one requested. Otherwise, an ID already taken by any asset is refused with 400 `ASSET_ID_UNAVAILABLE`.
format: uuid
type: string
mime_type:
description: MIME type of the asset (e.g., "image/png", "video/mp4")
type: string
name:
description: Display name for the asset
type: string
preview_id:
description: Optional preview asset ID. Must be your own asset in this workspace; anything else (including a catalog asset, another user's published asset, or an ID that does not exist) is refused with 400 `INVALID_PREVIEW_ID`. If not provided, images use their own ID as preview, except OpenEXR and Radiance HDR, which get no preview; a preview_id equal to the asset's own id is ignored for those.
format: uuid
type: string
tags:
description: JSON-encoded array of freeform tag strings, e.g. '["models","checkpoint"]'. Common types include "models", "input", "output", and "temp", but any tag can be used in any order. At most 64 tags, each a non-empty UTF-8 string of at most 256 bytes (surrounding whitespace included) with no NUL; a request breaking either rule is refused with 400 `INVALID_BODY`. JSON decoding replaces invalid UTF-8 and lone surrogate escapes (e.g. `\ud800`) with U+FFFD (3 bytes each) instead of refusing them, and the 256-byte limit applies to the replaced value.
type: string
user_metadata:
description: Custom JSON metadata as a string
type: string
required:
- file
type: object
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/AssetCreated'
description: |
Asset already existed for this user (deduplicated by content hash); the
existing asset is returned with created_new=false.
"201":
content:
application/json:
schema:
$ref: '#/components/schemas/AssetCreated'
description: Asset created successfully (created_new=true)
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request (bad file, invalid content type, etc.), `INVALID_PREVIEW_ID` when `preview_id` is not your own asset in this workspace, or `ASSET_ID_UNAVAILABLE` when a caller-chosen `id` is already taken
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"413":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: File too large
"415":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unsupported media type
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Validation error (e.g., disallowed model_type tag)
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
"503":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Upload buffer budget exhausted on this pod while buffering an image part; retry after the Retry-After seconds. `code` is `UPLOAD_BUDGET_EXHAUSTED`.
headers:
Retry-After:
description: Seconds to wait before retrying
schema:
type: integer
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Create a new asset
tags:
- file
/api/assets/{id}:
delete:
description: Deletes the asset record.
operationId: deleteAsset
parameters:
- description: Asset ID
in: path
name: id
required: true
schema:
format: uuid
type: string
responses:
"204":
description: Asset record deleted successfully
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Asset not found
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 'Asset cannot be deleted because it is referenced by another resource, e.g. a workflow version, or because content moderation still holds it (error code: ASSET_IN_USE for both; a moderation hold is deliberately not distinguishable)'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Delete asset
tags:
- file
get:
description: Retrieves detailed information about a specific asset
operationId: getAssetById
parameters:
- description: Asset ID
in: path
name: id
required: true
schema:
format: uuid
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/Asset'
description: Asset details retrieved successfully
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Asset not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get asset details
tags:
- file
put:
description: |
Updates an asset's metadata. At least one field must be provided.
Only name, mime_type, preview_id, and user_metadata can be updated.
For tag management, use POST (add) and DELETE (remove) /api/assets/{id}/tags.
operationId: updateAsset
parameters:
- description: Asset ID
in: path
name: id
required: true
schema:
format: uuid
type: string
requestBody:
content:
application/json:
schema:
minProperties: 1
properties:
mime_type:
description: Updated MIME type of the asset
type: string
name:
description: New display name for the asset
type: string
preview_id:
description: Updated preview asset ID. Must be your own asset in this workspace.
format: uuid
type: string
user_metadata:
additionalProperties: true
description: Updated custom metadata
type: object
type: object
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/AssetUpdated'
description: Asset updated successfully
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: |
Invalid request — no fields provided, or `preview_id` is the zero UUID
(`INVALID_PREVIEW_ID`).
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: |
Asset not found — returned both when the asset being updated does
not exist and when `preview_id` is not your own asset in this
workspace (a catalog asset or another user's published asset
does not qualify).
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Update asset metadata
tags:
- file
/api/assets/{id}/content:
get:
description: |
Returns the binary content of an asset by ID.
The contract is the same across runtimes — "GET this path and you
receive the asset's bytes" — but the mechanism differs:
- **Local ComfyUI** streams the bytes directly (`200`,
`application/octet-stream`).
- **Cloud** does not proxy large files; it responds `302` with a
`Location` redirect to a short-lived signed storage URL. Clients that
follow redirects (browsers, `fetch`/XHR, `<img>`/`<video>`) receive
the bytes transparently.
Prefer this over the filename-addressed `/api/view` when you have an
asset ID.
An `<img>`, `<video>` or `<audio>` tag loads this with the
`WebSessionAuth` or `CookieAuth` cookie, both accepted whatever
`web_session_enabled` says; neither needs `X-CSRF-Token` or
`X-Comfy-Client`, which a media tag cannot send. A 403
AuthTypeNotAllowedError here is a credential the route never takes,
such as `X-ComfyAPI-Secret`, never the session.
operationId: getAssetContent
parameters:
- description: Asset ID
in: path
name: id
required: true
schema:
type: string
- description: |
Content-Disposition for the response: `attachment` (download) or
`inline` (render in browser). Defaults to `attachment`.
in: query
name: disposition
schema:
default: attachment
enum:
- inline
- attachment
type: string
- content:
text/plain:
schema:
type: string
description: The workspace a media request reads from, where a media tag cannot send `X-Comfy-Workspace-ID`; see the `MediaWorkspaceID` parameter.
in: query
name: workspace_id
responses:
"200":
content:
application/octet-stream:
schema:
format: binary
type: string
description: Asset content stream (local runtime streams the bytes directly)
"302":
description: Redirect to a signed storage URL (cloud runtime)
headers:
Cache-Control:
description: Private caching directive scoped to the signed URL lifetime
schema:
type: string
Location:
description: Short-lived signed URL to the asset content in storage
schema:
type: string
Vary:
description: Partitions any cached redirect by auth credentials so a private redirect is not reused across users
schema:
type: string
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: '`code` `workspace_id_invalid`: the `workspace_id` or `X-Comfy-Workspace-ID` value is malformed, the two disagree, or, with the flag on, a token or API key names another workspace than its own. Or `BAD_REQUEST` from the generated wrapper when a parameter does not bind, such as a repeated `disposition`.'
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Asset not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- CookieAuth: []
- WebSessionAuth: []
summary: Get asset content
tags:
- file
/api/assets/{id}/tags:
delete:
description: Removes one or more tags from an existing asset
operationId: removeAssetTags
parameters:
- description: Asset ID
in: path
name: id
required: true
schema:
format: uuid
type: string
requestBody:
content:
application/json:
schema:
properties:
tags:
description: Tags to remove from the asset
items:
type: string
minItems: 1
type: array
required:
- tags
type: object
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/TagsModificationResponse'
description: Tags removed successfully
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Asset not found
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Validation error (e.g., reserved tag)
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Remove tags from asset
tags:
- file
post:
description: Adds one or more tags to an existing asset
operationId: addAssetTags
parameters:
- description: Asset ID
in: path
name: id
required: true
schema:
format: uuid
type: string
requestBody:
content:
application/json:
schema:
properties:
tags:
description: Tags to add to the asset. At most 64 tags, each a non-empty UTF-8 string of at most 256 bytes (surrounding whitespace included) with no NUL; a request breaking either rule is refused with 400 `INVALID_BODY`. An add that would grow the asset's stored set (server-added tags included) past 64 is refused the same way; an asset already over 64 is not trimmed and can still re-apply its stored non-category tags that add no new server-derived tag (`input`, `output`, `temp` and `models` are refused with 422 `RESERVED_TAG` before any count check; re-applying a legacy bare model-directory tag whose `model_type:` twin is not stored adds that twin, so it counts as growth). The counted set is the stored one, which the response's `total_tags` need not equal, as it hides stored `model_type:` tags or shows synthesized ones, depending on the deployment. JSON decoding replaces invalid UTF-8 and lone surrogate escapes (e.g. `\ud800`) with U+FFFD (3 bytes each) instead of refusing them, and the 256-byte limit applies to the replaced value.
items:
type: string
maxItems: 64
minItems: 1
type: array
required:
- tags
type: object
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/TagsModificationResponse'
description: Tags added successfully
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Asset not found
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Validation error (e.g., reserved tag)
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Add tags to asset
tags:
- file
/api/assets/from-hash:
post:
description: |
Creates a new asset reference using an existing asset's hash.
This avoids re-uploading the file content when the asset already exists in storage.
The user can provide their own metadata and tags for the reference.
operationId: createAssetFromHash
requestBody:
content:
application/json:
schema:
properties:
hash:
description: 'Blake3 content hash of the existing asset (blake3: prefix)'
pattern: ^blake3:[a-f0-9]{64}$
type: string
mime_type:
description: MIME type of the asset (e.g., "image/png", "video/mp4")
type: string
name:
description: Display name for the asset reference (optional)
type: string
tags:
description: Freeform tags for the asset. Common types include "models", "input", "output", and "temp", but any tag can be used in any order. At most 64 tags, each a non-empty UTF-8 string of at most 256 bytes (surrounding whitespace included) with no NUL; a request breaking either rule is refused with 400 `INVALID_BODY`. JSON decoding replaces invalid UTF-8 and lone surrogate escapes (e.g. `\ud800`) with U+FFFD (3 bytes each) instead of refusing them, and the 256-byte limit applies to the replaced value.
items:
type: string
maxItems: 64
minItems: 1
type: array
user_metadata:
additionalProperties: true
description: Custom metadata for this asset reference
type: object
required:
- hash
- tags
type: object
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/AssetCreated'
description: |
Asset reference already existed for this user (deduplicated by content
hash); the existing asset is returned with created_new=false.
"201":
content:
application/json:
schema:
$ref: '#/components/schemas/AssetCreated'
description: Asset reference created successfully (created_new=true)
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request (bad hash format, invalid tags, etc.)
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Source asset with given hash not found
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Validation error (e.g., disallowed model_type tag)
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Create asset reference from existing hash
tags:
- file
/api/assets/hash/{hash}:
head:
description: |
Checks if an asset exists in the system by its blake3 hash.
Returns 200 if the asset exists, 404 if it doesn't.
operationId: checkAssetByHash
parameters:
- description: Blake3 hash of the asset in format 'blake3:hex_digest'
in: path
name: hash
required: true
schema:
example: blake3:a1b2c3d4e5f67890123456789012345678901234567890123456789012345678
pattern: ^blake3:[a-f0-9]{64}$
type: string
responses:
"200":
description: Asset exists
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid hash format
"401":
description: No valid credential (see SessionUnauthorized). No body.
"403":
description: A refused web session request, or the route's own authorization check failing (see SessionForbidden). A HEAD response has no body, so the code is not sent.
"404":
description: Asset not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Check if asset exists by hash
tags:
- file
/api/assets/prune:
post:
description: Starts a background job that removes asset entries whose underlying content no longer exists on disk.
operationId: pruneAssets
responses:
"200":
content:
application/json:
schema:
properties:
marked:
description: Number of assets marked as missing
type: integer
status:
type: string
type: object
description: Prune result
summary: Mark assets whose backing files no longer exist on disk
/api/assets/seed:
post:
description: Starts a background job that scans configured directories and registers assets not yet in the asset database.
operationId: seedAssets
requestBody:
content:
application/json:
schema:
properties:
roots:
description: Root folder paths to scan (if omitted, scans all)
items:
type: string
type: array
type: object
responses:
"200":
content:
application/json:
schema:
properties:
status:
type: string
type: object
description: Seed started
summary: Trigger asset scan/seed from filesystem
/api/assets/seed/cancel:
post:
description: Requests cancellation of the currently-running asset seed job.
operationId: cancelAssetSeed
responses:
"200":
content:
application/json:
schema:
properties:
status:
type: string
type: object
description: Scan cancelled
summary: Cancel an in-progress asset scan
/api/assets/seed/status:
get:
description: Returns progress/status of the most recent asset seed job.
operationId: getAssetSeedStatus
responses:
"200":
content:
application/json:
schema:
additionalProperties: true
description: Scan progress details (files scanned, total, status, etc.)
type: object
description: Scan progress
summary: Get asset scan progress
/api/assets/tags/refine:
get:
description: |
Returns a histogram of tags appearing on assets matching the given filters.
Useful for refining asset searches by showing available tags and their counts.
Only returns tags with non-zero counts (tags that exist on matching assets).
operationId: getAssetTagHistogram
parameters:
- deprecated: true
description: |
Deprecated alias for `tags_all`, kept permanently for existing
callers. Filter assets that have ALL of these tags. The same
combination and list-size rules as on `/api/assets` apply
(400 `INVALID_TAG_FILTER`).
explode: false
in: query
name: include_tags
schema:
items:
type: string
type: array
style: form
- deprecated: true
description: |
Deprecated alias for `tags_none`, kept permanently for existing
callers. Exclude assets that have ANY of these tags. The same
combination and list-size rules as on `/api/assets` apply
(400 `INVALID_TAG_FILTER`).
explode: false
in: query
name: exclude_tags
schema:
items:
type: string
type: array
style: form
- description: |
Filter assets that have ALL of these tags. Replaces the deprecated
`include_tags`. The same combination and list-size rules as on
`/api/assets` apply (400 `INVALID_TAG_FILTER`).
explode: false
in: query
name: tags_all
schema:
items:
type: string
type: array
style: form
- description: |
Filter assets that have AT LEAST ONE of these tags. Combines with
`tags_all`/`tags_none` by intersection (`tags_none` always wins).
The same combination and list-size rules as on `/api/assets` apply
(400 `INVALID_TAG_FILTER`).
explode: false
in: query
name: tags_any
schema:
items:
type: string
type: array
style: form
- description: |
Exclude assets that have ANY of these tags. Replaces the deprecated
`exclude_tags`. The same combination and list-size rules as on
`/api/assets` apply (400 `INVALID_TAG_FILTER`).
explode: false
in: query
name: tags_none
schema:
items:
type: string
type: array
style: form
- description: Filter assets where name contains this substring (case-insensitive)
in: query
name: name_contains
schema:
type: string
- description: JSON object for filtering by metadata fields
in: query
name: metadata_filter
schema:
type: string
- description: Maximum number of tags to return (1-1000, default 100)
in: query
name: limit
schema:
default: 100
maximum: 1000
minimum: 1
type: integer
- description: Whether to include public/shared assets in results
in: query
name: include_public
schema:
default: true
type: boolean
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/AssetTagHistogramResponse'
description: Success - Tag histogram returned
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request parameters
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get tag histogram for filtered assets
tags:
- file
/api/billing/churnkey/auth:
get:
description: |
Returns the Stripe customer identifier and a server-signed
HMAC-SHA256 of the customer ID, used to launch the Churnkey-hosted
cancellation flow embed.
operationId: getChurnkeyAuth
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/ChurnkeyAuthResponse'
description: Success
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Workspace has no Stripe customer (never subscribed)
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
"503":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Churnkey is not configured on the server
security:
- BearerAuth: []
- WebSessionAuth: []
summary: Get Churnkey HMAC auth credentials
tags:
- billing
/api/billing/retention/accept:
post:
description: |
Owner-only, workspace-scoped cancellation flow. Cloud decides eligibility,
PostHog assigns the experiment arm, and billing-api binds any offer to a
server-issued session. The browser never sends coupon terms. A
non-owner gets `FORBIDDEN`, an owner who is not the creator gets
`NOT_ORIGINAL_OWNER` when the rollout mode is `creator`, and accepting a
session without an offer gets `RETENTION_NOT_ALLOWED`.
Poll the returned billing operation until it settles.
operationId: acceptRetentionOffer
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/RetentionAcceptRequest'
required: true
responses:
"202":
content:
application/json:
schema:
$ref: '#/components/schemas/RetentionAcceptance'
description: Success
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Session stale or a billing operation conflicts
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
"503":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Cancellation offers unavailable
security:
- BearerAuth: []
- WebSessionAuth: []
summary: Accept the retention offer for this cancellation session
tags:
- billing
/api/billing/retention/events:
post:
description: |
Owner-only, workspace-scoped cancellation flow. Cloud decides eligibility,
PostHog assigns the experiment arm, and billing-api binds any offer to a
server-issued session. The browser never sends coupon terms. A
non-owner gets `FORBIDDEN`, an owner who is not the creator gets
`NOT_ORIGINAL_OWNER` when the rollout mode is `creator`, and accepting a
session without an offer gets `RETENTION_NOT_ALLOWED`.
Events are recorded only for sessions assigned an experiment arm.
operationId: recordRetentionFlowEvent
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/RetentionFlowEventRequest'
required: true
responses:
"204":
description: Success
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Session stale or a billing operation conflicts
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
"503":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Cancellation offers unavailable
security:
- BearerAuth: []
- WebSessionAuth: []
summary: Record cancellation participation or an actual offer display
tags:
- billing
/api/billing/retention/prepare:
post:
description: |
Owner-only, workspace-scoped cancellation flow. Cloud decides eligibility,
PostHog assigns the experiment arm, and billing-api binds any offer to a
server-issued session. The browser never sends coupon terms. A
non-owner gets `FORBIDDEN`, an owner who is not the creator gets
`NOT_ORIGINAL_OWNER` when the rollout mode is `creator`, and accepting a
session without an offer gets `RETENTION_NOT_ALLOWED`.
Preparing a session does not cancel the subscription.
operationId: prepareRetentionFlow
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/RetentionFlowResponse'
description: Success
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Subscription does not support this flow, or cancellation offers are switched off
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
"503":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Cancellation offers unavailable
security:
- BearerAuth: []
- WebSessionAuth: []
summary: Prepare a cancellation session and any retention offer
tags:
- billing
/api/default_workflow:
get:
description: Returns the workflow the frontend loads when no other workflow is open.
operationId: getDefaultWorkflow
responses:
"200":
content:
application/json:
schema:
additionalProperties: true
type: object
description: Default workflow JSON
security: []
summary: Get the default workflow
tags:
- workflow
/api/deploy/bundle:
post:
description: On explicit user action, collects this installation's snapshot (comfyui-desktop-2-snapshot) and installed model list, sends them with the optional workflow and name to comfy-builder's POST /v1/import-bundles, and returns the Create a Build wizard link that opens it. The caller's credential is forwarded verbatim and never stored; exactly one of a Bearer Authorization header or an X-API-Key header must be sent. Never available under --offline.
operationId: createDeployBundle
requestBody:
content:
application/json:
schema:
description: A JSON object; `{}` is valid. Null members count as absent.
properties:
name:
description: Optional label for the bundle.
maxLength: 200
nullable: true
type: string
workflow:
additionalProperties: true
description: The workflow open in ComfyUI, sent as is.
nullable: true
type: object
type: object
required: true
responses:
"200":
content:
application/json:
schema:
properties:
bundle_id:
format: uuid
type: string
expires_at:
description: When the bundle stops being readable (24 hours after creation).
format: date-time
type: string
url:
description: The Create a Build wizard link that opens the bundle (/profile/builds/new?step=import&bundle=&workspace=&bundle_workspace=).
format: uri
type: string
workspace_id:
description: The workspace the bundle belongs to (the credential's).
type: string
required:
- url
- bundle_id
- workspace_id
- expires_at
type: object
description: Bundle stored on comfy-builder
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/DeployToCloudError'
description: 'Rejected before upload: `multiple_credentials` (both headers sent), `invalid_api_key_format` (X-API-Key is not comfyui- followed by 64 hex characters) or `invalid_body` (not a JSON object, or a bad workflow or name).'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/DeployToCloudError'
description: '`missing_credentials` (no credential sent) or `unauthorized` (the builder refused the credential).'
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/DeployToCloudError'
description: '`offline` (the server runs with --offline) or `unauthorized` (the builder refused the credential).'
"413":
content:
application/json:
schema:
$ref: '#/components/schemas/DeployToCloudError'
description: The bundle exceeds the builder's size cap (`too_large`).
"429":
content:
application/json:
schema:
$ref: '#/components/schemas/DeployToCloudError'
description: The user already holds the builder's limit of unexpired bundles in this workspace (`too_many_bundles`); clears as older bundles expire.
"502":
content:
application/json:
schema:
$ref: '#/components/schemas/DeployToCloudError'
description: '`builder_rejected` (the builder refused the bundle as invalid; `message` carries its reason, at most 500 characters) or `builder_unavailable` (the builder could not be reached or answered unexpectedly).'
"503":
content:
application/json:
schema:
$ref: '#/components/schemas/DeployToCloudError'
description: The builder is busy (`builder_busy`); retry after Retry-After seconds when present.
headers:
Retry-After:
description: Seconds to wait, when the builder sent one.
schema:
type: integer
security:
- BearerAuth: []
- ApiKeyAuth: []
summary: Upload this installation to Cloud as an import bundle
/api/deploy/summary:
get:
description: Counts the custom nodes and model files this local installation would send in an import bundle, so the UI can describe the upload before the user confirms it. Local reads only; makes no network request.
operationId: getDeploySummary
responses:
"200":
content:
application/json:
schema:
properties:
custom_nodes:
description: Custom node packages found in the custom_nodes folders
type: integer
models:
description: Model files found across the model folders
type: integer
required:
- custom_nodes
- models
type: object
description: Counts of what the bundle would include
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/DeployToCloudError'
description: The server runs with --offline (error `offline`)
security: []
summary: Count what a Deploy to Cloud bundle would carry
/api/embeddings:
get:
description: Returns the list of text-encoder embeddings available on disk.
operationId: getEmbeddings
responses:
"200":
content:
application/json:
schema:
items:
type: string
type: array
description: Embedding names
summary: List available embedding names
/api/experiment/models:
get:
description: |
Returns a list of model folders available in the system.
This is an experimental endpoint that replaces the legacy /models endpoint.
Each folder's name is the identifier to pass to /api/experiment/models/{folder}.
The folder vocabulary is resolved per request from the caller's identity: where the
model_type migration is active for that caller the names are model_type folder_names
(e.g. `ultralytics_bbox`), and a folder with no folder_name mapping is returned by its
directory path. An authenticated response can therefore differ from an anonymous one.
operationId: getModelFolders
responses:
"200":
content:
application/json:
schema:
items:
$ref: '#/components/schemas/ModelFolder'
type: array
description: Success - List of model folders
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"403":
$ref: '#/components/responses/SessionWorkspaceAccessDenied'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
- {}
summary: Get available model folders
tags:
- file
/api/experiment/models/{folder}:
get:
description: |
Returns a list of models available in the specified folder.
This is an experimental endpoint that provides enhanced model information.
Accepted folder identifiers are those returned by /api/experiment/models for the same
caller. That vocabulary is request-scoped, so list folders and fetch a folder's models
with the same credentials — a name obtained anonymously may not resolve when
authenticated, and vice versa.
operationId: getModelsInFolder
parameters:
- description: The folder name to list models from
in: path
name: folder
required: true
schema:
example: checkpoints
type: string
responses:
"200":
content:
application/json:
schema:
items:
$ref: '#/components/schemas/ModelFile'
type: array
description: Success - List of models in the folder
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"403":
$ref: '#/components/responses/SessionWorkspaceAccessDenied'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Folder not found or no models in folder
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
- {}
summary: Get models in a specific folder
tags:
- file
/api/extensions:
get:
description: |
Returns the list of custom node web extension JS files available for
loading by the ComfyUI frontend. Paths are relative to the web root
(e.g. `/extensions/VHS.core.js`). For a browser that picked a
developer-platform deployment (the cookie PUT
/api/workspaces/{id}/deployment sets) the list is the files of the
Release that deployment runs now, each at a release-scoped path,
`/extensions/<pack>@<workspace id>@<release id>/<rel>`; otherwise, and
for anonymous callers, it is the static list.
The `/extensions/*` files the browser then imports carry no
Authorization header, and cookie authentication resolves only a
personal workspace, so the scoped path itself names the workspace and
the Release. A scoped path is served the Release's file, with
`Cache-Control: private, max-age=31536000, immutable` and
`Vary: Sec-Fetch-Site`, to a member of the workspace it names when the
Release is that workspace's, and is a 404 otherwise. A path with no scope is always the static file, whatever
the browser picked.
operationId: getExtensions
responses:
"200":
content:
application/json:
schema:
description: URL paths (relative to web root) of available extension JS files
items:
type: string
type: array
description: JSON array of extension file paths
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"403":
$ref: '#/components/responses/SessionWorkspaceAccessDenied'
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
- {}
summary: List custom node JS extensions
tags:
- node
/api/features:
get:
description: Returns the server's feature capabilities
operationId: getFeatures
responses:
"200":
content:
application/json:
schema:
additionalProperties: true
properties:
agent:
description: 'Present when the caller passes the agent-in-app-experience rollout gate that /api/agent/* also enforces; the frontend mounts the agent panel only when it is. Absent when the gate is off and for unauthenticated requests. It answers the rollout question only: it does not reflect a scoped OAuth token''s agent scope or whether the agent service is currently reachable.'
properties:
state:
enum:
- ready
type: string
required:
- state
type: object
agent-free-use-message-placement:
default: control
description: Authenticated assignment for the Agent free-use notice placement experiment. Current Cloud responses include it and default to control when the caller is unauthenticated, evaluation is unavailable, or no treatment is assigned. It remains optional in the client contract, as agent-starter-prompt-set does, so older environments mid-rolling-deploy and partial feature fixtures fail closed rather than decoding an absent field as the empty string, which is not a member of this enum.
enum:
- control
- top-banner
- near-composer
- above-input
- inside-input
type: string
agent-starter-prompt-set:
default: control
description: Authenticated assignment for the Agent starter-prompt experiment. Current Cloud responses include it and default to control when the caller is unauthenticated, evaluation is unavailable, or no treatment is assigned. It remains optional in the client contract so older environments and partial feature fixtures fail closed. Reading this field does not constitute experiment exposure; the frontend emits the custom exposure event only after rendering the starter prompt surface.
enum:
- control
- test
type: string
billing_web_url:
description: Origin of the billing-web deployment paired with this Cloud environment (e.g. https://billing.comfy.org). Absent when BILLING_WEB_URL is not configured on the server, so a client can tell "not configured" from "configured as empty".
type: string
can_run_partner_nodes:
description: |-
Whether a partner/API-node workflow from THIS authenticated caller could run. It is ingest's own submit-time account-level decision published as a capability, resolved from the same authority ExecutePrompt uses, so a consumer never re-derives it from a tier table.
The two values are NOT symmetric, and a consumer that treats them as symmetric will be wrong.
false is sound: a partner-node submission from this caller would be refused. Usually that refusal is PARTNER_NODE_PAYMENT_REQUIRED, but a caller who is FREE for a further reason (an API key, a non-Google session under FreeTierRequireGoogleSignIn, or no job allowance on the legacy rail) is refused earlier and by a different code. Either way the workflow does not run, which is what the field answers.
true is narrower than it reads: the partner-node paywall is not what refuses this caller. Another gate still might — an inactive subscription, a blocked workspace and a BlockedSubscriptionTiers entry all report true, because their refusal is account-wide rather than about partner nodes, and so do the exemptions and the fail-open outcomes that make ExecutePrompt admit a submission at all (a partner-execution workspace, a disabled subscription check, a failed subscription lookup). Two per-prompt refusals are not modelled here at all, because this field is per-account and they are not: FreeTierBlockedModels (MODEL_PAYMENT_REQUIRED, named open-weights models) and the workspace partner-provider governance gate, which keys on which providers a prompt names and answers 403 for an enforcing workspace or 503 when its policy cannot be verified. A paid caller in a governance-restricted workspace therefore reads true here and is still refused at submit.
So: read false as "do not build with partner nodes" and true as "the partner gate will not stop you". Do not read true as "this caller can submit".
Absent for an unauthenticated caller (the decision is per-identity and there is none) and absent while AgentPartnerCapabilityEnabled is off, which is its default — resolving it costs an account-level authority read that this endpoint does not otherwise make. A consumer must treat absence as "unknown" and fail open, never as false.
Because absence carries that meaning, the field is only ever the authority's answer: unlike the flags beside it, it cannot be set from dynamic configuration, and it is removed from the response rather than left at a configured value when it is unresolvable. It is likewise absent from the WebSocket feature_flags push, which resolves no capability, so a client refreshing from the socket reads "unknown" and fails open rather than inheriting a stale answer.
type: boolean
deploy_to_cloud:
description: 'Local ComfyUI only: whether the UI should offer Deploy to Cloud. True when the server is not --offline and this installation has ever had a prompt queued by a non-browser client (a persistent marker in the user directory). A discovery hint only: it grants nothing, and the /api/deploy/* routes do not check it. Not settable with --feature-flag.'
type: boolean
x-runtime:
- local
free_tier_balance:
description: Free-tier job allowance for an authenticated non-paid (FREE-tier) user in the rollout. Absent for paid users and unauthenticated requests. Synthesized from config before a grant row exists so a brand-new user still sees their full allowance.
properties:
allowance:
description: Total free jobs granted for the current period
type: integer
remaining:
description: Free jobs remaining (allowance - used, floored at 0)
type: integer
used:
description: Free jobs consumed so far
type: integer
required:
- allowance
- used
- remaining
type: object
free_tier_offer:
description: The free-tier job allowance offered to new users, so a signed-out visitor sees the real offer before signing up. Same value for authenticated and unauthenticated requests. Absent when the free-tier allowance is disabled or zero.
properties:
job_allowance:
description: Number of free jobs granted to a new FREE-tier user
type: integer
requires_google_sign_in:
description: True when only Google-authenticated sessions receive the allowance; email/password signups get none.
type: boolean
required:
- job_allowance
- requires_google_sign_in
type: object
max_upload_size:
description: Maximum upload size in bytes
type: integer
new_free_tier_subscriptions:
description: Whether new free-tier subscriptions are enabled for this caller. Current servers always emit a boolean; clients should tolerate absence when talking to older servers that predate this declared field.
type: boolean
sso_enabled:
description: Global switch, the same for every caller and readable without credentials. When true, the frontend shows enterprise single sign-on (the SSO sign-in entry and SSO workspace states); when false it shows today's app. It gates no backend behaviour. Defaults to false.
type: boolean
stripe_publishable_key:
description: Stripe publishable key (pk_...) for the environment's Stripe account. Public by design (the secret key is never exposed here). Absent when STRIPE_PUBLISHABLE_KEY is not configured on the server, so a client can tell "not configured" from "configured as empty".
type: string
supports_preview_metadata:
description: Whether the server supports preview metadata
type: boolean
web_session_probe:
description: Global switch, the same for every caller and readable without credentials. When true, first-party sites send the credentialed /api/features read and take behaviour from its per-user unified_web_session. It grants nothing itself. Defaults to false.
type: boolean
type: object
description: Success
headers:
Cache-Control:
description: Short-lived private cache to deduplicate rapid-fire calls from the frontend
schema:
type: string
Vary:
description: Cache key includes auth headers so anonymous and authenticated responses are stored separately
schema:
type: string
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"403":
$ref: '#/components/responses/SessionWorkspaceAccessDenied'
security:
- ApiKeyAuth: []
- BearerAuth: []
- {}
- WebSessionAuth: []
summary: Get server feature flags
tags:
- node
/api/feedback:
post:
description: Submit feedback about the ComfyUI service
operationId: submitFeedback
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/FeedbackRequest'
required: true
responses:
"201":
content:
application/json:
schema:
$ref: '#/components/schemas/FeedbackResponse'
description: Feedback submitted successfully
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Submit user feedback
tags:
- feedback
/api/files/mask-layers:
get:
description: |
Given a mask file (any of the 4 layers), returns all related mask layer files.
This is used by the mask editor to load the paint, mask, and painted layers
when reopening a previously edited mask.
operationId: getMaskLayers
parameters:
- description: Hash filename of any mask layer file
in: query
name: filename
required: true
schema:
example: abc123def456.png
type: string
responses:
"200":
content:
application/json:
schema:
properties:
mask:
description: Filename of the mask layer
nullable: true
type: string
paint:
description: Filename of the paint strokes layer
nullable: true
type: string
painted:
description: Filename of the painted image layer
nullable: true
type: string
painted_masked:
description: Filename of the final composite layer
nullable: true
type: string
type: object
description: Success - Related mask layers returned
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: File not found or not a mask file
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get related mask layer files
tags:
- file
/api/free:
post:
description: Frees GPU memory by unloading models and/or freeing the resident model cache.
operationId: freeMemory
requestBody:
content:
application/json:
schema:
properties:
free_memory:
description: Run garbage collection and free cached memory
type: boolean
unload_models:
description: Unload all models from VRAM/RAM
type: boolean
type: object
responses:
"200":
description: Memory freed
summary: Free GPU memory and/or unload models
/api/global_subgraphs:
get:
description: |
Returns a list of globally available subgraph blueprints.
These are pre-built workflow components that can be used as nodes.
The data field contains a promise that resolves to the full subgraph JSON.
operationId: getGlobalSubgraphs
responses:
"200":
content:
application/json:
schema:
additionalProperties:
$ref: '#/components/schemas/GlobalSubgraphInfo'
type: object
description: Success - Map of subgraph IDs to their metadata
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security: []
summary: Get available subgraph blueprints
tags:
- workflow
/api/global_subgraphs/{id}:
get:
description: Returns the full data for a specific subgraph blueprint by ID
operationId: getGlobalSubgraph
parameters:
- description: The unique identifier of the subgraph blueprint
in: path
name: id
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/GlobalSubgraphData'
description: Success - Full subgraph data
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Subgraph not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security: []
summary: Get a specific subgraph blueprint
tags:
- workflow
/api/history:
post:
deprecated: true
description: |
**Deprecated.** Superseded by the job-management endpoints under
`/api/jobs`. Planned for removal no earlier than a future major
release; sunset timeline TBD.
Clear all history for the authenticated user or delete specific job IDs.
Supports clearing all history or deleting specific job IDs.
operationId: manageHistory
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/HistoryManageRequest'
required: true
responses:
"200":
description: Success - History management operation completed
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request parameters
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Manage execution history
tags:
- workflow
/api/history_v2:
get:
deprecated: true
description: |
**Deprecated.** Superseded by `GET /api/jobs`, which returns the same
execution records in a paginated, filterable format. Planned for removal
no earlier than a future major release; sunset timeline TBD.
Retrieve execution history for the authenticated user with pagination support.
Returns a lightweight history format with filtered prompt data (workflow removed from extra_pnginfo).
operationId: getHistory
parameters:
- description: Maximum number of items to return
in: query
name: max_items
schema:
type: integer
- description: Starting position (default 0)
in: query
name: offset
schema:
default: 0
type: integer
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/HistoryResponse'
description: Success - Execution history retrieved
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get execution history (v2)
tags:
- workflow
/api/history_v2/{prompt_id}:
get:
deprecated: true
description: |
**Deprecated.** Superseded by `GET /api/jobs/{job_id}`, which returns
the same execution record. Planned for removal no earlier than a future
major release; sunset timeline TBD.
Retrieve detailed execution history for a specific prompt ID.
Returns full history data for the recorded prompt, except the
canvas-format workflow graph: `extra_data.extra_pnginfo` is no longer
persisted, so it is not included in history records persisted after
that change (older records may still carry it). Callers that need the
workflow graph should use `GET /api/jobs/{job_id}`, which serves it
from the job's own stored workflow — `prompt_id` is the job ID, so it
can be passed straight through as `job_id`.
operationId: getHistoryForPrompt
parameters:
- description: The prompt ID to retrieve history for
in: path
name: prompt_id
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/HistoryDetailResponse'
description: Success - History for prompt retrieved
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Prompt not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get history for specific prompt
tags:
- workflow
/api/i18n:
get:
description: Returns translation file URLs contributed by custom nodes, keyed by locale.
operationId: getI18n
responses:
"200":
content:
application/json:
schema:
additionalProperties: true
description: Nested map of locale to translation key-value pairs
type: object
description: Translation map
summary: Get internationalisation translation strings
/api/interrupt:
post:
deprecated: true
description: |
Deprecated. Prefer the jobs-namespace cancel endpoints:
POST /api/jobs/{job_id}/cancel for a single job, or
POST /api/jobs/cancel to cancel jobs by ID.
Cancels one job of the authenticated user's. The body is optional, as
on ComfyUI's own /interrupt, and is never refused: it is read whatever
its Content-Type (a browser fetch with a string body sends text/plain),
up to 64 KiB, and never answers 400 or 415.
When the body is a JSON object whose `prompt_id` is a non-empty string
(the ComfyUI frontend sends `{"prompt_id": "<job id>"}` naming the job
it shows running), that job and no other, exactly as
POST /api/jobs/{job_id}/cancel acts on it: a pending or running job is
cancelled; one already finished or cancelling is left as it is (200,
nothing done); an ID that is not one of the
caller's jobs in this workspace, or is not a job ID (a 36-character
UUID) at all, returns 404 and cancels nothing.
In every other case the job is picked by queue order: no body, an
empty body, `{}`, a `prompt_id` that is absent, null, empty or not a
string, a body that is not a JSON object (malformed JSON, an array, a
non-JSON body), or a body longer than 64 KiB. The job, in order:
1. If a job is running on Cloud: the oldest such job.
2. Otherwise, if a job that runs on a Build's deployment (the platform
gateway) is running: the oldest one.
3. Otherwise (nothing running) the oldest pending job on Cloud, even
when an older pending job runs on a Build's deployment.
4. Otherwise the oldest pending job that runs on a Build's deployment.
The job is cancelled; for a job that runs on a Build's deployment, the
deployment is then asked to stop its run, best effort and after this
answers: not when the platform cannot be reached, or does not yet know
the API key the request was made with (the run then continues until it
ends on its own, and the job still ends cancelled).
operationId: interruptJob
responses:
"200":
description: |
Success - the job was cancelled, was already finished or
cancelling, or (without `prompt_id`) no active job was found
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: |
`prompt_id` is not one of the caller's jobs in this workspace, or
is not a job ID (a 36-character UUID) at all. Code NOT_FOUND;
nothing was cancelled.
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Interrupt a job, the named one or the first active one
tags:
- queue
/api/job/{job_id}/status:
get:
deprecated: true
description: |
**Deprecated.** Superseded by `GET /api/jobs/{job_id}` (plural path).
Clients should migrate; the endpoint is retained for backward
compatibility but will be removed in a future release.
operationId: getJobStatus
parameters:
- description: The unique ID of the job
in: path
name: job_id
required: true
schema:
format: uuid
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/JobStatusResponse'
description: Success - Job status returned
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Forbidden - job belongs to another user
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Job not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get job status (deprecated)
tags:
- job
/api/jobs:
get:
description: |
Retrieve a paginated list of jobs for the authenticated user.
Returns lightweight job data optimized for list views.
Workflow and full outputs are excluded to reduce payload size.
Each job says what ran it (`executor`) and, for a job that ran on a
deployment, which deployment and Release (`deployment`). The `deployment`
field and the `JobDeployment` schema say when each is absent.
operationId: listJobs
parameters:
- description: Filter by one or more statuses (comma-separated). If not provided, returns all jobs.
example: pending,in_progress
in: query
name: status
schema:
type: string
- description: Filter by workflow ID (exact match)
example: 550e8400-e29b-41d4-a716-446655440000
in: query
name: workflow_id
schema:
type: string
- description: Filter by output media type (only applies to completed jobs with outputs)
example: image
in: query
name: output_type
schema:
enum:
- image
- video
- audio
- 3d
type: string
- description: Field to sort by (create_time = when job was submitted, execution_time = how long workflow took to run)
example: execution_time
in: query
name: sort_by
schema:
default: create_time
enum:
- create_time
- execution_time
type: string
- description: Sort direction (asc = ascending, desc = descending)
in: query
name: sort_order
schema:
default: desc
enum:
- asc
- desc
type: string
- description: |
Opaque cursor for keyset pagination. Pass the `next_cursor` value
from a previous response to fetch the next page.
Cursor pagination is supported only when `sort_by=create_time`
(default). If `sort_by=execution_time`, `after` is ignored and
offset/limit pagination is used.
Cursors are opaque base64url payloads — clients should treat them
as strings and not parse the contents.
example: eyJzIjoiY3JlYXRlX3RpbWUiLCJ2IjoiMTcxNjIwMDAwMDAwMDAwMCIsImlkIjoiYTFiMmMzZDQtZTVmNi03YTg5LWIwYzEtZDJlM2Y0YTViNmM3In0
in: query
name: after
schema:
type: string
- deprecated: true
description: 'Pagination offset (0-based). Deprecated: prefer cursor-based pagination via `after`.'
in: query
name: offset
schema:
default: 0
minimum: 0
type: integer
- description: Maximum items per page (1-1000)
in: query
name: limit
schema:
default: 100
maximum: 1000
minimum: 1
type: integer
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/JobsListResponse'
description: Success - Jobs retrieved
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Bad request (e.g. malformed pagination cursor).
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: List jobs with pagination and filtering
tags:
- workflow
/api/jobs/{job_id}:
delete:
description: |
Delete a single job and every asset linked to it in one call. The client
sends a job delete and the backend fans out to the job's assets — the
client must not enumerate and delete the assets itself.
The deletion is directional, not symmetric: deleting a job deletes both
the job and its assets, but deleting an asset directly (via
`DELETE /api/assets/{id}`) leaves the job and its history record intact.
Asset visibility is never derived from the job's deletion state.
The job soft-delete is scoped to user-deletable jobs — the finished,
failed and cancelled states the Job Queue trash icon acts on (this includes
still-settling failed and mid-cancellation states, not only strictly
terminal ones), mirroring the legacy `POST /api/history` delete path this
endpoint replaces. A pending, in-progress or already-deleted job is left in
place and returns `204` as a no-op. Idempotent: a job already deleted, or
an asset already gone, is treated as a successful no-op.
Asset deletion is a best-effort fan-out of independent hard deletes and is
NOT atomic: if it aborts partway — a `409` for an in-use asset, or a `500`
— the assets deleted before the failure stay deleted while the job remains
in place. A retry re-runs the fan-out and is a no-op for the assets already
gone.
If a linked asset cannot be deleted because it is still referenced by
another resource (e.g. a workflow version), the endpoint surfaces
`409 ASSET_IN_USE` and leaves the job in place rather than silently
skipping the asset.
operationId: deleteJob
parameters:
- description: Job identifier (UUID)
in: path
name: job_id
required: true
schema:
format: uuid
type: string
responses:
"204":
description: Job and its assets deleted successfully, or the job was not in a deletable state (pending/in-progress/already-deleted) and no change was made (no-op)
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Job not found or does not belong to the user
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 'A linked asset cannot be deleted because it is referenced by another resource, e.g. a workflow version (error code: ASSET_IN_USE); the job is left in place'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Delete a job and its assets
tags:
- workflow
get:
description: |
Retrieve complete details for a specific job including workflow and outputs.
Used for detail views, workflow re-execution, and debugging.
The job says what ran it (`executor`) and, for a job that ran on a
deployment, which deployment and Release (`deployment`). The `deployment`
field and the `JobDeployment` schema say when each is absent.
operationId: getJobDetail
parameters:
- description: Job identifier (UUID)
in: path
name: job_id
required: true
schema:
format: uuid
type: string
- description: |
When present, each output item in the response receives a `short_url` field containing a short link for that asset. Omit this parameter (the default) to receive a response identical to the no-param baseline. The value selects the link's lifetime and auth model: use `ephemeral_tool_chain` for short-lived (≤5 minute) machine-to-machine handoffs — these are public bearer links where the link ID itself is the credential, so anyone holding the link can resolve it (intended for pasting into an agent/MCP tool chain); use `default` for durable (30 day) human-revisitable links, which are owner-gated and resolvable only by the authenticated owner. Links are always minted under the authenticated request owner's identity; the auth model is selected by the server and is never settable by the caller.
in: query
name: short_link
schema:
enum:
- ephemeral_tool_chain
- default
type: string
x-runtime:
- cloud
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/JobDetailResponse'
description: Success - Job details retrieved
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Forbidden - Job does not belong to user
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Job not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get full job details
tags:
- workflow
/api/jobs/{job_id}/assets:
get:
description: |
Retrieve a paginated list of the assets produced by a specific job,
enriched with the per-output node context (`node_id`, `output_key`,
`output_index`) correlated from the job's execution outputs by content
hash. Unlike `GET /api/assets?job_ids={id}`, this endpoint is scoped to a
single job and carries node-level placement, making it suited to job
output views rather than the general asset browser. Returns an empty
`assets` array for jobs that produced no assets.
operationId: getJobAssets
parameters:
- description: Job identifier (UUID)
in: path
name: job_id
required: true
schema:
format: uuid
type: string
- description: Maximum number of assets to return (1-500)
in: query
name: limit
schema:
default: 20
maximum: 500
minimum: 1
type: integer
- description: Number of assets to skip for pagination
in: query
name: offset
schema:
default: 0
minimum: 0
type: integer
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/JobAssetsResponse'
description: Success - Job assets returned
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request parameters
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Job not found or does not belong to the user
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: List a job's output assets
tags:
- workflow
/api/jobs/{job_id}/cancel:
post:
description: |
Cancel a specific job for the authenticated user.
Idempotent: a job that is already in a terminal state (completed, failed,
cancelled) or already cancelling is treated as a successful no-op and
returns 200. Only truly missing or cross-user jobs return 404.
A job that runs on a Build's deployment (the platform gateway) is
cancelled the same way, and the deployment is then asked to stop its
run, best effort and after this answers: not when the platform cannot
be reached, or does not yet know the API key the request was made
with. The run then continues until it ends on its own, and the job
still ends cancelled.
A job whose run has finished and whose result is being saved is left
to finish, as a finished job is.
operationId: cancelJob
parameters:
- description: Job identifier (UUID)
in: path
name: job_id
required: true
schema:
format: uuid
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/JobCancelResponse'
description: Success - Cancel request accepted (or job was already terminal)
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Bad Request - job_id is not a valid UUID (emitted by request validation before the handler runs)
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Job not found for this user
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error - cancellation failed
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Cancel a job
tags:
- workflow
/api/jobs/cancel:
post:
description: |
Cancel one or more jobs for the authenticated user in a single request.
State-agnostic: cancels both pending and running jobs (both transition to
the cancelled state via the same mechanism as the single-job endpoint).
Idempotent per job: a job already in a terminal or cancelling state is a
no-op and simply will not appear in the returned `cancelled` list.
Fail-fast on unknown IDs: if any provided job ID does not exist for this
user, the request returns 404 and no jobs are cancelled. This surfaces
bad IDs to the caller rather than silently dropping them.
A job that runs on a Build's deployment (the platform gateway) is
cancelled the same way, and the deployment is then asked to stop its
run, best effort and after this answers: not when the platform cannot
be reached, or does not yet know the API key the request was made
with. The run then continues until it ends on its own, and the job
still ends cancelled.
A job whose run has finished and whose result is being saved is left
to finish, as a finished job is.
This is the canonical batch-cancel endpoint. The delete operation on
POST /api/queue is deprecated in favour of this.
operationId: cancelJobs
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/JobsCancelRequest'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/JobsCancelResponse'
description: Success - cancel requests dispatched (or jobs were already terminal)
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Bad Request - job_ids is missing, empty, exceeds the maximum count, or contains an invalid UUID
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: One or more job IDs not found for this user (no jobs cancelled)
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error - cancellation failed
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Cancel multiple jobs
tags:
- workflow
/api/node_replacements:
get:
description: |
Returns mappings of unsupported node class names to their cloud-installed replacements.
Used by the frontend to offer "Quick Fix" when a workflow contains missing nodes.
operationId: getNodeReplacements
responses:
"200":
content:
application/json:
schema:
additionalProperties: true
type: object
description: Success - Node replacement mappings
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security: []
summary: Get node replacement mappings
tags:
- node
/api/object_info:
get:
description: |
Returns information about all available nodes. For a browser that
picked a developer-platform deployment (the cookie PUT
/api/workspaces/{id}/deployment sets) the catalog is that of the
Release the deployment runs now, fetched from comfy-builder; otherwise
it is Cloud's own.
operationId: getNodeInfo
parameters:
- description: |
Also list the models the caller can run that the models config
does not: their own imported models and the public model assets the
asset library shows them (assets tagged `models`), each in the model
dropdown of the directory it installs under, so a client that
validates widget values against this catalog accepts a model that
would run. Off by default: the frontend reads these models through
the asset browser instead.
in: query
name: include_user_models
schema:
default: false
type: boolean
responses:
"200":
content:
application/json:
schema:
additionalProperties:
$ref: '#/components/schemas/NodeInfo'
type: object
description: Success
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get all node information
tags:
- node
/api/prompt:
get:
description: Returns information about the current prompt in the execution queue
operationId: getPromptInfo
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/PromptInfo'
description: Success
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get information about current prompt execution
tags:
- workflow
post:
description: |
Submit a workflow to be executed by the backend.
The workflow is a JSON object describing the nodes and their connections.
operationId: executePrompt
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PromptRequest'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/PromptResponse'
description: Success - Prompt accepted
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/PromptErrorResponse'
description: Invalid prompt, or `code` `workspace_id_invalid` (see SessionWorkspaceIDInvalid).
"401":
$ref: '#/components/responses/SessionUnauthorized'
"402":
content:
application/json:
schema:
$ref: '#/components/schemas/PromptErrorResponse'
description: 'The account''s plan does not allow this submission; nothing was queued and retrying without changing the plan never succeeds. Disambiguated by the body''s `error.type`, NOT by parsing `error.message`: `PAYMENT_REQUIRED` (no active subscription, no funds, blocked tier), `CLOUD_SUBSCRIPTION_REQUIRED`, `FREE_TIER_EXHAUSTED`, `PARTNER_NODE_PAYMENT_REQUIRED`, or `MODEL_PAYMENT_REQUIRED`.'
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/PromptErrorResponse'
description: Workspace governance policy blocks one or more partner providers (error.type PARTNER_NODE_DISABLED; error.class_types lists the offending nodes, error.providers the disabled providers), or a refused request with `code` and `message` (see SessionWriteForbidden).
"413":
content:
application/json:
schema:
$ref: '#/components/schemas/PromptErrorResponse'
description: Workflow JSON too large
"429":
content:
application/json:
schema:
$ref: '#/components/schemas/PromptErrorResponse'
description: 'Retryable backpressure, disambiguated by the body''s `error.type`: `QUEUE_LIMIT` (this workspace''s bounded job queue is full - retrying after some queued jobs complete will succeed) or `FREE_TIER_UNAVAILABLE` (the free tier is switched off for now - retrying once it is back will succeed), or `BILLING_UNAVAILABLE` with `error.reason` `funds_unavailable` (ingest got no billing verdict for the workspace because the billing service was unreachable or rejected the check, or the billing-status read behind a no-funds verdict failed - nothing was queued, and retrying the same submission after `Retry-After` seconds will succeed once billing answers). Of the billing outcomes, a plan or billing policy refusal is a 402; only billing being unavailable is a 429. For a browser that picked a developer-platform deployment, also `PLATFORM_REFUSED` with `error.details` `deployment_not_ready` (the deployment is on its way to ready - nothing was queued, and retrying after `Retry-After` seconds will succeed once it is ready) or another platform 429 passed through.'
headers:
Retry-After:
description: Seconds to wait before retrying. Sent with `BILLING_UNAVAILABLE` and with a `deployment_not_ready` that ingest answers before any job is written.
schema:
type: integer
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/PromptErrorResponse'
description: Internal server error
"503":
content:
application/json:
schema:
$ref: '#/components/schemas/PromptErrorResponse'
description: Service unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Submit a workflow for execution
tags:
- workflow
/api/queue:
get:
description: Returns information about running and pending items in the queue
operationId: getQueueInfo
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/QueueInfo'
description: Success
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request parameters
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request parameters
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get queue information
tags:
- queue
post:
deprecated: true
description: |
Deprecated. Prefer the jobs-namespace cancel endpoints:
POST /api/jobs/cancel for cancelling jobs by ID, and
POST /api/jobs/{job_id}/cancel for a single job.
Cancel specific jobs by ID (the `delete` field) or clear all pending
jobs in the queue (the `clear` field). Despite the `delete` naming, this
does not delete anything — listed jobs transition to the cancelled state,
and `delete` cancels both pending and running jobs (not pending-only as
previously documented). Job-by-ID cancellation is superseded by
POST /api/jobs/cancel; `clear` has no jobs-namespace replacement yet.
Jobs that run on a Build's deployment (the platform gateway) are
cancelled the same way, by `delete` and by `clear`, and the deployment
is then asked to stop their runs, best effort and after this answers:
not when the platform cannot be reached, or does not yet know the API
key the request was made with. A run then continues until it ends on
its own, and its job still ends cancelled.
operationId: manageQueue
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/QueueManageRequest'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/QueueManageResponse'
description: Success
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request parameters
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Manage queue operations
tags:
- queue
/api/settings:
get:
description: Returns all settings for the authenticated user
operationId: getAllSettings
responses:
"200":
content:
application/json:
schema:
additionalProperties: true
description: User settings as key-value pairs
type: object
description: Success
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get all user settings
tags:
- settings
post:
description: Update multiple settings (merge with existing)
operationId: updateMultipleSettings
requestBody:
content:
application/json:
schema:
additionalProperties: true
description: Settings to update as key-value pairs
type: object
text/plain:
schema:
description: JSON string of settings to update
type: string
required: true
responses:
"200":
content:
application/json:
schema:
additionalProperties: true
description: Updated user settings
type: object
description: Success
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Update multiple settings
tags:
- settings
/api/settings/{id}:
get:
description: Returns a specific setting value by its id
operationId: getSettingById
parameters:
- description: Setting id to retrieve
in: path
name: id
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
description: Setting value response
properties:
value:
description: The setting value
type: object
description: Success
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Setting not found
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get a specific setting by id
tags:
- settings
post:
description: Update a specific setting by its id
operationId: updateSettingById
parameters:
- description: Setting id to update
in: path
name: id
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
description: New value for the setting
text/plain:
schema:
description: JSON string of the new setting value
type: string
required: true
responses:
"200":
content:
application/json:
schema:
description: Updated setting value response
properties:
value:
description: The updated setting value
type: object
description: Success
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Update a specific setting by id
tags:
- settings
/api/system_stats:
get:
description: Returns system statistics including ComfyUI version, device info, and system resources
operationId: getSystemStats
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/SystemStatsResponse'
description: Success
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
security: []
summary: Get system statistics
tags:
- system
/api/tags:
get:
description: |
Retrieves a list of all tags used across assets.
Includes usage counts and filtering options.
operationId: listTags
parameters:
- description: Filter tags by prefix
in: query
name: prefix
schema:
type: string
- description: Maximum number of tags to return (1-1000)
in: query
name: limit
schema:
default: 100
maximum: 1000
minimum: 1
type: integer
- description: Number of tags to skip for pagination
in: query
name: offset
schema:
default: 0
minimum: 0
type: integer
- description: Sort order for tags
in: query
name: order
schema:
default: count_desc
enum:
- count_desc
- name_asc
type: string
- description: Include tags with zero usage count
in: query
name: include_zero
schema:
default: false
type: boolean
- description: Whether to include public/shared assets when counting tags
in: query
name: include_public
schema:
default: true
type: boolean
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/ListTagsResponse'
description: Tags retrieved successfully
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid request parameters
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: List all tags
tags:
- file
/api/tasks:
get:
description: |
Retrieve a paginated list of background tasks for the authenticated user.
Supports filtering by task type, status, and creation time.
operationId: listTasks
parameters:
- description: Filter by task type name (exact match)
example: model_upload
in: query
name: task_name
schema:
type: string
- description: Filter by idempotency key (exact match). For best performance, specify task_name as well.
example: upload-model-abc123
in: query
name: idempotency_key
schema:
type: string
- description: Filter by one or more statuses (comma-separated)
example: created,running
in: query
name: status
schema:
type: string
- description: Filter tasks created after this timestamp (RFC3339 format)
example: "2024-01-01T00:00:00Z"
in: query
name: created_after
schema:
format: date-time
type: string
- description: Filter tasks created before this timestamp (RFC3339 format)
example: "2024-12-31T23:59:59Z"
in: query
name: created_before
schema:
format: date-time
type: string
- description: Sort direction (asc = ascending, desc = descending by create_time)
in: query
name: sort_order
schema:
default: desc
enum:
- asc
- desc
type: string
- description: Pagination offset (0-based)
in: query
name: offset
schema:
default: 0
minimum: 0
type: integer
- description: Maximum items per page (1-100)
in: query
name: limit
schema:
default: 20
maximum: 100
minimum: 1
type: integer
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/TasksListResponse'
description: Success - Tasks retrieved
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionForbidden'
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Validation error - Invalid filter values
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: List background tasks
tags:
- task
/api/tasks/{task_id}:
delete:
description: Cancels an authenticated user's queued or running asset download.
operationId: cancelTask
parameters:
- in: path
name: task_id
required: true
schema:
format: uuid
type: string
responses:
"204":
description: Cancellation accepted
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Task not found
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Task cannot be cancelled
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Cancellation failed
"503":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Task queue unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Cancel an asset download task
tags:
- task
get:
description: |
Retrieve full details for a specific background task.
operationId: getTask
parameters:
- description: Task identifier (UUID)
in: path
name: task_id
required: true
schema:
format: uuid
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/TaskResponse'
description: Success - Task details retrieved
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized - Authentication required
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Task not found (also returned for ownership failures to avoid leaking task existence)
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get task details
tags:
- task
/api/upload/image:
post:
description: |
Upload an image file to cloud storage.
Image limits:
- Maximum file size: 50 MB
- Maximum width/height per edge: 16384 px
- Maximum total pixel count: 64 megapixels (67108864 pixels)
Uploads that exceed any of these limits are rejected with HTTP 400.
So is an upload too large to ever fit the pod's upload memory budget
("upload exceeds the maximum buffered size").
When the pod is already buffering its whole upload memory budget the
upload is shed with HTTP 503 and a Retry-After header; retry it.
operationId: uploadImage
requestBody:
content:
multipart/form-data:
schema:
properties:
image:
description: The image file to upload
format: binary
type: string
overwrite:
description: Whether to overwrite existing file (true/false)
type: string
subfolder:
description: Optional subfolder path
type: string
type:
description: Upload type (defaults to "output")
type: string
required:
- image
type: object
required: true
responses:
"200":
content:
application/json:
schema:
properties:
name:
description: Filename of the uploaded image
type: string
subfolder:
description: Subfolder path where image was saved
type: string
type:
description: Type of upload (e.g., "output")
type: string
type: object
description: Image uploaded successfully
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Bad request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
"503":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Upload buffer budget exhausted on this pod; retry after the Retry-After seconds. `code` is `UPLOAD_BUDGET_EXHAUSTED`.
headers:
Retry-After:
description: Seconds to wait before retrying
schema:
type: integer
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Upload an image file
tags:
- file
/api/upload/mask:
post:
description: |
Upload a mask image to be applied to an existing image.
Image limits apply to both the uploaded mask and the referenced
original image:
- Maximum file size: 50 MB
- Maximum width/height per edge: 16384 px
- Maximum total pixel count: 64 megapixels (67108864 pixels)
Uploads that exceed any of these limits are rejected with HTTP 400.
So is an upload too large to ever fit the pod's upload memory budget
("upload exceeds the maximum buffered size").
When the pod is already buffering its whole upload memory budget the
upload is shed with HTTP 503 and a Retry-After header; retry it.
operationId: uploadMask
requestBody:
content:
multipart/form-data:
schema:
properties:
image:
description: The mask image file to upload
format: binary
type: string
original_ref:
description: JSON string containing reference to the original image
type: string
required:
- image
- original_ref
type: object
required: true
responses:
"200":
content:
application/json:
schema:
properties:
name:
description: Filename of the uploaded mask
type: string
subfolder:
description: Subfolder path where mask was saved
type: string
type:
description: Type of upload (e.g., "output")
type: string
type: object
description: Mask uploaded successfully
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Bad request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
"503":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Upload buffer budget exhausted on this pod; retry after the Retry-After seconds. `code` is `UPLOAD_BUDGET_EXHAUSTED`.
headers:
Retry-After:
description: Seconds to wait before retrying
schema:
type: integer
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Upload a mask image
tags:
- file
/api/user:
get:
description: Returns information about the currently authenticated user
operationId: getUser
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/UserResponse'
description: Success
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get current user information
tags:
- user
/api/userdata:
get:
description: Returns a list of user data files in the specified directory, optionally recursively and with full metadata.
operationId: getUserdata
parameters:
- description: The directory to list files from.
in: query
name: dir
schema:
type: string
- description: Whether to list files recursively.
in: query
name: recurse
schema:
default: false
type: boolean
- description: Whether to split file information by type.
in: query
name: split
schema:
default: false
type: boolean
- description: Whether to return full file metadata.
in: query
name: full_info
schema:
default: false
type: boolean
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/GetUserDataResponseFull'
description: A list of user data files.
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
text/plain:
schema:
type: string
description: Bad request (e.g., invalid filename).
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
text/plain:
schema:
type: string
description: Unauthorized.
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
text/plain:
schema:
type: string
description: File not found or invalid path.
"500":
content:
text/plain:
schema:
type: string
description: General error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: List user data files
tags:
- user
/api/userdata/{file}:
delete:
description: |
Delete a user data file from the database. The file parameter should be
the relative path within the user's data directory.
operationId: deleteUserdataFile
parameters:
- description: The file path to delete (URL encoded if necessary).
in: path
name: file
required: true
schema:
type: string
responses:
"204":
description: File deleted successfully (No Content).
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
text/plain:
schema:
type: string
description: Unauthorized.
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
text/plain:
schema:
type: string
description: File not found.
"500":
content:
text/plain:
schema:
type: string
description: Internal server error.
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Delete a user data file
tags:
- user
get:
description: Returns the requested user data file if it exists.
operationId: getUserdataFile
parameters:
- description: The filename of the user data to retrieve.
in: path
name: file
required: true
schema:
type: string
responses:
"200":
content:
application/octet-stream:
schema:
format: binary
type: string
description: Successfully retrieved the file.
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
text/plain:
schema:
type: string
description: Bad request (e.g., invalid filename).
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
text/plain:
schema:
type: string
description: Unauthorized.
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
text/plain:
schema:
type: string
description: File not found or invalid path.
"500":
content:
text/plain:
schema:
type: string
description: General error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get user data file
tags:
- user
post:
description: |
Upload a file to a user's data directory. Optional query parameters allow
control over overwrite behavior and response detail.
operationId: postUserdataFile
parameters:
- description: The target file path (URL encoded if necessary).
in: path
name: file
required: true
schema:
type: string
- description: If "false", prevents overwriting existing files. Defaults to "true".
in: query
name: overwrite
schema:
default: "true"
enum:
- "true"
- "false"
type: string
- description: If "true", returns detailed file info; if "false", returns only the relative path.
in: query
name: full_info
schema:
default: "false"
enum:
- "true"
- "false"
type: string
requestBody:
content:
application/octet-stream:
schema:
format: binary
type: string
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/UserDataResponseFull'
description: File uploaded successfully.
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
text/plain:
schema:
type: string
description: Missing or invalid 'file' parameter.
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
text/plain:
schema:
type: string
description: Unauthorized.
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
text/plain:
schema:
type: string
description: The requested path is not allowed.
"409":
content:
text/plain:
schema:
type: string
description: File already exists and overwrite is set to false.
"500":
content:
text/plain:
schema:
type: string
description: General error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Upload or update a user data file
tags:
- user
/api/userdata/{file}/move/{dest}:
post:
description: |
Move or rename a file within a user's data directory, with options for
controlling overwrite behavior and response format.
operationId: moveUserdataFile
parameters:
- description: The source file path (URL encoded if necessary).
in: path
name: file
required: true
schema:
type: string
- description: The destination file path (URL encoded if necessary).
in: path
name: dest
required: true
schema:
type: string
- description: If "false", prevents overwriting existing files. Defaults to "true".
in: query
name: overwrite
schema:
default: "true"
enum:
- "true"
- "false"
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/UserDataResponseFull'
description: File moved successfully.
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
text/plain:
schema:
type: string
description: Missing or invalid parameters.
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
text/plain:
schema:
type: string
description: Unauthorized.
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
text/plain:
schema:
type: string
description: Source file not found.
"409":
content:
text/plain:
schema:
type: string
description: Destination file already exists and overwrite is set to false.
"500":
content:
text/plain:
schema:
type: string
description: General error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Move or rename a user data file
tags:
- user
/api/userdata/{file}/publish:
delete:
description: |-
Deletes the personal (URL) share for a workflow identified by its userdata path, retiring its `?share=<id>` link and the published snapshots behind it. Hub publishes are unaffected — those are revoked via `DELETE /api/hub/workflows/{share_id}`.
Note the asymmetry with `GET /api/userdata/{file}/publish` on this same path: that handler resolves the hub publish in preference to the URL one, so the `share_id` it reports is not necessarily the share this endpoint revokes. A hub-only publish reports a `share_id` there but gets a 404 here, and a workflow published on both channels gets a 204 here while the hub link it was showing keeps resolving.
operationId: deleteUserdataFilePublish
parameters:
- description: The workflow file path within the user's data directory (URL encoded if necessary).
in: path
name: file
required: true
schema:
type: string
responses:
"204":
description: Share revoked
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Workflow or share not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Revoke the personal share link for a workflow file
tags:
- workflows
get:
description: Returns the publish status and share info for a workflow identified by its userdata path.
operationId: getUserdataFilePublish
parameters:
- description: The workflow file path within the user's data directory (URL encoded if necessary).
in: path
name: file
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/WorkflowPublishInfo'
description: Publish info (publish_time is null if never published)
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Workflow not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get publish info for a workflow file
tags:
- workflows
post:
description: Creates a new published_workflow record from the latest version and snapshots the provided assets.
operationId: postUserdataFilePublish
parameters:
- description: The workflow file path within the user's data directory (URL encoded if necessary).
in: path
name: file
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/PublishWorkflowAssetsRequest'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/WorkflowPublishInfo'
description: Workflow published
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Bad request
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Workflow not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Publish a workflow file
tags:
- workflows
/api/users:
get:
description: |
ComfyUI legacy users endpoint. Returns information about how user
data is stored. In cloud this is always server-managed, so callers
receive a constant response indicating server-side storage.
operationId: getUsersInfo
responses:
"200":
content:
application/json:
schema:
properties:
migrated:
description: Whether user data has been migrated (always true in cloud)
type: boolean
storage:
description: Where user data is stored (always "server" in cloud)
type: string
required:
- storage
- migrated
type: object
description: Userdata storage information
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: ComfyUI userdata storage info
tags:
- user
/api/v1/catalog/agents:
get:
operationId: getCatalogAgentInstructions
responses:
"200":
content:
text/plain:
schema:
type: string
description: Editing instructions from this deployed catalog API build
"503":
description: Catalog disabled or unavailable
security: []
summary: Agent instructions for editing Comfy Content Catalog JSON
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/authoring-context:
get:
description: Read-only private staff verification for authoring clients. Returns the verified actor, canonical owner scope, independent edit/apply grants and current catalog tokens. Creates or refreshes no session, cookie, credential, content or approval. Does not return a legacy review projection. Every mutation must still reauthorize and check exact CAS. No query parameters.
operationId: getCCCAuthoringContext
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCAuthoringContext'
description: Current verified authoring context; private no-store
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unsupported query parameters; or `code` `workspace_id_invalid` (see SessionWorkspaceIDInvalid).
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Verify current staff authoring permissions and catalog state
tags:
- site-catalog
x-permission-match: any
x-required-permissions:
- comfy_site.edit
- comfy_site.apply
/api/v1/catalog/cards:
get:
operationId: listCCCWebsiteCards
parameters:
- description: Optional exact public cache version from public-authority for an initial page. Cursor continuations are not cache fills. Invalid, superseded or cursor-bearing pins fail with 409. A guarded response is returned only when the version is unchanged before and after complete presentation.
in: header
name: X-Comfy-Catalog-Authority
schema:
type: string
- in: query
name: kind
required: true
schema:
enum:
- MODEL
- WORKFLOW
- APP
type: string
- in: query
name: limit
schema:
default: 24
maximum: 24
minimum: 1
type: integer
- in: query
name: cursor
schema:
maxLength: 4096
type: string
- in: query
name: locale
schema:
default: en
enum:
- en
- zh-CN
type: string
- in: query
name: q
schema:
maxLength: 300
type: string
- in: query
name: sort
schema:
default: popular
enum:
- popular
- name
- priceAsc
- priceDesc
type: string
- explode: true
in: query
name: category
schema:
items:
maxLength: 200
type: string
maxItems: 30
type: array
style: form
- explode: true
in: query
name: model
schema:
items:
maxLength: 200
type: string
maxItems: 30
type: array
style: form
- explode: true
in: query
name: use
schema:
items:
maxLength: 200
type: string
maxItems: 30
type: array
style: form
- explode: true
in: query
name: modality
schema:
items:
maxLength: 200
type: string
maxItems: 30
type: array
style: form
- explode: true
in: query
name: provider
schema:
items:
maxLength: 200
type: string
maxItems: 30
type: array
style: form
- explode: true
in: query
name: capability
schema:
items:
maxLength: 200
type: string
maxItems: 30
type: array
style: form
- description: Only Live public cards credited to this creator username (case-insensitive)
in: query
name: author
schema:
maxLength: 30
minLength: 1
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCWebsiteCardsPage'
description: At most 24 card summaries; no graphs, inputs, examples or long bodies. Anonymous responses omit total, generation and facet counts. Cursors are audience, filter, clock and state bound and expire after five minutes.
"400":
description: Invalid or unsupported query or cursor
"403":
description: Verified staff permission required for Preview
"409":
description: Public authority or cursor selection changed or expired; restart from current authority
"503":
description: Catalog unavailable or card budget exceeded
security: []
summary: Read bounded website card summaries
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/creators:
get:
description: Creators that have at least one Live public Hub workflow, ordered by username. Public display fields only.
operationId: listCCCCreators
parameters:
- in: query
name: limit
schema:
default: 24
maximum: 100
minimum: 1
type: integer
- in: query
name: cursor
schema:
maxLength: 200
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCCreatorsPage'
description: One page of creators
"400":
description: Invalid or unsupported query or cursor
"503":
description: Catalog unavailable
security: []
summary: List creators with Live public workflows
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/creators/{username}:
get:
description: The username match is case-insensitive. A creator without a Live public Hub workflow is not found.
operationId: getCCCCreator
parameters:
- in: path
name: username
required: true
schema:
maxLength: 30
minLength: 1
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCCreatorProfile'
description: Public creator profile
"400":
description: Unsupported query parameter
"404":
description: No creator with a Live public workflow has this username
"503":
description: Catalog unavailable
security: []
summary: Read one creator's public profile
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/docs:
get:
description: Read-only HTML rendered from the deployed catalog contract. No credential collection or execution console.
operationId: getCatalogDocs
responses:
"200":
content:
text/html:
schema:
type: string
description: Build-coupled catalog instructions, permissions and endpoint contracts
"503":
description: Catalog disabled or unavailable
security: []
summary: Readable catalog-only API documentation
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/draft/batch:
post:
description: One expected Draft and 1–100 flat documents. Omit uid for creates; existing items require uid and expected_revision_uid. Duplicate targets and per-item Draft overrides are rejected. Any failure rolls back every item, generation, audit and idempotency result. Media upload remains separate.
operationId: batchCCCItems
parameters:
- in: header
name: Idempotency-Key
required: true
schema:
maxLength: 200
minLength: 1
type: string
requestBody:
content:
application/json:
schema:
additionalProperties: false
properties:
expected_draft_rev:
format: int64
minimum: 1
type: integer
items:
items:
$ref: '#/components/schemas/CCCJSON'
maxItems: 100
minItems: 1
type: array
required:
- expected_draft_rev
- items
type: object
x-go-type: CCCJSON
required: true
responses:
"200":
content:
application/json:
schema:
items:
$ref: '#/components/schemas/CCCJSON'
type: array
description: Flat immutable edits in request order; retry returns identical UIDs/tokens
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Structured validation failure with item field paths
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
description: Existing target absent from owner-scoped Draft
"409":
description: Stale Draft/edit token or idempotency mismatch
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Save bounded Content edits atomically
tags:
- site-catalog
x-required-permissions:
- comfy_site.edit
/api/v1/catalog/draft/discard-changes:
post:
description: Requires comfy_site.edit, an explicit confirmed selection of at most 100 unique UID/exact-version pairs, reviewed Live/Draft/generation, full matching filter/count/digest and Idempotency-Key. Restores selected Live JSON and exact media reference metadata through new immutable Draft saves; never-published additions become retained tombstones. No hard deletion, blob deletion, publication, inherited approval or change to Live/projection/unselected saves. Remaining Draft dependencies and pins are validated in the same state-locked transaction; conflicts fail all changes with field errors. Effective cancellations/restores leave the pending queue. No query parameters. Request maximum256KiB. Private/no-store.
operationId: discardCCCChanges
parameters:
- in: header
name: Idempotency-Key
required: true
schema:
maxLength: 200
minLength: 1
type: string
- in: header
name: Prefer
schema:
enum:
- return=minimal
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Updated complete unfiltered private staging snapshot and global unresolved_count
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"409":
description: Stale state/selection/exact version or idempotency mismatch; no partial discard
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Invalid confirmed selection or remaining Draft dependency/pin conflict; no partial discard
"503":
description: Catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Atomically discard selected Draft changes without deleting Live content
tags:
- site-catalog
x-required-permissions:
- comfy_site.edit
/api/v1/catalog/draft/final-review:
get:
description: Read-only publisher review of the complete selective candidate. Deferred changes are listed separately and restored to Live values for structural/reference checks. Returns state and selection_digest binding every exact save and decision. Any unfinished review or invalid dependency rejects the candidate. Does not publish, certify external delivery or functional evidence, or start paid execution. No query parameters are supported. Change items carry saved_at, the RFC3339 UTC save time of their exact revision (display only, not in the digest).
operationId: getCCCFinalReview
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Private exact approved changes, deferred work, state and selection digest
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unsupported query parameters; or `code` `workspace_id_invalid` (see SessionWorkspaceIDInvalid).
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
"422":
description: Unreviewed work, no approved changes, or invalid selective candidate
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Review the exact approved additions, modifications and deletions
tags:
- site-catalog
x-required-permissions:
- comfy_site.apply
post:
description: Body contains exact review state and a nonempty unique selected_uids set bounded to 5000. Stored editorial decisions are ignored. Changes contains only checked pending saves; deferred contains all unchecked work. The digest binds the canonical checked set and exact selected versions at this state. Invalid selected dependencies reject the whole candidate. No authoring, approval, audit, retry or publication writes. Private/no-store. Change items carry saved_at, the RFC3339 UTC save time of their exact revision (display only, not in the digest).
operationId: reviewCCCCheckedPublication
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Exact checked changes and unchecked private work with state and selection digest
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unsupported query parameters; or `code` `workspace_id_invalid` (see SessionWorkspaceIDInvalid).
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"409":
description: Stale reviewed state or selected item no longer pending
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Invalid explicit selection or candidate dependencies; bounded field_errors include the affected resource_uid when known
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Read-only review of an explicit checked publication candidate
tags:
- site-catalog
x-required-permissions:
- comfy_site.apply
/api/v1/catalog/draft/final-review/receipt:
post:
description: Same strict review state and selected_uids input and complete candidate validation as POST final-review. Returns no documents, presentation or unchecked IDs. selected_versions_digest is lowercase SHA256 of compact JSON ["ccc-checked-review-receipt-v1",[live_rev,draft_rev,draft_generation],[[uid,revision_uid],...]] with canonical UUID pairs sorted by ASCII UID. Clients must compare state, count and this digest against their frozen checked snapshot before displaying confirmation. selection_digest binds the existing publish request; publication revalidates state and candidate. Read-only, private/no-store; no approval, audit, retry or publication writes. Maximum request256KiB; response below16KiB.
operationId: reviewCCCCheckedReceipt
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCCheckedReviewReceipt'
description: Exact checked-version receipt after complete candidate validation
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unsupported query parameters; or `code` `workspace_id_invalid` (see SessionWorkspaceIDInvalid).
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"409":
description: Stale reviewed state or selected item no longer pending
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Invalid explicit selection or candidate dependencies; bounded field_errors include affected resource_uid
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Validate checked publication and return a compact exact-version receipt
tags:
- site-catalog
x-required-permissions:
- comfy_site.apply
/api/v1/catalog/draft/items:
post:
description: Flat typed document with expected_draft_rev, type and schema_version. Server assigns UID and fixed organization owner; author_uid is editable versioned account attribution, defaulting to the creator. CONTENT v2 adds a short title/description, long_description, FAQ, runs/downloads and workflow facts. Exact type schemas and field values are validated before saving; historical v1 remains readable. Media requires verified upload instead. Private; no implicit paid validation.
operationId: createCCCItem
parameters:
- in: header
name: Idempotency-Key
required: true
schema:
maxLength: 200
minLength: 1
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
required: true
responses:
"201":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Flat immutable Content edit with exact concurrency tokens
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Structured document or token validation errors
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"409":
description: Stale Draft/edit token or idempotency payload mismatch
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Create a Content identity and immutable Draft edit
tags:
- site-catalog
x-required-permissions:
- comfy_site.edit
/api/v1/catalog/draft/items/{uid}:
delete:
operationId: deleteCCCItem
parameters:
- in: path
name: uid
required: true
schema:
format: uuid
type: string
- in: header
name: Idempotency-Key
required: true
schema:
maxLength: 200
minLength: 1
type: string
requestBody:
content:
application/json:
schema:
additionalProperties: false
properties:
expected_draft_rev:
format: int64
minimum: 1
type: integer
expected_revision_uid:
format: uuid
type: string
required:
- expected_draft_rev
- expected_revision_uid
type: object
x-go-type: CCCJSON
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Flat retained Content with is_deleted=true and new exact edit token
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Invalid tokens; generic Media mutation refused
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
description: Resource absent from owner-scoped Draft
"409":
description: Stale Draft/edit token or idempotency mismatch
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Append a Draft tombstone without erasing history
tags:
- site-catalog
x-required-permissions:
- comfy_site.edit
get:
description: Owner-scoped private read, including retained tombstones. Returns flat authored JSON plus read-only metadata and expected_draft_rev/expected_revision_uid from a single snapshot. The record catalog_rev may be older than Draft; use expected_draft_rev for saves. The response saves back unchanged, since PUT accepts this exact body, and its read-only metadata (uid, owner_uid, creator_uid, revision_uid, catalog_rev, edit_sequence, digest, saved_by_uid, draft_generation, saved_at, is_deleted false) is ignored, never applied; author_uid is the authored credited author. saved_at is this exact edit's save time (RFC3339 UTC). Reading does not invalidate approval or create history. No query parameters.
operationId: getCCCDraftItem
parameters:
- in: path
name: uid
required: true
schema:
format: uuid
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Current complete authored JSON with exact working-save tokens and read-only metadata
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid UID or unsupported query parameters; or `code` `workspace_id_invalid` (see SessionWorkspaceIDInvalid).
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
description: Resource missing or outside canonical owner scope
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Fetch current Draft JSON and exact save tokens without making a copy
tags:
- site-catalog
x-permission-match: any
x-required-permissions:
- comfy_site.edit
- comfy_site.apply
put:
description: Complete authored JSON plus expected_draft_rev, expected_revision_uid, type and schema_version. The exact getCCCDraftItem body is a valid request (GET then PUT). Read-only metadata keys from that read are accepted and ignored, never applied; owner, creator, editor and identity stay server-assigned. is_deleted true is refused (use restore). Unknown authored fields are rejected.
operationId: replaceCCCItem
parameters:
- in: path
name: uid
required: true
schema:
format: uuid
type: string
- in: header
name: Idempotency-Key
required: true
schema:
maxLength: 200
minLength: 1
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: New immutable edit; owner stays fixed, author attribution is versioned and saved_by_uid records the actual editor
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Structured document or token validation errors
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
description: Resource not found in the selected Draft/owner scope
"409":
description: Stale Draft/edit token or idempotency payload mismatch
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Append a complete flat JSON replacement to Draft
tags:
- site-catalog
x-required-permissions:
- comfy_site.edit
/api/v1/catalog/draft/items/{uid}/restore:
post:
description: Source edit must belong to the same UID and organization. Append and revalidate a new immutable Draft save; never edit history or publish. Generic Media restore remains unavailable until verified media authoring is connected.
operationId: restoreCCCItemVersion
parameters:
- in: path
name: uid
required: true
schema:
format: uuid
type: string
- in: header
name: Idempotency-Key
required: true
schema:
maxLength: 200
minLength: 1
type: string
requestBody:
content:
application/json:
schema:
additionalProperties: false
properties:
expected_draft_rev:
format: int64
minimum: 1
type: integer
expected_revision_uid:
format: uuid
type: string
source_revision_uid:
format: uuid
type: string
required:
- expected_draft_rev
- expected_revision_uid
- source_revision_uid
type: object
x-go-type: CCCJSON
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: New immutable forward Draft save and exact concurrency tokens
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Invalid tokens or unsupported historical schema
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
description: Current or source edit not found in the target UID/owner scope
"409":
description: Stale Draft/edit token or idempotency mismatch
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Restore an exact retained Content save into Draft
tags:
- site-catalog
x-required-permissions:
- comfy_site.edit
/api/v1/catalog/draft/media:
post:
description: Staff edit permission required. Multipart with exactly one file or upload_token; server verifies SHA-256, MIME, size and dimensions. upload_token finalizes bytes sent through upload-url directly to private storage, up to the configured 300 MiB limit. Inline multipart bytes retain the 65 MiB HTTP envelope. New UID per intentional upload even for identical bytes; idempotent retry returns original result. Private storage required. Videos include verified duration and dimensions. No public URL or paid execution.
operationId: uploadCCCMedia
parameters:
- in: header
name: Idempotency-Key
required: true
schema:
maxLength: 200
minLength: 1
type: string
requestBody:
content:
multipart/form-data:
schema:
additionalProperties: false
oneOf:
- required:
- file
- required:
- upload_token
properties:
change_id:
description: Optional case-sensitive editorial batch label; not identity or approval.
maxLength: 128
minLength: 1
pattern: ^[A-Za-z0-9][A-Za-z0-9._-]*$
type: string
expected_draft_rev:
minimum: 1
type: integer
file:
format: binary
type: string
name:
description: Safe contextual filename/path; normally entity-slug/filename.
maxLength: 500
minLength: 1
type: string
originating_entity_uid:
format: uuid
type: string
role:
maxLength: 500
minLength: 1
type: string
upload_token:
maxLength: 8192
minLength: 1
type: string
required:
- expected_draft_rev
- originating_entity_uid
- role
- name
type: object
required: true
responses:
"201":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Private verified media metadata and exact Draft/edit tokens; bytes remain unreleased
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Malformed multipart request; or `code` `workspace_id_invalid` (see SessionWorkspaceIDInvalid).
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
description: Origin is absent or outside owner scope
"409":
description: Stale Draft or reused retry key with different input
"413":
description: Request body exceeds bounded upload envelope
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Invalid fields or unsupported/unsafe bytes
"503":
description: Private storage or dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Upload verified bytes as an independent Draft media use
tags:
- site-catalog
x-required-permissions:
- comfy_site.edit
/api/v1/catalog/draft/media/{uid}:
delete:
operationId: deleteCCCMedia
parameters:
- in: path
name: uid
required: true
schema:
format: uuid
type: string
- in: header
name: Idempotency-Key
required: true
schema:
maxLength: 200
minLength: 1
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: New tombstone version and Draft generation; history bytes retained
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
description: Logical media is absent or outside owner scope
"409":
description: Stale Draft/edit token or retry mismatch
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Invalid exact edit tokens or non-Media target
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Append a Draft Media tombstone without deleting bytes
tags:
- site-catalog
x-required-permissions:
- comfy_site.edit
/api/v1/catalog/draft/media/{uid}/file:
put:
description: Multipart with exactly one file or upload_token from upload-url; independent uses and old Live bytes are unchanged. Safe name is explicit to keep retries deterministic. Server verifies staged bytes before finalization; no caller-supplied storage key, verified MIME or owner metadata accepted.
operationId: replaceCCCMediaFile
parameters:
- in: path
name: uid
required: true
schema:
format: uuid
type: string
- in: header
name: Idempotency-Key
required: true
schema:
maxLength: 200
minLength: 1
type: string
requestBody:
content:
multipart/form-data:
schema:
additionalProperties: false
oneOf:
- required:
- file
- required:
- upload_token
properties:
change_id:
description: Optional case-sensitive editorial batch label; not identity or approval.
maxLength: 128
minLength: 1
pattern: ^[A-Za-z0-9][A-Za-z0-9._-]*$
type: string
expected_draft_rev:
minimum: 1
type: integer
expected_revision_uid:
format: uuid
type: string
file:
format: binary
type: string
name:
maxLength: 500
minLength: 1
type: string
upload_token:
maxLength: 8192
minLength: 1
type: string
required:
- expected_draft_rev
- expected_revision_uid
- name
type: object
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: New immutable Draft file-version metadata under the same media UID
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Malformed multipart request; or `code` `workspace_id_invalid` (see SessionWorkspaceIDInvalid).
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
description: Logical media is absent or outside owner scope
"409":
description: Stale Draft/edit token or retry mismatch
"413":
description: Request body exceeds bounded upload envelope
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Invalid fields or unsupported/unsafe bytes
"503":
description: Private storage or dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Replace one logical media use in Draft with verified bytes
tags:
- site-catalog
x-required-permissions:
- comfy_site.edit
/api/v1/catalog/draft/media/upload-url:
post:
description: Staff edit permission required. Supply filename, byte_size and optionally sha256. Returns an expiring PUT upload_url, required headers and an upload_token bound to this account, exact size and filename. Upload directly to private storage, then pass upload_token instead of file to the media create or replacement operation. No content becomes public. Finalization streams and verifies the exact uploaded bytes and recomputes SHA-256 before storing an immutable content-addressed blob. Direct uploads support up to the configured limit, at most 300 MiB.
operationId: requestCCCUploadURL
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Expiring private upload URL, token and required request headers
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Unsupported filename, invalid hash or empty/oversized file
"503":
description: Direct-upload storage or catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Request a private direct-upload URL
tags:
- site-catalog
x-required-permissions:
- comfy_site.edit
/api/v1/catalog/draft/publish:
post:
description: Requires catalog publish permission. Body contains review.expected_live_rev, review.expected_draft_rev, review.expected_draft_generation, expected_selection_digest from POST Final review, and selected_uids (nonempty unique set, at most 5000, matching that review). Publishes exactly the checked changes; unchecked changes are carried into the next Draft unchanged (same version IDs). Stored approvals are ignored. Invalid references roll back everything. Dormant unless the catalog is enabled; never active in production. No query parameters, no paid validation. Idempotency-Key retries do not publish twice. Private/no-store. An API key gets 403 FORBIDDEN; publishing needs a signed-in session.
operationId: publishCCCDraft
parameters:
- in: header
name: Idempotency-Key
required: true
schema:
maxLength: 200
minLength: 1
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: New Live, previous Live and fresh Draft state after atomic commit
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unsupported query parameters; or `code` `workspace_id_invalid` (see SessionWorkspaceIDInvalid).
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"409":
description: Stale reviewed state or decisions or conflicting retry; nothing published
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Invalid review, unfinished decisions or reference/dependency validation failed; nothing published. Bounded field_errors include the affected resource_uid when known.
"503":
description: Catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Publish the checked Draft changes and open the next Draft
tags:
- site-catalog
x-required-permissions:
- comfy_site.apply
/api/v1/catalog/draft/staging:
get:
description: Without representation, returns the legacy complete matching review. representation=page returns at most limit sparse rows. Cursors bind the complete Live/Draft/generation snapshot, filters, sort, and limit; stale snapshots return 409. representation=selection requires a snapshot cursor and returns sparse exact-version pins for all matching rows (at most 5000), only for explicit select-all. representation=detail requires that cursor and a matching uid and returns one complete change. Staff-only constrained search/filter. Credited author at the selected version is not the latest editor. unresolved_count counts every pending Draft entry whose exact-save decision is neither APPROVED nor DEFERRED, independently of display filters, including undecided deletions. It binds the same repeatable snapshot as the returned generation. Bulk operations cover explicit selected versions across all pages. Each item's saved_at is the RFC3339 UTC save time of its exact change; it is not part of selection_digest.
operationId: getCCCStaging
parameters:
- in: query
name: representation
schema:
enum:
- page
- selection
- detail
type: string
- in: query
name: limit
schema:
default: 50
maximum: 100
minimum: 1
type: integer
- in: query
name: cursor
schema:
maxLength: 2048
type: string
- in: query
name: sort
schema:
default: name
enum:
- name
- latest
type: string
- in: query
name: change
schema:
enum:
- new
- updates
type: string
- in: query
name: uid
schema:
format: uuid
type: string
- in: query
name: search
schema:
maxLength: 300
type: string
- in: query
name: author_uid
schema:
minLength: 1
type: string
- in: query
name: change_id
schema:
maxLength: 128
minLength: 1
pattern: ^[A-Za-z0-9][A-Za-z0-9._-]*$
type: string
- explode: true
in: query
name: tags
schema:
items:
maxLength: 200
minLength: 1
type: string
maxItems: 30
type: array
style: form
- explode: true
in: query
name: types
schema:
items:
enum:
- model
- workflow
- app
- media
- template_set
type: string
maxItems: 5
type: array
style: form
- explode: true
in: query
name: statuses
schema:
items:
enum:
- NEW
- APPROVED
- DEFERRED
- DELETED
type: string
maxItems: 4
type: array
style: form
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Private review with exact Draft generation and optional sparse page metadata
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unknown, repeated scalar or invalid filter; bounded result exceeded; or `code` `workspace_id_invalid` (see SessionWorkspaceIDInvalid).
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
"409":
description: The frozen page, selection or detail belongs to a stale Draft generation
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Read Draft changes for editorial staging
tags:
- site-catalog
x-permission-match: any
x-required-permissions:
- comfy_site.edit
- comfy_site.apply
post:
description: Requires review with expected_live_rev, expected_draft_rev and expected_draft_generation, the exact returned filter and expected_selection_digest, status NEW/APPROVED/DEFERRED and expected_count of the complete frozen matching set. Optional selected_uids is a nonempty list of at most 5000 distinct UUIDs from that set; omitted means all matching records. The operation is atomic, never a loop of separately committed decisions. The digest binds the full filter and exact matching versions; the selected UIDs are bound to the idempotent mutation request. An unfiltered action affecting every matching record additionally requires confirm_all, including when all are checked explicitly. Approval applies only to the exact immutable saves; later edits become NEW. Deleted changes remain explicit and require approval. No publication, functional validation or paid execution. Maximum request body 256 KiB. An API key gets 403 FORBIDDEN; staging needs a signed-in session.
operationId: stageCCCChanges
parameters:
- in: header
name: Idempotency-Key
required: true
schema:
maxLength: 200
minLength: 1
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Atomic matching-set decisions and updated private staging state
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"409":
description: Stale review, changed matching count or conflicting retry
"422":
description: Invalid status/filter/tokens/count or missing unfiltered confirmation
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Approve or defer reviewed changes, optionally a checked subset
tags:
- site-catalog
x-required-permissions:
- comfy_site.apply
/api/v1/catalog/items:
get:
description: Public bounded LIVE page (default 20, maximum 100). Filters run before keyset pagination. Unknown or repeated parameters and invalid cursors return 400; publication or revert invalidates prior cursors (409). Every request, including conditional GET, rechecks real UTC eligibility; browser caching requires revalidation and shared CDN caching is disabled. Never returns DRAFT, disabled, deleted, staff-only, or future content.
operationId: listContentCatalogItems
parameters:
- description: Optional exact public-authority token for a workflow_slug detail fill only. Collections and cursors with this header return 409. The token is checked before and after all presentation and file reads, including misses and conditional responses. Guarded responses are no-store; unavailable author or selected API-file reads return 503.
in: header
name: X-Comfy-Catalog-Authority
schema:
type: string
- in: query
name: q
schema:
maxLength: 300
type: string
- in: query
name: slug
schema:
type: string
- in: query
name: kind
schema:
enum:
- MODEL
- WORKFLOW
- APP
type: string
- in: query
name: type
schema:
enum:
- model
- workflow
- app
- template_set
type: string
- in: query
name: surface
schema:
enum:
- hub
- cloud_templates
- local_templates
- desktop_starters
- nvidia_performance_tests
type: string
- in: query
name: tag
schema:
maxLength: 200
type: string
- in: query
name: use_case
schema:
maxLength: 200
type: string
- in: query
name: sort
schema:
default: sort_order
enum:
- sort_order
- title
type: string
- in: query
name: limit
schema:
default: 20
maximum: 100
minimum: 1
type: integer
- in: query
name: cursor
schema:
maxLength: 4096
type: string
- description: Compatibility detail lookup, exclusive with all other query parameters. Select at most one eligible record by canonical path, UID or website detail slug, expanding the verified primary API file for that workflow only. A miss returns an empty page, never the collection. Collection reads never open API blobs. kind is a legacy alias for type and cannot be combined with type; slug accepts a canonical Hub pathname or native slug.
in: query
name: workflow_slug
schema:
maxLength: 300
minLength: 1
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCPublicItemsPage'
description: Bounded LIVE page with continuation metadata
"304":
description: Current eligible representation matches If-None-Match after fresh validation
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid, repeated, unsupported or conflicting query parameters or malformed cursor
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Cursor publication identity or public authority changed, or a guarded request was not a single detail lookup
"503":
description: Catalog disabled or unavailable
security: []
summary: Read eligible LIVE website content
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/items/{uid}:
get:
operationId: getContentCatalogItem
parameters:
- description: Optional exact public-authority token checked before and after complete detail presentation, including a not-found result. Malformed or superseded tokens return 409; unavailable author or selected API-file reads return 503. Responses are no-store and grant no private access.
in: header
name: X-Comfy-Catalog-Authority
schema:
type: string
- in: path
name: uid
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/ContentCatalogRecord'
description: Website content record
"404":
description: Not found or not publicly eligible
"409":
description: Public authority changed; select the current version before filling
"503":
description: Catalog disabled or unavailable
security: []
summary: Read an eligible LIVE record by UID
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/items/{uid}/history:
get:
description: Keyset pagination by descending per-resource edit_sequence, including intermediate and archived saves. This is not the public workflow-file version list. No total count or arbitrary query fields. Private no-store.
operationId: getCCCItemHistory
parameters:
- in: path
name: uid
required: true
schema:
format: uuid
type: string
- in: query
name: limit
schema:
default: 20
maximum: 100
minimum: 1
type: integer
- in: query
name: cursor
schema:
maxLength: 256
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Flat immutable items with catalog_status and saved_at, has_more and optional opaque next_cursor; no total
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Invalid limit, cursor or unsupported query parameter; or `code` `workspace_id_invalid` (see SessionWorkspaceIDInvalid).
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
description: Resource outside organization scope or absent
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Read bounded staff-only immutable save history
tags:
- site-catalog
x-permission-match: any
x-required-permissions:
- comfy_site.edit
- comfy_site.apply
/api/v1/catalog/legacy/{source}/{id}:
get:
description: Maps an id from an old public URL to the current Hub page of the record that replaced it. Source `template` takes a workflow_templates name; source `hub` takes an old Hub share id. Only an eligible LIVE workflow, app or model resolves. An unknown source, an unknown id, or a target that is not publicly eligible returns 404, so a caller has one miss path. Browser caching requires revalidation and shared CDN caching is disabled, as for the other public reads.
operationId: getCCCLegacyTarget
parameters:
- description: '`template` or `hub`'
in: path
name: source
required: true
schema:
maxLength: 20
type: string
- description: Template name or Hub share id
in: path
name: id
required: true
schema:
maxLength: 500
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCLegacyTarget'
description: Current Hub page of the mapped record
"404":
description: Unknown source or id, or the target is not publicly eligible
"503":
description: Catalog disabled or unavailable
security: []
summary: Resolve an old public id to its current Hub page
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/model-directory:
get:
description: One compact typed read of eligible LIVE model UIDs, canonical paths, localized titles and providers, without cards, media or profiles. Only locale is accepted; unknown or repeated parameters return 400. More than 5000 models or 2 MiB returns 503, never partial data. Every request rechecks current Live and scheduled visibility. Responses are private, no-store. The existing cards contract is unchanged.
operationId: listCCCWebsiteModelDirectory
parameters:
- description: Optional exact public cache version; unchanged before and after the complete directory fill. Invalid, repeated or superseded tokens fail with 409 and no response body.
in: header
name: X-Comfy-Catalog-Authority
schema:
type: string
- in: query
name: locale
schema:
default: en
enum:
- en
- zh-CN
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCWebsiteModelDirectory'
description: Complete eligible model directory, without Draft generation
"400":
description: Invalid, repeated or unsupported query parameter
"409":
description: Public cache version changed; restart from current authority
"503":
description: Catalog unavailable or directory budget exceeded
security: []
summary: Read the complete eligible public model-name directory
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/openapi.json:
get:
description: Public discovery grants no editing authority and does not replace the Cloud API specification.
operationId: getCatalogOpenAPI
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Catalog OpenAPI with contract fingerprint and environment
"503":
description: Catalog disabled or unavailable
security: []
summary: Catalog-only deployed OpenAPI contract
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/public-authority:
get:
description: A fresh metadata-only database snapshot. Never cache this response. The token binds environment, owner, public content generation, schedule visibility. Unchanged content keeps the same token across clock windows; valid_until bounds this observation rather than an artifact selected by a later fresh read. It grants no private access. Public artifact fills send the token in X-Comfy-Catalog-Authority; a changed version fails with 409 instead of returning content under a superseded key.
operationId: getCCCPublicCacheAuthority
responses:
"200":
content:
application/json:
schema:
additionalProperties: false
properties:
as_of:
format: date-time
type: string
next_visibility_at:
description: Exact next scheduled public visibility boundary; null when none is pending. Not the one-minute observation validity.
format: date-time
nullable: true
type: string
revision_id:
description: Current numeric Live revision, matching card revision_id. A URL-plus-revision cache key must also validate the token stored with its value because rollback, profile edits and eligibility changes can invalidate the same revision number.
format: int64
minimum: 1
type: integer
token:
pattern: ^[0-9a-f]{64}$
type: string
valid_until:
format: date-time
type: string
required:
- revision_id
- token
- as_of
- valid_until
- next_visibility_at
type: object
description: Current public authority and its next time boundary; no private identifiers
"503":
description: Current authority unavailable; do not reuse an earlier artifact
security: []
summary: Select the current opaque public website cache version
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/revisions/{rev}/items/{uid}:
get:
description: Resolve heads before filtering. Explicit archived candidate review never makes it eligible in Live. Private no-store.
operationId: getCCCRevisionItem
parameters:
- in: path
name: rev
required: true
schema:
format: int64
minimum: 1
type: integer
- in: path
name: uid
required: true
schema:
format: uuid
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Flat Content and exact edit/revision context
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
description: Resource/revision not found in organization scope
"503":
description: Dedicated catalog unavailable
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Read an exact retained staff Content view
tags:
- site-catalog
x-permission-match: any
x-required-permissions:
- comfy_site.edit
- comfy_site.apply
/api/v1/catalog/root-presentation:
get:
description: Complete eligible public card metadata for Models, Workflows and Apps in one snapshot-bound bundle, plus compact model labels and initial page metadata. No graphs, input contracts, private counts or continuation cursors. At most 5000 cards and 2 MiB serialized JSON; overflow fails rather than truncating. Search, filtering and paging continue through cards. Unknown or repeated query parameters are rejected. Select public authority once at page entry and send both revision_id and X-Comfy-Catalog-Authority to use the Ingest Redis artifact. Missing either bypasses Redis for a fresh guarded origin read. Cache hits match the authority stamp locally and check the absolute schedule deadline without current-state requests. A fresh selector pin after a same-revision public change rejects and refills the older cached artifact. Previously pinned metadata remains a selected snapshot, not an instant historical-revocation mechanism; protected media byte authorization is unchanged. Origin fills verify the revision and authority before and after complete presentation. Responses remain no-store to browser and CDN caches.
operationId: getCCCWebsiteRootPresentation
parameters:
- in: query
name: path
required: true
schema:
enum:
- /hub/models/
- /hub/workflows/
- /hub/apps/
type: string
- in: query
name: locale
schema:
default: en
enum:
- en
- zh-CN
type: string
- description: Live revision selected once at page entry. Redis requires both this revision and the selected authority pin. On an origin miss the revision must match current Live.
in: query
name: revision_id
schema:
format: int64
minimum: 1
type: integer
- description: Exact token from the fresh page-entry public-authority selection. Required with revision_id for Redis eligibility; absent pins bypass Redis. Invalid or repeated pins return 409.
in: header
name: X-Comfy-Catalog-Authority
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCWebsiteRootPresentation'
description: Complete root metadata; no personal data or executable bodies
headers:
X-Comfy-Catalog-Cache:
description: Ingest versioned root artifact source. Absent on direct catalog-api or bypassed requests.
schema:
enum:
- HIT
- MISS
type: string
"400":
description: Unsupported or repeated root path or locale
"409":
description: Public authority changed or the supplied pin is invalid
"503":
description: Current complete presentation unavailable or over budget
security: []
summary: Read complete bounded public Hub root presentation metadata
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/schemas/{type}/{schema_version}:
get:
description: Author new Content as schema_version 2; v1 stays readable but skips input, binding and translation checks. Media is server-created (uploads are media/1, recorded Cloud-asset references media/2); generic JSON authoring cannot create or replace Media, and upload/finalization routes are separate. Media references use src "media" ("r2" is a legacy alias) and file_version_uid = the upload's revision_uid. static_thumb is recommended and must be verified image/webp Media, 1 byte to 160 KiB, at most 960 px per side; reviewed policy requires it at publish but the current runtime does not enforce that yet. Direct uploads support up to 300 MiB, subject to CATALOG_MAX_DIRECT_UPLOAD_BYTES; images remain capped at 50 MiB, JSON at 64 MiB and API workflow JSON at 1 MiB.
operationId: getCCCTypeSchema
parameters:
- in: path
name: type
required: true
schema:
enum:
- model
- workflow
- app
- template_set
- media
type: string
- in: path
name: schema_version
required: true
schema:
minimum: 1
type: integer
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Build-coupled OpenAPI 3.0 schema object, type, version and API environment
"404":
description: Unsupported type or schema version
"503":
description: Catalog disabled or unavailable
security: []
summary: Type schema used by this deployed authoring validator
tags:
- site-catalog
x-required-permissions: []
/api/v1/catalog/state:
get:
operationId: getCCCState
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/CCCJSON'
description: Private state; never cacheable
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
"503":
description: Dedicated catalog unavailable; no legacy fallback
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Read dedicated CCC Live and Draft state
tags:
- site-catalog
x-permission-match: any
x-required-permissions:
- comfy_site.edit
- comfy_site.apply
/api/vhs/queryvideo:
get:
description: |
VHS custom node endpoint that returns metadata about a video file
(frame count, fps, resolution, duration). Currently returns default
placeholder values; real ffprobe integration is a follow-up.
An `<img>`, `<video>` or `<audio>` tag loads this with the
`WebSessionAuth` or `CookieAuth` cookie, both accepted whatever
`web_session_enabled` says; neither needs `X-CSRF-Token` or
`X-Comfy-Client`, which a media tag cannot send. A 403
AuthTypeNotAllowedError here is a credential the route never takes,
such as `X-ComfyAPI-Secret`, never the session.
operationId: getVhsQueryVideo
parameters:
- description: Name of the video file to query
in: query
name: filename
required: true
schema:
type: string
- content:
text/plain:
schema:
type: string
description: The workspace a media request reads from, where a media tag cannot send `X-Comfy-Workspace-ID`; see the `MediaWorkspaceID` parameter.
in: query
name: workspace_id
responses:
"200":
content:
application/json:
schema:
properties:
source:
description: Source video metadata
properties:
duration:
description: Duration in seconds
type: number
fps:
description: Frames per second
type: number
frames:
description: Total frame count
type: integer
size:
description: '[width, height] in pixels'
items:
type: integer
maxItems: 2
minItems: 2
type: array
required:
- size
- fps
- frames
- duration
type: object
required:
- source
type: object
description: Video metadata
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: |
Missing required query parameter. Produced by the oapi-codegen
wrapper via echo.NewHTTPError; the custom Echo HTTPErrorHandler
normalizes it to the standard ErrorResponse {code, message} shape
(BE-1178). Or `code` `workspace_id_invalid`: the `workspace_id` or
`X-Comfy-Workspace-ID` value is malformed, the two disagree, or,
with the flag on, a token or API key names another workspace than
its own.
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error, such as the auth policy failing to look up the workspace `workspace_id` names.
security:
- ApiKeyAuth: []
- BearerAuth: []
- CookieAuth: []
- WebSessionAuth: []
summary: Query VHS video metadata
tags:
- file
/api/view:
get:
description: |
Retrieve and view a file from the ComfyUI file system.
This endpoint is typically used to view generated images or other output files.
An `<img>`, `<video>` or `<audio>` tag loads this with the
`WebSessionAuth` or `CookieAuth` cookie, both accepted whatever
`web_session_enabled` says; neither needs `X-CSRF-Token` or
`X-Comfy-Client`, which a media tag cannot send. A 403
AuthTypeNotAllowedError here is a credential the route never takes,
such as `X-ComfyAPI-Secret`, never the session.
operationId: viewFile
parameters:
- description: Name of the file to view
in: query
name: filename
required: true
schema:
example: ComfyUI_00004_.png
type: string
- description: Subfolder path where the file is located
in: query
name: subfolder
schema:
example: tests/foo/bar
type: string
- description: Type of file (e.g., output, input, temp)
in: query
name: type
schema:
example: output
type: string
- description: Full path to the file (used for temp files)
in: query
name: fullpath
schema:
type: string
- description: Format of the file
in: query
name: format
schema:
type: string
- description: Frame rate for video files
in: query
name: frame_rate
schema:
type: integer
- description: Workflow identifier
in: query
name: workflow
schema:
type: string
- description: Timestamp parameter
in: query
name: timestamp
schema:
example: 1234567890
type: integer
- description: |
Image channel to extract from PNG images.
- 'rgb': Return only RGB channels (alpha set to fully opaque)
- 'a' or 'alpha': Return alpha channel as grayscale image
- If not specified, return original image unchanged via redirect
in: query
name: channel
schema:
example: rgb
type: string
- description: |
Maximum dimension (width or height) to resize the image to, preserving aspect ratio.
The image is fit within a res x res box. Returns a JPEG thumbnail.
Only applies to raster image files (PNG, JPEG, WebP, GIF).
in: query
name: res
schema:
example: 256
maximum: 1024
minimum: 64
type: integer
- content:
text/plain:
schema:
type: string
description: The workspace a media request reads from, where a media tag cannot send `X-Comfy-Workspace-ID`; see the `MediaWorkspaceID` parameter.
in: query
name: workspace_id
responses:
"200":
content:
image/jpeg:
schema:
description: Resized JPEG thumbnail (returned when res parameter is used)
format: binary
type: string
image/png:
schema:
description: Processed PNG image with extracted channel
format: binary
type: string
description: Success - File content returned (used when channel or res parameter is present)
"302":
description: Redirect to GCS signed URL
headers:
Cache-Control:
description: Cache directive for the redirect response
schema:
type: string
Location:
description: Signed URL to access the file in GCS
schema:
type: string
Vary:
description: Headers that affect response caching
schema:
type: string
"400":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: 'Invalid request parameters, or `code` `workspace_id_invalid`: the `workspace_id` or `X-Comfy-Workspace-ID` value is malformed, the two disagree, or, with the flag on, a token or API key names another workspace than its own.'
"401":
$ref: '#/components/responses/SessionUnauthorized'
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: File not found or unauthorized
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- CookieAuth: []
- WebSessionAuth: []
summary: View a file
tags:
- file
/api/workflow_templates:
get:
description: Returns available workflow templates
operationId: getWorkflowTemplates
responses:
"200":
content:
application/json:
schema:
description: Empty object for workflow templates
type: object
description: Success
security: []
summary: Get available workflow templates
tags:
- workflow
/api/workflows:
get:
description: Returns a paginated list of workflows for the authenticated user in the current workspace.
operationId: listWorkflows
parameters:
- in: query
name: limit
schema:
default: 20
maximum: 100
type: integer
- in: query
name: offset
schema:
default: 0
type: integer
- description: Search workflows by name (case-insensitive substring match)
in: query
name: name
schema:
type: string
- description: Filter by default view type
in: query
name: default_view
schema:
enum:
- workflow
- app
type: string
- description: Sort field
in: query
name: sort
schema:
default: create_time
enum:
- create_time
- update_time
- name
type: string
- description: Sort order
in: query
name: order
schema:
default: desc
enum:
- asc
- desc
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/WorkflowListResponse'
description: Success
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: List workflows
tags:
- workflows
post:
description: Creates a new workflow with its first version.
operationId: createWorkflow
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CreateWorkflowRequest'
required: true
responses:
"201":
content:
application/json:
schema:
$ref: '#/components/schemas/WorkflowResponse'
description: Workflow created successfully
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Validation error
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Create a new workflow
tags:
- workflows
/api/workflows/{workflow_id}:
delete:
description: Soft-deletes a workflow.
operationId: deleteWorkflow
parameters:
- description: The UUID of the workflow to delete.
in: path
name: workflow_id
required: true
schema:
type: string
responses:
"204":
description: Workflow deleted successfully
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Workflow not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Delete workflow
tags:
- workflows
get:
description: Retrieves workflow metadata by ID.
operationId: getWorkflow
parameters:
- description: The UUID of the workflow.
in: path
name: workflow_id
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/WorkflowResponse'
description: Success
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Workflow not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get workflow
tags:
- workflows
patch:
description: Updates mutable workflow metadata (name, description, default_view).
operationId: updateWorkflow
parameters:
- description: The UUID of the workflow to update.
in: path
name: workflow_id
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/UpdateWorkflowRequest'
required: true
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/WorkflowResponse'
description: Success
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionWriteForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Workflow not found
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Validation error
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Update workflow metadata
tags:
- workflows
/api/workflows/{workflow_id}/content:
get:
description: Retrieves the latest version of a workflow and its JSON content.
operationId: getWorkflowContent
parameters:
- description: The UUID of the workflow whose content should be retrieved.
in: path
name: workflow_id
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/WorkflowVersionContentResponse'
description: Success
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Workflow not found
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get workflow content
tags:
- workflows
/api/workflows/{workflow_id}/fork:
post:
description: Creates a new workflow by forking from an existing version.
operationId: forkWorkflow
parameters:
- description: The UUID of the source workflow to fork from.
in: path
name: workflow_id
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/ForkWorkflowRequest'
required: true
responses:
"201":
content:
application/json:
schema:
$ref: '#/components/schemas/WorkflowResponse'
description: Workflow forked successfully
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Forbidden
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Source workflow or version not found
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Validation error
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Fork a workflow
tags:
- workflows
/api/workflows/{workflow_id}/versions:
post:
description: Creates a new workflow version with updated workflow JSON. Uses optimistic concurrency via base_version.
operationId: createWorkflowVersion
parameters:
- description: The UUID of the workflow to create a new version for.
in: path
name: workflow_id
required: true
schema:
type: string
requestBody:
content:
application/json:
schema:
$ref: '#/components/schemas/CreateWorkflowVersionRequest'
required: true
responses:
"201":
content:
application/json:
schema:
$ref: '#/components/schemas/WorkflowVersionResponse'
description: Version created successfully
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Forbidden - not the workflow owner
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Workflow not found
"409":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Version conflict - base_version does not match latest
"422":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Validation error
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Create a new version
tags:
- workflows
/api/workflows/published/{share_id}:
get:
description: |
Returns the published workflow details including the status of each
published asset relative to the caller's library. Authentication is required.
operationId: getPublishedWorkflow
parameters:
- description: The share ID of the published workflow.
in: path
name: share_id
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
$ref: '#/components/schemas/PublishedWorkflowDetail'
description: Published workflow details with asset statuses
"400":
$ref: '#/components/responses/SessionWorkspaceIDInvalid'
"401":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Unauthorized
"403":
$ref: '#/components/responses/SessionForbidden'
"404":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Share not found
"413":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Workflow JSON too large
"500":
content:
application/json:
schema:
$ref: '#/components/schemas/ErrorResponse'
description: Internal server error
security:
- ApiKeyAuth: []
- BearerAuth: []
- WebSessionAuth: []
summary: Get a published workflow by share ID
tags:
- workflows
/health:
get:
description: |
Returns `200 OK` if the database is reachable and dynamic config has
loaded, otherwise `503 Service Unavailable`. Used by the GKE ingress
for health checks. Response body is plain text for probe simplicity.
operationId: getHealth
responses:
"200":
content:
text/plain:
schema:
example: OK
type: string
description: Service is healthy
"503":
content:
text/plain:
schema:
example: Service Unavailable
type: string
description: Service is unhealthy
security: []
summary: Health probe for Kubernetes readiness/liveness
tags:
- system
/internal/folder_paths:
get:
description: Returns the filesystem paths ComfyUI loads models and assets from, keyed by folder type.
operationId: getInternalFolderPaths
responses:
"200":
content:
application/json:
schema:
additionalProperties:
items:
items:
type: string
type: array
type: array
description: Map of folder type name to list of path entries
type: object
description: Dictionary of folder type to paths
summary: Get configured folder paths
/internal/logs:
get:
description: Returns ComfyUI log entries from the in-memory log buffer.
operationId: getInternalLogs
responses:
"200":
content:
text/plain:
schema:
type: string
description: Log text
summary: Get server logs as text
/internal/logs/raw:
get:
description: Returns the raw ComfyUI log buffer plus size metadata.
operationId: getInternalLogsRaw
responses:
"200":
content:
application/json:
schema:
properties:
entries:
items:
properties:
m:
description: Message
type: string
t:
description: Timestamp
type: number
type: object
type: array
size:
properties:
cols:
type: integer
rows:
type: integer
type: object
type: object
description: Structured log data
summary: Get raw structured log entries
/internal/logs/subscribe:
patch:
description: Subscribes or unsubscribes the current client from live log streaming over the WebSocket.
operationId: subscribeToLogs
requestBody:
content:
application/json:
schema:
properties:
clientId:
description: WebSocket client ID
type: string
enabled:
description: Enable or disable log streaming for this client
type: boolean
required:
- clientId
- enabled
type: object
required: true
responses:
"200":
description: Subscription updated
summary: Subscribe or unsubscribe a WebSocket client to log streaming
security:
- ApiKeyAuth: []
- BearerAuth: []
servers:
- description: Default ComfyUI server
url: /
tags:
- description: Workflow execution and management
name: workflow
- description: Node information
name: node
- description: File operations
name: file
- description: User settings management
name: settings
- description: User feedback management
name: feedback
- description: System operations and monitoring
name: system
- description: User information and management
name: user
- description: Background task management
name: task
- description: Comfy Content Catalog discovery, reads and staff authoring
name: site-catalog
- description: Workspace billing and subscription management
name: billing
- description: Workflow storage and version management
name: workflows
- description: Job queue state and control
name: queue
- description: Job lifecycle queries
name: job