components: schemas: AcceptInviteResponse: description: Response returned after successfully accepting a workspace invitation. properties: workspace_id: description: ID of the workspace joined type: string workspace_name: description: Name of the workspace joined type: string required: - workspace_id - workspace_name type: object Asset: description: Represents a user-owned asset (image, video, or other generated output). properties: asset_hash: description: Blake3 hash of the asset content pattern: ^blake3:[a-f0-9]{64}$ type: string 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 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 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 prompt_id: deprecated: true description: 'Deprecated: use job_id instead. ID of the prompt that created this asset, if available' format: uuid nullable: true type: string 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 - size - 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. AssetDownloadResponse: description: Acknowledgement of an async asset download task; clients poll GET /api/tasks/{task_id} for status. properties: message: description: Human-readable message example: Download task created. Use task_id to track progress. type: string status: description: Current task status enum: - created - running - completed - failed type: string task_id: description: Task ID for tracking download progress via GET /api/tasks/{task_id} format: uuid type: string required: - task_id - status type: object 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 AssetMetadataResponse: description: Metadata for a remotely hosted asset resolved by URL. properties: content_length: description: Size of the asset in bytes (-1 if unknown) example: 4294967296 format: int64 type: integer content_type: description: MIME type of the asset example: application/octet-stream type: string filename: description: Suggested filename for the asset from source example: realistic-vision-v5.safetensors type: string name: description: Display name or title for the asset from source example: Realistic Vision v5.0 type: string preview_image: description: Preview image as base64-encoded data URL example: data:image/jpeg;base64,/9j/4AAQSkZJRg... type: string tags: description: Tags for categorization from source example: - models - checkpoint items: type: string type: array validation: allOf: - $ref: '#/components/schemas/ValidationResult' description: Validation results for the file required: - content_length 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: asset_hash: description: Blake3 hash of the asset content pattern: ^blake3:[a-f0-9]{64}$ type: string display_name: description: Display name of the asset. Mirrors name for backwards compatibility. nullable: true type: string id: description: Asset ID format: uuid 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 BillingBalanceResponse: description: Current credit balance and usage details for a workspace. properties: amount_micros: description: The total remaining balance in microamount (1/1,000,000 of the currency unit) format: double type: number cloud_credit_balance_micros: description: The remaining balance from cloud credits in microamount format: double type: number currency: description: Currency code example: usd type: string effective_balance_micros: description: The effective balance (total balance minus pending charges). Can be negative if pending charges exceed the balance. format: double type: number pending_charges_micros: description: The total amount of pending/unbilled charges from draft invoices in microamount format: double type: number prepaid_balance_micros: description: The remaining balance from prepaid commits in microamount format: double type: number required: - amount_micros - currency type: object BillingEvent: description: A single billing event such as a charge, credit, or adjustment. properties: createdAt: description: When the event occurred format: date-time type: string event_id: description: Unique event identifier type: string event_type: description: Type of billing event (e.g., subscription.created, payment.succeeded) type: string params: additionalProperties: true description: Event-specific parameters type: object required: - event_type - event_id - createdAt type: object BillingEventsResponse: description: Paginated list of billing events for a workspace. properties: events: items: $ref: '#/components/schemas/BillingEvent' type: array limit: description: Items per page type: integer page: description: Current page number (1-indexed) type: integer total: description: Total number of events type: integer totalPages: description: Total number of pages type: integer required: - total - events - page - limit - totalPages type: object BillingOpStatusResponse: description: Status of an asynchronous billing operation. properties: completed_at: description: When the operation completed (success or failure) format: date-time type: string error_message: description: Error message if status is failed type: string id: description: Unique identifier for the billing operation type: string started_at: description: When the operation was initiated format: date-time type: string status: description: Current status of the operation enum: - pending - succeeded - failed type: string required: - id - status - started_at type: object BillingPlansResponse: description: List of available billing plans for subscription. properties: current_plan_slug: description: Current plan slug if subscribed type: string plans: items: $ref: '#/components/schemas/Plan' type: array required: - plans type: object BillingStatus: description: Payment lifecycle status enum: - awaiting_payment_method - pending_payment - paid - payment_failed - inactive type: string BillingStatusResponse: description: Current billing and subscription status for a workspace. properties: billing_status: $ref: '#/components/schemas/BillingStatus' cancel_at: description: When the subscription will become inactive (if canceled) format: date-time type: string has_funds: description: Whether the workspace has available credits type: boolean is_active: description: Whether the workspace has an active subscription type: boolean plan_slug: description: Plan identifier (e.g., standard-monthly, team-pro-annual) type: string renewal_date: description: When the current billing period ends and the next one begins format: date-time type: string subscription_duration: $ref: '#/components/schemas/SubscriptionDuration' subscription_status: description: Subscription activity status (scheduled subscriptions are not returned) enum: - active - ended - canceled type: string subscription_tier: $ref: '#/components/schemas/SubscriptionTier' required: - is_active - has_funds type: object BindingErrorResponse: description: Error shape returned when request binding or validation fails before the handler runs. properties: message: type: string required: - message type: object BulkRevokeAPIKeysResponse: description: Response after bulk-revoking API keys for a workspace member. properties: revoked_count: description: Number of API keys that were revoked minimum: 0 type: integer required: - revoked_count type: object CancelSubscriptionRequest: description: Request body for cancelling the current subscription. properties: idempotency_key: description: | Client-provided key to prevent duplicate operations. If a billing op with this key already exists, returns the existing op instead of creating a new one. type: string type: object CancelSubscriptionResponse: description: Response after successfully cancelling a subscription. properties: billing_op_id: description: Billing operation ID to poll for status via GET /api/billing/ops/{id} type: string cancel_at: description: The date when the subscription will end (end of current billing period) format: date-time type: string required: - cancel_at - billing_op_id type: object CreateHubProfileRequest: description: Request body for creating a new Hub profile. properties: avatar_token: description: | Token (from /api/hub/assets/upload-url) for an avatar image. Omit to have no avatar. type: string description: type: string display_name: type: string username: description: Unique URL-safe slug for the hub profile. Immutable after creation. type: string website_urls: description: List of website URLs. items: type: string type: array workspace_id: description: ID of the workspace to create the hub profile for. The authenticated user must belong to this workspace. type: string required: - workspace_id - username type: object CreateInviteRequest: description: Request body for inviting a user to a workspace. properties: email: description: Email address to invite format: email type: string required: - email type: object CreateSecretRequest: description: Request body for creating a new user secret. properties: name: description: User-provided label for the secret maxLength: 255 minLength: 1 type: string provider: description: Optional provider identifier (e.g., huggingface, civitai) maxLength: 64 type: string secret_value: description: The plaintext secret to encrypt and store minLength: 1 type: string required: - name - secret_value type: object CreateSessionResponse: description: Response after creating a session cookie properties: expiresIn: description: Session expiration time in seconds (5 days) type: integer success: description: Whether the session was created successfully type: boolean required: - success type: object CreateTopupRequest: description: Request body for purchasing a one-time credit top-up. properties: amount_cents: description: Amount to charge and grant as credits (in cents). Minimum $5.00. format: int64 minimum: 500 type: integer idempotency_key: description: | Client-provided key to prevent duplicate operations. If a billing op with this key already exists, returns the existing op instead of creating a new one. type: string required: - amount_cents type: object CreateTopupResponse: description: Response after successfully purchasing a credit top-up. properties: amount_cents: description: Amount being charged in cents format: int64 type: integer billing_op_id: description: Billing operation ID to poll for status via GET /api/billing/ops/{id} type: string status: description: Current status of the top-up enum: - pending - completed - failed type: string topup_id: description: Unique identifier for the top-up request (same as billing_op_id, deprecated) type: string required: - topup_id - status - amount_cents - billing_op_id 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 CreateWorkspaceAPIKeyRequest: description: Request body for creating a new workspace-scoped API key. properties: description: description: User-provided description of the key's purpose. Limit is byte-based (UTF-8 encoding); 5000 bytes equals 5000 ASCII characters or fewer multi-byte characters. maxLength: 5000 type: string expires_at: description: Optional expiration timestamp format: date-time type: string name: description: User-provided label for the key type: string required: - name type: object CreateWorkspaceAPIKeyResponse: description: Response containing the newly created workspace API key. properties: created_at: description: When the key was created format: date-time type: string description: description: User-provided description of the key's purpose. Limit is byte-based (UTF-8 encoding); 5000 bytes equals 5000 ASCII characters or fewer multi-byte characters. maxLength: 5000 type: string expires_at: description: When the key expires (if set) format: date-time type: string id: description: API key ID format: uuid type: string key: description: The full plaintext API key (only shown once) type: string key_prefix: description: First 8 chars after prefix for display type: string name: description: User-provided label type: string required: - id - name - description - key - key_prefix - created_at type: object CreateWorkspaceRequest: description: Request body for creating a new workspace. properties: name: description: Display name for the workspace example: My Team Workspace maxLength: 100 minLength: 1 type: string required: - name type: object DeleteSessionResponse: description: Response after deleting a session cookie properties: success: description: Whether the session was deleted successfully type: boolean required: - success type: object ErrorResponse: description: Standard error response with a machine-readable code and human-readable message. properties: code: type: string message: type: string required: - code - message type: object ExchangeTokenRequest: description: | Optional request body for the token exchange endpoint. The Firebase JWT being exchanged is supplied via the `Authorization: Bearer` header; this body only carries workspace-selection input. properties: workspace_id: description: Workspace ID to get token for. Defaults to personal workspace if omitted. example: w-a1b2c3d4-5678-90ab-cdef-1234567890ab type: string type: object ExchangeTokenResponse: description: Response containing the issued Cloud JWT and its expiry. properties: expires_at: description: Token expiration time (RFC 3339) format: date-time type: string permissions: description: Permission strings for the role example: - owner:* items: type: string type: array role: description: User's role in the workspace enum: - owner - member type: string token: description: Cloud JWT token type: string workspace: $ref: '#/components/schemas/WorkspaceSummary' required: - token - expires_at - workspace - role - permissions 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 ExportDownloadURLResponse: description: Response containing a signed download URL for an exported asset archive. properties: expires_at: description: When the signed URL expires format: date-time type: string url: description: Signed URL for downloading the export ZIP file type: string required: - url 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 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 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 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 HubAssetUploadUrlRequest: description: Request body for requesting a signed upload URL for a Hub asset. properties: content_type: description: | MIME type of the file (e.g. "image/jpeg", "video/mp4"). Validated against a whitelist; the canonical file extension is derived from this value. type: string filename: description: Original filename for display purposes. Not used in the storage key. type: string required: - filename - content_type type: object HubAssetUploadUrlResponse: description: Response containing a signed upload URL and the target asset path. properties: public_url: description: The public URL where the file will be accessible after upload. type: string token: description: Signed token to pass in the publish request. Has a server-determined TTL. type: string upload_url: description: Presigned R2 URL for uploading the file via PUT. type: string required: - upload_url - public_url - token type: object HubLabelInfo: description: Metadata for a single Hub label. properties: description: description: Optional description of the label. type: string display_name: description: Human-readable display name. type: string name: description: Slug identifier. type: string type: description: Label category. enum: - tag - model - custom_node type: string required: - name - display_name - type type: object HubLabelListResponse: description: List of available Hub labels for categorizing workflows. properties: labels: description: Available labels filtered by type (or all if no type specified). items: $ref: '#/components/schemas/HubLabelInfo' type: array required: - labels type: object HubProfile: description: Full public profile for a Hub creator. properties: avatar_url: description: Public URL of the profile avatar image. type: string description: type: string display_name: type: string username: type: string website_urls: description: List of website URLs. items: type: string type: array required: - username type: object HubProfileSummary: description: Abbreviated Hub profile used in workflow listings. properties: avatar_url: description: Public URL of the profile avatar image. type: string display_name: type: string username: type: string required: - username type: object HubUsernameCheckResponse: description: Response indicating whether a Hub username is available. properties: available: description: Whether the username is available for the caller's workspace. type: boolean suggestions: description: Up to 5 available alternative usernames (only present when unavailable). items: type: string type: array username: description: The username that was checked. type: string validation_error: description: If the username format is invalid, describes the format requirement. type: string required: - username - available type: object HubWorkflowDetail: description: Full Hub workflow detail including versions, assets, and statistics. properties: assets: description: Published assets. Each asset's id is the published asset ID (not the original private asset ID). items: $ref: '#/components/schemas/AssetInfo' type: array custom_nodes: items: $ref: '#/components/schemas/LabelRef' type: array description: type: string metadata: additionalProperties: true type: object models: items: $ref: '#/components/schemas/LabelRef' type: array name: type: string profile: $ref: '#/components/schemas/HubProfileSummary' publish_time: format: date-time nullable: true type: string sample_image_urls: items: type: string type: array share_id: type: string status: $ref: '#/components/schemas/HubWorkflowStatus' tags: items: $ref: '#/components/schemas/LabelRef' type: array thumbnail_comparison_url: type: string thumbnail_type: enum: - image - video - image_comparison type: string thumbnail_url: type: string tutorial_url: type: string workflow_id: type: string workflow_json: additionalProperties: true type: object required: - share_id - workflow_id - name - workflow_json - assets - profile - status type: object HubWorkflowListResponse: description: Paginated list of Hub workflows matching search criteria. properties: next_cursor: description: Cursor for the next page, empty if no more results. type: string workflows: description: Array of HubWorkflowSummary (default) or HubWorkflowDetail (when detail=true). items: anyOf: - $ref: '#/components/schemas/HubWorkflowSummary' - $ref: '#/components/schemas/HubWorkflowDetail' type: array required: - workflows type: object HubWorkflowStatus: description: Public workflow status. NULL in the database is represented as pending in API responses. enum: - pending - approved - rejected - deprecated type: string HubWorkflowSummary: description: Abbreviated Hub workflow metadata used in search and listing results. properties: custom_nodes: items: $ref: '#/components/schemas/LabelRef' type: array description: type: string metadata: additionalProperties: true type: object models: items: $ref: '#/components/schemas/LabelRef' type: array name: type: string profile: $ref: '#/components/schemas/HubProfileSummary' publish_time: format: date-time nullable: true type: string sample_image_urls: items: type: string type: array share_id: type: string status: $ref: '#/components/schemas/HubWorkflowStatus' tags: items: $ref: '#/components/schemas/LabelRef' type: array thumbnail_comparison_url: type: string thumbnail_type: enum: - image - video - image_comparison type: string thumbnail_url: type: string tutorial_url: type: string required: - share_id - name - profile - status type: object HubWorkflowTemplateEntry: description: Entry in the curated workflow template gallery shown on the home page. properties: contentTemplate: description: Content template used for generation (tutorial, showcase, comparison, breakthrough) type: string date: description: Publication date in YYYY-MM-DD format type: string description: type: string extendedDescription: description: AI-generated extended description of the workflow type: string faqItems: description: AI-generated FAQ items items: properties: answer: type: string question: type: string required: - question - answer type: object type: array howToUse: description: AI-generated step-by-step usage instructions items: type: string type: array includeOnDistributions: items: type: string type: array io: properties: inputs: items: additionalProperties: true type: object type: array outputs: items: additionalProperties: true type: object type: array type: object isEssential: description: Whether the template belongs to a module marked as essential. type: boolean logos: items: additionalProperties: true type: object type: array mediaSubtype: type: string mediaType: type: string metaDescription: description: AI-generated SEO meta description (under 160 chars) type: string models: items: type: string type: array name: description: Slug identifier for the template type: string openSource: type: boolean profile: $ref: '#/components/schemas/HubProfileSummary' requiresCustomNodes: items: type: string type: array searchRank: description: Search ranking score reported upstream. format: int64 type: integer shareId: description: Share ID for linking to the hub workflow detail type: string size: description: Workflow asset size in bytes. format: int64 type: integer status: $ref: '#/components/schemas/HubWorkflowStatus' suggestedUseCases: description: AI-generated suggested use cases items: type: string type: array tags: items: type: string type: array thumbnailComparisonUrl: description: Public URL of the comparison thumbnail type: string thumbnailUrl: description: Public URL of the primary thumbnail type: string thumbnailVariant: type: string title: type: string tutorialUrl: type: string usage: description: Usage count reported upstream. format: int64 type: integer vram: description: Approximate VRAM requirement in bytes. format: int64 type: integer required: - name - title - status type: object ImportPublishedAssetsRequest: description: Request body for importing assets from a published workflow. properties: published_asset_ids: description: IDs of published assets (inputs and models) to import. items: type: string type: array share_id: description: | Optional. Share ID of the published workflow these assets belong to. When provided (non-null, non-empty): all published_asset_ids must belong to this share's workflow version; returns 400/CodeInvalidAssets if the share is not found or any asset does not belong to it. When omitted, null, or empty string: no share-scoped validation is performed and the assets are validated only against global rules (legacy behaviour, preserved for clients that have not yet adopted share_id). nullable: true type: string required: - published_asset_ids type: object ImportPublishedAssetsResponse: description: Response after importing published workflow assets. properties: assets: items: $ref: '#/components/schemas/AssetInfo' type: array required: - assets 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 JobDetailResponse: description: Full job details including workflow and outputs properties: create_time: description: Job creation timestamp (Unix timestamp in milliseconds) 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_status: additionalProperties: true description: ComfyUI execution status and timeline (only for terminal states) type: object 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 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 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 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 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 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 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 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 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 JwkKey: description: A single JSON Web Key entry within a JWKS response. properties: alg: example: ES256 type: string crv: example: P-256 type: string kid: example: cloud-jwt-key-1 type: string kty: example: EC type: string use: example: sig type: string x: description: Base64url-encoded X coordinate type: string "y": description: Base64url-encoded Y coordinate type: string required: - kty - crv - kid - use - alg - x - "y" type: object JwksResponse: description: JSON Web Key Set containing the public keys used to verify Cloud JWTs. properties: keys: items: $ref: '#/components/schemas/JwkKey' type: array required: - keys type: object LabelRef: description: Reference to a Hub label by ID. properties: display_name: description: Human-readable display name (e.g. "Video Generation", "Flux"). type: string name: description: Slug identifier (e.g. "video-generation", "flux"). type: string required: - name - display_name 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 ListInvitesResponse: description: List of pending invitations for the current workspace. properties: invites: items: $ref: '#/components/schemas/PendingInvite' type: array required: - invites type: object ListMembersResponse: description: List of members in the current workspace. properties: members: items: $ref: '#/components/schemas/Member' type: array pagination: $ref: '#/components/schemas/PaginationInfo' required: - members - pagination 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 ListWorkspaceAPIKeysResponse: description: List of API keys associated with the current workspace. properties: api_keys: items: $ref: '#/components/schemas/WorkspaceAPIKeyInfo' type: array required: - api_keys type: object ListWorkspacesResponse: description: Paginated list of workspaces the authenticated user belongs to. properties: workspaces: items: $ref: '#/components/schemas/WorkspaceWithRole' type: array required: - workspaces type: object Member: description: Workspace member with profile and role information. properties: email: description: User's email address format: email type: string id: description: User ID type: string joined_at: description: When the user joined the workspace format: date-time type: string name: description: User's display name type: string role: description: User's role in the workspace enum: - owner - member type: string required: - id - name - email - role - joined_at 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 OAuthAuthorizationServerMetadata: description: OAuth 2.1 authorization-server metadata (RFC 8414). properties: authorization_endpoint: format: uri type: string code_challenge_methods_supported: items: type: string type: array grant_types_supported: items: type: string type: array issuer: format: uri type: string jwks_uri: format: uri type: string registration_endpoint: description: | RFC 7591 §3.1 Dynamic Client Registration endpoint. Advertised so MCP-spec-compliant clients can auto-discover and self-register without operator involvement. Present only when DCR is enabled. format: uri type: string response_types_supported: items: type: string type: array scopes_supported: items: type: string type: array token_endpoint: format: uri type: string token_endpoint_auth_methods_supported: items: type: string type: array required: - issuer - authorization_endpoint - token_endpoint - jwks_uri - response_types_supported - grant_types_supported - code_challenge_methods_supported - token_endpoint_auth_methods_supported type: object OAuthAuthorizeRedirectResponse: description: Redirect target produced after a JSON consent submission. The frontend must navigate the browser to this URL so custom-scheme client callbacks work without relying on fetch-visible 302 headers. properties: redirect_url: description: OAuth client redirect URI with either code+state for allow, or error+state for deny. format: uri type: string required: - redirect_url type: object OAuthConsentChallenge: description: | Server-side state describing the OAuth consent decision the user is being asked to make. Returned by GET /oauth/authorize when a valid Cloud session exists; the frontend renders the consent UI from this payload and POSTs the decision back. Browser never sees the original OAuth params on resume. properties: client_display_name: description: Human-readable name of the OAuth client requesting authorization, from oauth_clients.display_name. type: string csrf_token: description: Per-row CSRF token bound to this authorization request (not to the session). Must be echoed back on POST. type: string oauth_request_id: description: Opaque server-side identifier for the authorization-request row. Carried back unchanged in the consent submission. format: uuid type: string resource_display_name: description: Human-readable name of the protected resource, from oauth_resources.display_name. type: string scopes: description: Scopes the client is requesting for this resource. The frontend should present these for the user to approve. items: type: string type: array workspaces: description: Workspaces the user can select from. Membership is re-checked on POST. items: $ref: '#/components/schemas/OAuthConsentChallengeWorkspace' type: array required: - oauth_request_id - csrf_token - client_display_name - resource_display_name - scopes - workspaces type: object OAuthConsentChallengeWorkspace: description: | One workspace option presented in the OAuth consent challenge. Promoted to a named schema so the generated Go type is referenceable in handlers and tests rather than re-declared as an anonymous struct at every callsite. properties: id: type: string name: type: string role: enum: - owner - member type: string type: enum: - personal - team type: string required: - id - name - type - role type: object OAuthProtectedResourceMetadata: description: OAuth 2.1 protected-resource metadata (RFC 9728). properties: authorization_servers: items: format: uri type: string type: array bearer_methods_supported: items: type: string type: array resource: format: uri type: string scopes_supported: items: type: string type: array required: - resource - authorization_servers - scopes_supported type: object OAuthRegisterBadRequestResponse: description: | Union of the two 400 shapes /oauth/register can emit. `OAuthRegisterError` is the handler-shaped RFC 7591 §3.2.2 error; `BindingErrorResponse` is the strict-server binding-layer error fired when the request body fails OpenAPI-schema validation before the handler runs. oneOf: - $ref: '#/components/schemas/OAuthRegisterError' - $ref: '#/components/schemas/BindingErrorResponse' OAuthRegisterError: description: RFC 7591 §3.2.2 error response. properties: error: enum: - invalid_redirect_uri - invalid_client_metadata type: string error_description: nullable: true type: string required: - error type: object OAuthRegisterRequest: additionalProperties: false description: | RFC 7591 §2 client metadata document. Only the fields the server honors are listed; presence of `scope` or `resource_grants` in the request is rejected (`invalid_client_metadata`) because those are server-owned for dynamic clients. `additionalProperties: false` mirrors the runtime middleware that rejects any unknown metadata key. properties: application_type: description: | RFC 7591 §2 application_type. **OPTIONAL** — omit the field to default to `native` (the loopback-friendly policy), rather than the RFC's nominal `web` default; the MCP SDK's DCR client omits it. `native` for desktop / CLI / MCP-spec-strict clients (loopback redirects); `web` for hosted clients (HTTPS only, host must be allowlisted). The realistic MCP-client population is overwhelmingly native/loopback, so defaulting to `web` would silently bounce those clients off the wrong redirect policy. A *present* value must be one of the enum members; any other value rejects with `invalid_client_metadata`. (The server has no runtime enum validation and defensively coerces a null/empty value to `native`, but spec-validating clients should omit the field rather than send `""` — the enum does not permit it.) enum: - native - web type: string client_name: description: Human-readable name shown in the consent UI. Reserved-name list rejects impersonation of major MCP clients. maxLength: 100 type: string client_uri: description: '**REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase.' nullable: true type: string contacts: description: '**REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase.' items: type: string nullable: true type: array grant_types: description: Optional. Defaults to `["authorization_code","refresh_token"]`. items: enum: - authorization_code - refresh_token type: string type: array jwks: additionalProperties: true description: '**REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase.' nullable: true type: object jwks_uri: description: '**REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase.' nullable: true type: string logo_uri: description: '**REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase.' nullable: true type: string policy_uri: description: '**REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase.' nullable: true type: string redirect_uris: description: 1–5 redirect URIs. Validated against `application_type` policy. items: type: string maxItems: 5 minItems: 1 type: array resource_grants: additionalProperties: items: type: string type: array description: | **REJECTED IF PRESENT.** Same reason as `scope`. The set of resources and scopes a dynamic client may request is server-policy, not request-driven. nullable: true type: object response_types: description: Optional. Defaults to `["code"]`. items: enum: - code type: string type: array scope: description: | **REJECTED IF PRESENT.** Dynamic clients do not pick scopes — the server assigns scopes from the active MCP resource's published list. Sending `scope` in the registration body is treated as a privilege-escalation attempt and returns `invalid_client_metadata`. The field is documented here so clients see a well-defined error rather than silent drop. nullable: true type: string software_id: description: '**REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase.' nullable: true type: string software_version: description: '**REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase.' nullable: true type: string token_endpoint_auth_method: description: Public clients only this phase — must be `none` if present. The server forces `none` regardless. enum: - none type: string tos_uri: description: '**REJECTED IF PRESENT.** Unsupported RFC 7591 metadata for this public MCP-client phase.' nullable: true type: string required: - redirect_uris type: object OAuthRegisterResponse: description: RFC 7591 §3.2.1 successful registration response. properties: application_type: enum: - native - web type: string client_id: description: Server-generated client_id. Always carries the `comfy-dyn-` prefix. type: string client_id_issued_at: description: Unix timestamp (seconds) when the client was registered. format: int64 type: integer client_name: type: string grant_types: items: type: string type: array redirect_uris: items: type: string type: array response_types: items: type: string type: array token_endpoint_auth_method: enum: - none type: string required: - client_id - client_id_issued_at - redirect_uris - grant_types - response_types - token_endpoint_auth_method - application_type type: object OAuthTokenError: description: RFC 6749 §5.2 error response. properties: error: description: 'RFC 6749 §5.2 error code: invalid_request, invalid_client, invalid_grant, unauthorized_client, unsupported_grant_type, invalid_scope.' type: string error_description: description: Human-readable, no leak of internal storage state. type: string required: - error type: object OAuthTokenResponse: description: RFC 6749 §5.1 successful token response. properties: access_token: description: Resource-bound Cloud JWT (audience matches the protected resource). type: string expires_in: description: Access token lifetime in seconds. type: integer refresh_token: description: Opaque refresh token. Rotates on every successful refresh; presenting an already-rotated token revokes the entire family. type: string scope: description: Space-delimited scopes granted with this token. type: string token_type: enum: - Bearer type: string required: - access_token - token_type - expires_in - refresh_token - scope type: object PaginationInfo: description: Offset/limit-based pagination metadata included in list responses. properties: has_more: description: Whether more items are available beyond this page type: boolean limit: description: Items per page minimum: 1 type: integer offset: description: Current offset (0-based) minimum: 0 type: integer total: description: Total number of items matching filters minimum: 0 type: integer required: - offset - limit - total - has_more type: object PaymentPortalRequest: description: Request body for generating a payment portal session URL. properties: return_url: description: URL to redirect after the user exits the portal type: string type: object PaymentPortalResponse: description: Response containing a redirect URL to the payment portal. properties: url: description: Stripe Billing Portal URL type: string required: - url type: object PendingInvite: description: An outstanding workspace invitation that has not yet been accepted. properties: email: description: Email address of the invited user format: email type: string expires_at: description: When the invite expires format: date-time type: string id: description: Invite ID type: string invited_at: description: When the invite was created format: date-time type: string token: description: Invite token for constructing invite links. Empty for expired invites. type: string required: - id - email - invited_at - expires_at type: object Plan: description: Billing plan details including pricing, limits, and features. properties: availability: $ref: '#/components/schemas/PlanAvailability' credits_cents: description: Per-member credits in cents (base + one seat) example: 10000 format: int64 type: integer duration: $ref: '#/components/schemas/SubscriptionDuration' max_seats: description: Maximum number of seats allowed for this plan example: 20 format: int64 type: integer price_cents: description: Per-member price in cents (base + one seat) example: 10000 format: int64 type: integer seat_summary: $ref: '#/components/schemas/PlanSeatSummary' slug: description: Plan identifier (e.g., "pro-monthly", "team-standard-annual") example: pro-monthly type: string tier: $ref: '#/components/schemas/SubscriptionTier' required: - slug - tier - duration - price_cents - credits_cents - max_seats - availability - seat_summary type: object PlanAvailability: description: Availability and eligibility information for a billing plan. properties: available: description: Whether the workspace can subscribe to this plan type: boolean reason: $ref: '#/components/schemas/PlanAvailabilityReason' required: - available type: object PlanAvailabilityReason: description: Reason why a plan is unavailable enum: - same_plan - incompatible_transition - requires_team - requires_personal - exceeds_max_seats type: string PlanSeatSummary: description: Summary of seat costs based on current workspace members properties: seat_count: description: Total number of seats (owner + members) that would be charged example: 5 type: integer total_cost_cents: description: Total cost for all seats in cents example: 50000 format: int64 type: integer total_credits_cents: description: Total credits granted for all seats in cents example: 50000 format: int64 type: integer required: - seat_count - total_cost_cents - total_credits_cents type: object PreviewPlanInfo: description: Plan information for preview display properties: credits_cents: description: Per-seat credits in cents example: 10000 format: int64 type: integer duration: $ref: '#/components/schemas/SubscriptionDuration' period_end: description: Current billing period end (only for current_plan) format: date-time type: string period_start: description: Current billing period start (only for current_plan) format: date-time type: string price_cents: description: Per-seat price in cents example: 10000 format: int64 type: integer seat_summary: $ref: '#/components/schemas/PlanSeatSummary' slug: description: Plan slug example: team-pro-monthly type: string tier: $ref: '#/components/schemas/SubscriptionTier' required: - slug - tier - duration - price_cents - credits_cents - seat_summary type: object PreviewSubscribeRequest: description: Request body for previewing the cost of a plan subscription change. properties: plan_slug: description: Target plan slug to preview subscribing to example: team-pro-monthly type: string required: - plan_slug type: object PreviewSubscribeResponse: description: Itemized cost preview for a pending subscription change. properties: allowed: description: Whether this subscription change is allowed type: boolean cost_next_period_cents: description: Amount that will be charged at next billing period in cents example: 10000 format: int64 type: integer cost_today_cents: description: Amount to charge today in cents (0 for downgrades) example: 5000 format: int64 type: integer credits_next_period_cents: description: Credits that will be granted at next billing period in cents example: 10000 format: int64 type: integer credits_today_cents: description: Credits granted today in cents (prorated for mid-period upgrades) example: 5000 format: int64 type: integer current_plan: $ref: '#/components/schemas/PreviewPlanInfo' effective_at: description: When the change takes effect format: date-time type: string is_immediate: description: Whether the change takes effect immediately (true) or at period end (false) type: boolean new_plan: $ref: '#/components/schemas/PreviewPlanInfo' reason: description: Reason why the change is not allowed (only present if allowed=false) type: string transition_type: description: Type of subscription transition enum: - new_subscription - upgrade - downgrade - duration_change type: string required: - allowed - transition_type - effective_at - is_immediate - cost_today_cents - cost_next_period_cents - credits_today_cents - credits_next_period_cents - new_plan 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 PublishHubWorkflowRequest: description: Request body for publishing or updating a workflow on the Hub. properties: asset_ids: description: IDs of assets (inputs and models) to snapshot. items: type: string type: array custom_nodes: description: Custom node slugs. Must exist in hub_labels. items: type: string type: array description: description: Workflow description for the hub listing. type: string metadata: additionalProperties: true description: Arbitrary metadata (size, vram, open_source, etc.). Reserved keys (extended_description, meta_description, how_to_use, suggested_use_cases, faq_items, content_template) are backend-managed and will be stripped if supplied. type: object models: description: Model slugs. Must exist in hub_labels. items: type: string type: array name: description: Display name for the published workflow on the hub. type: string sample_image_tokens_or_urls: description: | Array of tokens or existing public URLs from the previous published version. Full replacement (PUT semantics). Omit or pass [] to have no sample images. items: type: string type: array tags: description: Searchable tag slugs. Must exist in hub_labels. items: type: string type: array thumbnail_comparison_token_or_url: description: | Token or existing public URL from the previous published version. Omit to have no comparison image. type: string thumbnail_token_or_url: description: | Token (from /api/hub/assets/upload-url) for a new upload, or an existing public URL from the previous published version. Omit to have no thumbnail. type: string thumbnail_type: enum: - image - video - image_comparison type: string tutorial_url: description: URL to a tutorial for this workflow. type: string username: description: Username of the hub profile to publish under. The authenticated user must belong to the workspace that owns this profile. type: string workflow_filename: description: Userdata path of the workflow file (e.g. "workflows/my-flow.json"). type: string required: - username - name - workflow_filename - asset_ids 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: } 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: } 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 PENDING job IDs to cancel 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 ResubscribeRequest: description: Request body for reactivating a previously cancelled subscription. properties: idempotency_key: description: | Client-provided key to prevent duplicate operations. If a billing op with this key already exists, returns the existing op instead of creating a new one. type: string type: object ResubscribeResponse: description: Response after successfully resubscribing to a billing plan. properties: billing_op_id: description: Billing operation ID to poll for status via GET /api/billing/ops/{id} type: string message: description: Human-readable confirmation message type: string status: description: The subscription status after resubscribing enum: - active type: string required: - status - billing_op_id type: object SecretListResponse: description: List of user secrets with metadata only. properties: data: items: $ref: '#/components/schemas/SecretResponse' type: array required: - data type: object SecretResponse: description: User secret metadata (the secret value itself is never returned after creation). properties: created_at: description: When the secret was created format: date-time type: string id: description: Unique identifier for the secret format: uuid type: string last_used_at: description: When the secret was last used for decryption format: date-time type: string name: description: User-provided label for the secret type: string provider: description: Provider identifier (e.g., huggingface, civitai) type: string updated_at: description: When the secret was last updated format: date-time type: string required: - id - name - created_at - updated_at type: object SubscribeRequest: description: Request body for subscribing a workspace to a billing plan. properties: cancel_url: description: | URL to redirect if user cancels the payment method flow. If not provided, return_url is used for both success and cancel. example: https://cloud.comfy.org/billing type: string idempotency_key: description: | Client-provided key to prevent duplicate operations. If a billing op with this key already exists, returns the existing op instead of creating a new one. example: sub-abc123-1234567890 type: string plan_slug: description: Target plan slug to subscribe to example: team-pro-monthly type: string return_url: description: | URL to redirect after payment method is added successfully. Required if workspace has no payment method on file. example: https://cloud.comfy.org/billing/success type: string required: - plan_slug type: object SubscribeResponse: description: Response after successfully subscribing to a billing plan. properties: billing_op_id: description: Billing operation ID to poll for status via GET /api/billing/ops/{id} type: string effective_at: description: When the subscription became/becomes active (present when status=subscribed or pending_payment) format: date-time type: string payment_method_url: description: URL to redirect user to add payment method (present when status=needs_payment_method) type: string status: description: | Status of the subscription operation: - subscribed: Subscription is active immediately - needs_payment_method: User must add payment method via payment_method_url - pending_payment: Upgrade initiated, waiting for payment to complete enum: - subscribed - needs_payment_method - pending_payment type: string required: - status - billing_op_id type: object SubscriptionDuration: description: Billing period (uppercase to match comfy-api) enum: - MONTHLY - ANNUAL type: string SubscriptionTier: description: Subscription tier (uppercase to match comfy-api) enum: - FREE - STANDARD - CREATOR - PRO - FOUNDERS_EDITION type: string 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 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 or failed (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 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 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 UpdateHubProfileRequest: description: Request body for updating an existing Hub profile. properties: avatar_token: description: | Token (from /api/hub/assets/upload-url) for a new avatar image. Omit or send null to leave unchanged; send empty string "" to remove. nullable: true type: string description: type: string display_name: type: string website_urls: description: List of website URLs. items: type: string type: array type: object UpdateSecretRequest: description: Request body for updating an existing user secret. properties: name: description: New name for the secret maxLength: 255 minLength: 1 type: string secret_value: description: New secret value (API key, token, etc.) minLength: 1 type: string 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 UpdateWorkspaceRequest: description: Request body for updating an existing workspace's settings. properties: name: description: New display name for the workspace example: New Team Name maxLength: 100 minLength: 1 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 ValidationError: description: Details of a single validation error encountered during asset operations. properties: code: description: Machine-readable error code example: FORMAT_NOT_ALLOWED type: string field: description: Field that failed validation example: format type: string message: description: Human-readable error message example: 'File format "PickleTensor" is not allowed. Allowed formats: [SafeTensor]' type: string required: - code - message - field type: object ValidationResult: description: Result of validating a set of asset operations. properties: errors: description: Blocking validation errors that prevent download items: $ref: '#/components/schemas/ValidationError' type: array is_valid: description: Overall validation status (true if all checks passed) example: true type: boolean warnings: description: Non-blocking validation warnings (informational only) items: $ref: '#/components/schemas/ValidationError' type: array required: - is_valid type: object WorkflowApiAssetsRequest: description: Request body for querying assets associated with a workflow. properties: workflow_api_json: additionalProperties: true type: object required: - workflow_api_json type: object WorkflowApiAssetsResponse: description: Response containing assets associated with a workflow. properties: assets: items: $ref: '#/components/schemas/AssetInfo' type: array required: - assets 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 Workspace: description: Full workspace entity with configuration and ownership details. properties: created_at: format: date-time type: string id: example: w-a1b2c3d4-5678-90ab-cdef-1234567890ab type: string name: example: My Team type: string type: enum: - personal - team type: string required: - id - name - type - created_at type: object WorkspaceAPIKeyInfo: description: Metadata for a workspace-scoped API key (secret is never returned). properties: created_at: description: When the key was created format: date-time type: string description: description: User-provided description of the key's purpose. Limit is byte-based (UTF-8 encoding); 5000 bytes equals 5000 ASCII characters or fewer multi-byte characters. maxLength: 5000 type: string expires_at: description: When the key expires (if set) format: date-time type: string id: description: API key ID format: uuid type: string key_prefix: description: First 8 chars after prefix for display type: string last_used_at: description: Last time the key was used format: date-time type: string name: description: User-provided label type: string revoked_at: description: When the key was revoked (if revoked) format: date-time type: string user_id: description: User who created this key type: string workspace_id: description: Workspace this key belongs to type: string required: - id - workspace_id - user_id - name - description - key_prefix - created_at type: object WorkspaceSummary: description: Abbreviated workspace metadata used in list responses. properties: id: example: w-a1b2c3d4-5678-90ab-cdef-1234567890ab type: string name: example: My Team type: string type: enum: - personal - team type: string required: - id - name - type type: object WorkspaceWithRole: description: Workspace entity annotated with the requesting user's role. properties: created_at: description: When the workspace was created format: date-time type: string id: example: w-a1b2c3d4-5678-90ab-cdef-1234567890ab type: string joined_at: description: When the user joined the workspace (same as created_at for the workspace creator) format: date-time type: string name: example: My Team type: string role: enum: - owner - member type: string subscription_tier: $ref: '#/components/schemas/SubscriptionTier' type: enum: - personal - team type: string required: - id - name - type - role - created_at - joined_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: | Firebase JWT token authentication. Obtain a token by authenticating with Firebase and pass it in the Authorization header. scheme: bearer type: http CookieAuth: description: | Session cookie authentication. Set automatically after successful login via the /api/auth/session endpoint. in: cookie name: 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: /.well-known/jwks.json: get: description: Public keys for validating Cloud JWTs operationId: getJwks responses: "200": content: application/json: schema: $ref: '#/components/schemas/JwksResponse' description: JWKS response headers: Cache-Control: description: Caching directive (e.g., "public, max-age=86400") schema: type: string security: [] summary: Get JSON Web Key Set tags: - auth /.well-known/oauth-authorization-server: get: description: Public metadata document for OAuth 2.1 clients. Cached 5 minutes. operationId: getOAuthAuthorizationServer responses: "200": content: application/json: schema: $ref: '#/components/schemas/OAuthAuthorizationServerMetadata' description: Authorization-server metadata headers: Cache-Control: description: 'Caching directive: "public, max-age=300"' schema: type: string "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: OAuth disabled security: [] summary: OAuth 2.1 authorization-server metadata (RFC 8414) tags: - oauth /.well-known/oauth-protected-resource: get: description: Public metadata describing the currently advertised protected resource. Cached 5 minutes. MCP is the only seeded active resource in the initial rollout. operationId: getOAuthProtectedResource responses: "200": content: application/json: schema: $ref: '#/components/schemas/OAuthProtectedResourceMetadata' description: Protected-resource metadata headers: Cache-Control: description: 'Caching directive: "public, max-age=300"' schema: type: string "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: OAuth disabled or no active resource configured security: [] summary: OAuth 2.1 protected-resource metadata (RFC 9728) tags: - oauth /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: - description: Filter assets that have ALL of these tags explode: false in: query name: include_tags schema: items: type: string type: array style: form - description: Exclude assets that have ANY of these tags explode: false in: query name: exclude_tags 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 exact content hash in: query name: asset_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 "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: List user assets tags: - file post: description: | Uploads a new asset to the system with associated metadata. Supports two upload methods: 1. Direct file upload (multipart/form-data) 2. URL-based upload (application/json with source: "url") If an asset with the same hash already exists, returns the existing asset. operationId: uploadAsset requestBody: content: application/json: schema: properties: name: description: Display name for the asset (used to determine file extension) type: string preview_id: description: Optional preview asset ID format: uuid 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. items: type: string type: array url: description: HTTP/HTTPS URL to download the asset from format: uri type: string user_metadata: additionalProperties: true description: Custom metadata to store with the asset type: object required: - url - name type: object multipart/form-data: schema: properties: file: description: The asset file to upload format: binary type: string id: description: Optional asset ID for idempotent creation. If provided and asset exists, returns existing asset. 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. If not provided, images will use their own ID as preview. format: uuid 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. items: type: string type: array user_metadata: description: Custom JSON metadata as a string type: string required: - file type: object required: true responses: "201": content: application/json: schema: $ref: '#/components/schemas/AssetCreated' description: Asset created successfully "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid request (bad file, invalid URL, invalid content type, etc.) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Source URL requires authentication or access denied "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Source URL not found "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: Download failed due to network error or timeout "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Upload a new asset tags: - file /api/assets/{id}: delete: description: | Deletes an asset and its content from storage. Both the database record and storage content are deleted. operationId: deleteAsset parameters: - description: Asset ID in: path name: id required: true schema: format: uuid type: string responses: "204": description: Asset deleted successfully "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "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., workflow version) "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "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 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 the dedicated PUT /api/assets/{id}/tags endpoint. 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 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) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "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 summary: Update asset metadata 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 "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 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 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 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 "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 summary: Add tags to asset tags: - file put: description: Adds and removes tags from an asset in a single operation operationId: updateAssetTags parameters: - description: Asset ID in: path name: id required: true schema: format: uuid type: string requestBody: content: application/json: schema: description: At least one of add or remove must contain items. Empty arrays are allowed when the other array has items. minProperties: 1 properties: add: description: Tags to add to the asset. Can be empty if remove has items. items: type: string type: array remove: description: Tags to remove from the asset. Can be empty if add has items. items: type: string type: array type: object required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/TagsModificationResponse' description: Tags updated successfully "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid request "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Asset not found "422": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Reserved tag validation error "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Update asset tags tags: - file /api/assets/download: post: description: | Initiates a background download job for large files from Huggingface or Civitai. If the file already exists in storage, the asset record is created immediately and returned (200 OK). If the file doesn't exist, a background task is created and the task ID is returned (202 Accepted). The frontend can track progress using GET /api/tasks/{task_id}. operationId: createAssetDownload requestBody: content: application/json: schema: properties: preview_id: description: Optional preview asset ID to associate with the downloaded asset example: 550e8400-e29b-41d4-a716-446655440000 format: uuid type: string source_url: description: URL of the file to download (must be from huggingface.co, civitai.com, or civitai.red) example: https://huggingface.co/runwayml/stable-diffusion-v1-5/resolve/main/v1-5-pruned.safetensors format: uri type: string tags: description: Optional tags for the asset (e.g., ["model", "checkpoint"]) items: type: string type: array user_metadata: additionalProperties: true description: Optional user-defined metadata to attach to the asset type: object required: - source_url type: object required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/AssetCreated' description: File already exists in storage - asset created/returned immediately "202": content: application/json: schema: $ref: '#/components/schemas/AssetDownloadResponse' description: Accepted - Download task created and processing in background "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid URL or unsupported source "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "422": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Validation errors "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Initiate background download for large files tags: - file /api/assets/export: post: description: | Initiates a background task to export a ZIP file from assets resolved by job IDs and/or selected by asset IDs. The frontend can track progress using GET /api/tasks/{task_id}. At least one of `job_ids` or `asset_ids` must be provided. operationId: createAssetExport requestBody: content: application/json: schema: properties: asset_ids: description: Asset IDs to include in the ZIP bundle. Additive to the assets associated with provided job IDs. example: - 833a1b5c-beab-436a-ae8e-f07e7cd7b2c4 items: type: string type: array job_asset_name_filters: additionalProperties: items: type: string minItems: 1 type: array description: | Optional per-job asset name filters. When provided for a job ID, only assets whose name matches one of the specified names are included. Job IDs present in `job_ids` but absent from this map include all their assets. example: 833a1b5c-beab-436a-ae8e-f07e7cd7b2c4: - ComfyUI_00001_.png - ComfyUI_00003_.png type: object job_ids: description: Job IDs to include *all associated assets* of the jobs in the ZIP bundle. example: - 833a1b5c-beab-436a-ae8e-f07e7cd7b2c4 items: type: string type: array naming_strategy: default: group_by_job_time description: | Strategy for naming files in the ZIP: - group_by_job_id: Group assets by job ID as a parent directory (e.g., "833a1b5c-beab-436a-ae8e-f07e7cd7b2c4/ComfyUI_00001_.png") - preserve: Use original asset names, skip duplicates (first one wins) - asset_id: Use the asset ID as the filename (e.g., "833a1b5c-beab-436a-ae8e-f07e7cd7b2c4.png") - group_by_job_time: Group by job creation timestamp (e.g., "2026-03-26T16-13-00/ComfyUI_00001_.png") enum: - group_by_job_id - preserve - asset_id - group_by_job_time type: string type: object required: true responses: "202": content: application/json: schema: $ref: '#/components/schemas/AssetDownloadResponse' description: Accepted - Export task created and processing in background "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid request "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Initiate background ZIP export for multiple assets tags: - file x-runtime: - cloud /api/assets/exports/{exportName}: get: description: | Returns a URL for downloading the export file. The export must have been created by the authenticated user. operationId: downloadExport parameters: - description: Export filename with extension (e.g., "021e55cd-9785-4ac7-ac39-f4010138e3bc.zip") in: path name: exportName required: true schema: pattern: ^[a-zA-Z0-9_-]+\.zip$ type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/ExportDownloadURLResponse' description: Signed URL for downloading the export "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid export name "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Export not found or not owned by user "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Get a URL for downloading an export file tags: - file x-runtime: - cloud /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: Hash of the existing asset. Supports Blake3 (blake3:) or SHA256 (sha256:) formats pattern: ^(blake3|sha256):[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. items: type: string 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: "201": content: application/json: schema: $ref: '#/components/schemas/AssetCreated' description: Asset reference created successfully "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 "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Source asset with given hash not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Create asset reference from existing hash tags: - file /api/assets/from-workflow: post: description: | Given a workflow in API format, returns the assets (inputs) and models referenced by the workflow. operationId: postAssetsFromWorkflow requestBody: content: application/json: schema: $ref: '#/components/schemas/WorkflowApiAssetsRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/WorkflowApiAssetsResponse' description: Success "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Get assets and models referenced in a workflow tags: - file x-runtime: - cloud /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": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": description: Asset not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Check if asset exists by hash tags: - file /api/assets/import: post: description: | Imports the specified published assets into the caller's asset library. New DB records reference the same storage objects; no file copying occurs. Assets the caller already owns (by hash) are deduplicated. The `id` field on each returned AssetInfo is the caller's newly created private asset ID, not the published_asset_id supplied in the request. operationId: importPublishedAssets requestBody: content: application/json: schema: $ref: '#/components/schemas/ImportPublishedAssetsRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/ImportPublishedAssetsResponse' description: Successfully imported assets "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Import published assets into the caller's library tags: - file /api/assets/prune: post: description: '[local-only] Starts a background job that removes asset entries whose underlying content no longer exists on disk. Local ComfyUI only; cloud assets live in GCS.' 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 x-runtime: - local /api/assets/remote-metadata: get: description: | Retrieves metadata for an asset from a remote download URL without downloading the entire file. Supports various sources including CivitAI and other model repositories. Uses HEAD requests or API calls to fetch metadata efficiently. This endpoint is for previewing metadata before downloading, not for getting metadata of existing assets. operationId: getRemoteAssetMetadata parameters: - description: Download URL to retrieve metadata from in: query name: url required: true schema: example: https://civitai.com/api/download/models/123456 format: uri type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/AssetMetadataResponse' description: Metadata retrieved successfully "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid URL or missing required parameter "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "422": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Failed to retrieve metadata from source "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Get asset metadata from remote URL tags: - file x-runtime: - cloud /api/assets/seed: post: description: '[local-only] Starts a background job that scans configured directories and registers assets not yet in the asset database. Local ComfyUI only.' 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 x-runtime: - local /api/assets/seed/cancel: post: description: '[local-only] Requests cancellation of the currently-running asset seed job. Local ComfyUI only.' operationId: cancelAssetSeed responses: "200": content: application/json: schema: properties: status: type: string type: object description: Scan cancelled summary: Cancel an in-progress asset scan x-runtime: - local /api/assets/seed/status: get: description: '[local-only] Returns progress/status of the most recent asset seed job. Local ComfyUI only.' 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 x-runtime: - local /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: - description: Filter assets that have ALL of these tags explode: false in: query name: include_tags schema: items: type: string type: array style: form - description: Exclude assets that have ANY of these tags explode: false in: query name: exclude_tags 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 "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Get tag histogram for filtered assets tags: - file /api/auth/session: delete: description: | Clears the session cookie and optionally revokes the session on the server. This logs the user out of their current session. operationId: deleteSession responses: "200": content: application/json: schema: $ref: '#/components/schemas/DeleteSessionResponse' description: Session deleted successfully headers: Set-Cookie: description: Session cookie cleared (Max-Age=-1) schema: type: string "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: [] summary: Delete session cookie (logout) tags: - auth post: description: | Creates a session cookie from the Firebase ID token in the Authorization header. Returns a Set-Cookie header with a secure, HttpOnly session cookie that expires in 2 hours. A new session cookie is created on every call. Authentication: Requires Authorization header with Bearer token or API key. Cookie authentication is not allowed for this endpoint. operationId: createSession responses: "200": content: application/json: schema: $ref: '#/components/schemas/CreateSessionResponse' description: Session created successfully headers: Set-Cookie: description: Session cookie with 2-hour expiration schema: type: string "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request - Invalid or old ID token "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized - Authentication required "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - ApiKeyAuth: [] - BearerAuth: [] summary: Create a session cookie tags: - auth /api/auth/token: post: description: | Exchanges a Firebase JWT for a workspace-scoped Cloud JWT. If workspace_id is omitted, returns a token for the user's personal workspace. operationId: exchangeToken requestBody: content: application/json: schema: $ref: '#/components/schemas/ExchangeTokenRequest' responses: "200": content: application/json: schema: $ref: '#/components/schemas/ExchangeTokenResponse' description: Token exchanged successfully "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid or expired Firebase JWT "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workspace not found or user not a member "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Exchange Firebase JWT for Cloud JWT tags: - auth /api/billing/balance: get: description: | Returns the current credit balance for the workspace from Metronome. This is a GET endpoint that may occasionally write (to update has_funds status). operationId: getBillingBalance responses: "200": content: application/json: schema: $ref: '#/components/schemas/BillingBalanceResponse' description: Credit balance "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Get credit balance tags: - billing /api/billing/events: get: description: | Returns paginated billing events for the workspace. Events include subscription changes, payments, and credit adjustments. operationId: getBillingEvents parameters: - description: Page number (1-indexed) in: query name: page schema: default: 1 minimum: 1 type: integer - description: Number of events per page in: query name: limit schema: default: 20 maximum: 100 minimum: 1 type: integer responses: "200": content: application/json: schema: $ref: '#/components/schemas/BillingEventsResponse' description: Paginated billing events "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Get billing events tags: - billing /api/billing/ops/{id}: get: description: | Returns the current status of a billing operation. All billing mutations (subscribe, cancel, topup, plan change) return a billing_op_id. Use this endpoint to poll for completion status. Status values: - pending: Operation is in progress - succeeded: Operation completed successfully - failed: Operation failed, see error_message for details operationId: getBillingOpStatus parameters: - description: The billing operation ID in: path name: id required: true schema: type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/BillingOpStatusResponse' description: Billing operation status "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Billing operation not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Get billing operation status tags: - billing /api/billing/payment-portal: post: description: | Returns a Stripe Billing Portal URL for managing payment methods. The user can add, update, or remove payment methods in the portal. operationId: getPaymentPortal requestBody: content: application/json: schema: $ref: '#/components/schemas/PaymentPortalRequest' responses: "200": content: application/json: schema: $ref: '#/components/schemas/PaymentPortalResponse' description: Success "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request (e.g., missing return_url) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Get payment portal URL tags: - billing /api/billing/plans: get: description: | Returns all subscription plans with pricing and availability for the workspace. Availability indicates whether the workspace can subscribe to each plan. operationId: getBillingPlans responses: "200": content: application/json: schema: $ref: '#/components/schemas/BillingPlansResponse' description: Available plans with pricing "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Get available subscription plans tags: - billing /api/billing/preview-subscribe: post: description: | Returns a preview of the subscription transition including: - Cost to charge today (for upgrades/new subscriptions) - Cost at next billing period - Credits granted today (prorated for upgrades) - Credits granted at next billing period This endpoint does not execute any billing operations. Use it to show the user what will happen before they confirm. operationId: previewSubscribe requestBody: content: application/json: schema: $ref: '#/components/schemas/PreviewSubscribeRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/PreviewSubscribeResponse' description: Subscription preview "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid request (e.g., invalid plan slug, seats below minimum) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Preview what will happen when subscribing to a plan tags: - billing /api/billing/status: get: description: | Returns the current billing status for the workspace. Requires workspace-scoped authentication. operationId: getBillingStatus responses: "200": content: application/json: schema: $ref: '#/components/schemas/BillingStatusResponse' description: Billing status "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workspace not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Get billing status tags: - billing /api/billing/subscribe: post: description: | Subscribes the workspace to the specified plan. Flow depends on payment method: **If workspace has payment method:** - Creates subscription immediately - Returns status="subscribed" with effective_at timestamp **If workspace needs payment method:** - Creates scheduled subscription (status=scheduled) - Returns status="needs_payment_method" with payment_method_url - After payment method is added via checkout, subscription is finalized For existing subscriptions, this performs a plan change (upgrade/downgrade). operationId: subscribe requestBody: content: application/json: schema: $ref: '#/components/schemas/SubscribeRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/SubscribeResponse' description: Subscription created or payment method needed "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid request (e.g., invalid plan slug, incompatible plan) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Subscribe to a billing plan tags: - billing /api/billing/subscription/cancel: post: description: | Cancels the workspace's active subscription at the end of the current billing period. The subscription remains active until the period ends, then transitions to ended. Returns the date when the subscription will end. operationId: cancelSubscription requestBody: content: application/json: schema: $ref: '#/components/schemas/CancelSubscriptionRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/CancelSubscriptionResponse' description: Subscription cancellation scheduled "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid request (e.g., no active subscription) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Cancel the current subscription tags: - billing /api/billing/subscription/resubscribe: post: description: | Reverses a scheduled subscription cancellation before the period ends. If the subscription has a cancel_at date set (scheduled to cancel at period end), this clears the cancellation and resumes the subscription. This operation: 1. Clears the cancel_at date on the subscription 2. Sets subscription status back to active 3. Clears the ending_before on the Metronome recurring commit Can only be called while the subscription is still in the cancellation grace period (before the period ends). After period end, you must subscribe again. operationId: resubscribe requestBody: content: application/json: schema: $ref: '#/components/schemas/ResubscribeRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/ResubscribeResponse' description: Subscription resumed successfully "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid request (e.g., no active subscription, not in cancellation grace period) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Resubscribe (undo cancel) before period ends tags: - billing /api/billing/topup: post: description: | Initiates a credit top-up for the workspace. Creates a payment-gated prepaid commit in Metronome that triggers an immediate Stripe charge. Credits are held until payment completes. Requires the workspace to have a valid payment method on file. If no payment method exists, returns an error directing the user to add one via the payment portal. The response includes a billing_op_id that can be used to poll for status via GET /api/billing/ops/{id}. operationId: createTopup requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateTopupRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/CreateTopupResponse' description: Top-up initiated successfully "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request (invalid amount, no payment method) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Create a credit top-up tags: - billing /api/embeddings: get: description: '[local-only] Returns the list of text-encoder embeddings available on disk. Local ComfyUI only; the cloud runtime does not serve this.' operationId: getEmbeddings responses: "200": content: application/json: schema: items: type: string type: array description: Embedding names summary: List available embedding names x-runtime: - local /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. operationId: getModelFolders responses: "200": content: application/json: schema: items: $ref: '#/components/schemas/ModelFolder' type: array description: Success - List of model folders "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: [] 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. 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 "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: [] 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`). 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 security: [] 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: max_upload_size: description: Maximum upload size in bytes type: integer supports_preview_metadata: description: Whether the server supports preview metadata 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 security: - ApiKeyAuth: [] - BearerAuth: [] - CookieAuth: [] - {} 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 "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error 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 "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: File not found or not a mask file summary: Get related mask layer files tags: - file /api/free: post: description: '[local-only] Frees GPU memory by unloading models and/or freeing the resident model cache. Local ComfyUI only; cloud manages GPU lifecycle per-pod.' 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 x-runtime: - local /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 "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized - Authentication required "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error 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 including complete prompt information. 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized - Authentication required "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 summary: Get history for specific prompt tags: - workflow /api/hub/assets/upload-url: post: description: | Returns a presigned R2 upload URL and a signed token. The token is signed with the authenticated caller's user ID; no existing hub profile is required. The frontend uploads the file directly to R2 using the presigned URL, then passes the token in the create profile, update profile, or publish request. operationId: createHubAssetUploadUrl requestBody: content: application/json: schema: $ref: '#/components/schemas/HubAssetUploadUrlRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/HubAssetUploadUrlResponse' description: Presigned upload URL and token "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request (e.g. unsupported content type) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Get a presigned upload URL for hub assets tags: - hub /api/hub/labels: get: description: Returns hub labels (tags, models, custom nodes) that can be used when publishing workflows. Filter by type to get a specific category. operationId: listHubLabels parameters: - description: Filter by label type. Omit to return all labels. in: query name: type schema: enum: - tag - model - custom_node type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/HubLabelListResponse' description: List of labels "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request (e.g. invalid type parameter) "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: List available hub labels tags: - hub /api/hub/profiles: post: description: Creates a hub profile for the specified workspace. Username is immutable after creation. operationId: createHubProfile requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateHubProfileRequest' required: true responses: "201": content: application/json: schema: $ref: '#/components/schemas/HubProfile' description: Hub profile created "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request (e.g. invalid username) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found "409": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Username already taken or profile already exists "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Create hub profile tags: - hub /api/hub/profiles/{username}: get: description: Returns the public hub profile for the given username. operationId: getHubProfileByUsername parameters: - description: The hub profile username. in: path name: username required: true schema: type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/HubProfile' description: Hub profile "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Profile not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: [] summary: Get a public hub profile by username tags: - hub patch: description: Updates the hub profile identified by username. The authenticated user must belong to the workspace that owns the profile. Username cannot be changed. operationId: updateHubProfile parameters: - description: The hub profile username to update. in: path name: username required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateHubProfileRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/HubProfile' description: Hub profile updated "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request (e.g. missing body, invalid avatar token) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: No hub profile exists with this username "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Update hub profile tags: - hub /api/hub/profiles/check: get: description: | Checks whether a username is available for the caller's workspace. If the username is taken by another workspace, returns up to 5 available suggestions. If the username format is invalid, returns a validation error. operationId: checkHubUsername parameters: - in: query name: username required: true schema: type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/HubUsernameCheckResponse' description: Username availability result "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Check username availability tags: - hub /api/hub/profiles/me: get: description: Returns the hub profile for the authenticated user's workspace. operationId: getMyHubProfile responses: "200": content: application/json: schema: $ref: '#/components/schemas/HubProfile' description: Hub profile "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: No hub profile exists "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Get current user's hub profile tags: - hub /api/hub/workflows: get: description: Returns paginated hub workflows with optional search and filtering. operationId: listHubWorkflows parameters: - in: query name: cursor schema: type: string - in: query name: limit schema: default: 20 maximum: 100 minimum: 1 type: integer - description: Search by workflow name in: query name: search schema: type: string - description: Filter by tag in: query name: tag schema: type: string - description: Filter by profile username in: query name: username schema: type: string - description: When true, returns full HubWorkflowDetail objects in the workflows array instead of summaries. Requires limit <= 20. in: query name: detail schema: default: false type: boolean - description: Filter by status (e.g. ?status=pending,approved). Defaults to approved if omitted. explode: false in: query name: status schema: items: $ref: '#/components/schemas/HubWorkflowStatus' type: array style: form responses: "200": content: application/json: schema: $ref: '#/components/schemas/HubWorkflowListResponse' description: Paginated list of hub workflows "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request (e.g. malformed pagination cursor) "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Profile not found (when filtering by username) "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: [] summary: Browse hub workflows tags: - hub post: description: Publishes a workflow to the hub with metadata, thumbnail, and sample images. operationId: publishHubWorkflow requestBody: content: application/json: schema: $ref: '#/components/schemas/PublishHubWorkflowRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/HubWorkflowDetail' description: Workflow published to hub "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workflow or profile not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Publish a workflow to the hub tags: - hub /api/hub/workflows/{share_id}: delete: description: Removes a workflow from the hub listing. operationId: deleteHubWorkflow parameters: - description: The share ID of the hub workflow to unpublish. in: path name: share_id required: true schema: type: string responses: "204": description: Successfully unpublished "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "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 summary: Unpublish a workflow from the hub tags: - hub get: description: Returns full details of a hub workflow including workflow JSON and assets. operationId: getHubWorkflow parameters: - description: The share ID of the hub workflow. in: path name: share_id required: true schema: type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/HubWorkflowDetail' description: Hub workflow detail "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workflow 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: [] summary: Get hub workflow detail tags: - hub /api/hub/workflows/index: get: description: Returns all listed hub workflows in the same format as workflow_templates index.json. No pagination — returns the full list. operationId: listHubWorkflowIndex parameters: - description: Filter by status (e.g. ?status=pending,approved). Defaults to approved if omitted. explode: false in: query name: status schema: items: $ref: '#/components/schemas/HubWorkflowStatus' type: array style: form responses: "200": content: application/json: schema: items: $ref: '#/components/schemas/HubWorkflowTemplateEntry' type: array description: List of hub workflow template entries "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: [] summary: List hub workflows in template index format tags: - hub /api/i18n: get: description: '[local-only] Returns translation file URLs contributed by custom nodes, keyed by locale. Local ComfyUI only; cloud serves translations from GCS.' 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 x-runtime: - local /api/interrupt: post: description: | Cancel all currently RUNNING jobs for the authenticated user. This will interrupt any job that is currently in 'in_progress' status. Note: This endpoint only affects running jobs. To cancel pending jobs, use /api/queue. operationId: interruptJob responses: "200": description: Success - Job interrupted or no running job found "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized - Authentication required "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Interrupt currently running jobs tags: - queue /api/invites/{token}/accept: post: description: Accepts an invite and adds the user as a member of the workspace. operationId: acceptWorkspaceInvite parameters: - description: Invite token in: path name: token required: true schema: type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/AcceptInviteResponse' description: Invite accepted, user is now a member "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Email does not match invite "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invite not found or expired "409": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Already a member of this workspace "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Accept a workspace invite tags: - workspaces /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 "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 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. 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: Pagination offset (0-based) 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized - Authentication required "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: List jobs with pagination and filtering tags: - workflow /api/jobs/{job_id}: get: description: | Retrieve complete details for a specific job including workflow and outputs. Used for detail views, workflow re-execution, and debugging. operationId: getJobDetail 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/JobDetailResponse' description: Success - Job details retrieved "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 summary: Get full job details 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. 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/BindingErrorResponse' 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 "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 summary: Cancel a job 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 operationId: getNodeInfo responses: "200": content: application/json: schema: additionalProperties: $ref: '#/components/schemas/NodeInfo' type: object description: Success 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error 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 "402": content: application/json: schema: $ref: '#/components/schemas/PromptErrorResponse' description: Payment required - Insufficient credits "429": content: application/json: schema: $ref: '#/components/schemas/PromptErrorResponse' description: Payment required - User has not paid "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 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 "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid request parameters summary: Get queue information tags: - queue post: description: | Cancel specific PENDING jobs by ID or clear all pending jobs in the queue. Note: This endpoint only affects pending jobs. To cancel running jobs, use /api/interrupt. 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 "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error summary: Manage queue operations tags: - queue /api/secrets: get: description: Returns all secrets for the authenticated user in the current workspace. Does not return plaintext secret values. operationId: listSecrets responses: "200": content: application/json: schema: $ref: '#/components/schemas/SecretListResponse' description: Success "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error "503": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Service unavailable - feature is disabled summary: List user secrets tags: - secrets post: description: Store an encrypted secret (e.g., HuggingFace or Civitai API key) for the authenticated user in the current workspace. operationId: createSecret requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateSecretRequest' required: true responses: "201": content: application/json: schema: $ref: '#/components/schemas/SecretResponse' description: Secret created successfully "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid request "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "409": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Conflict - secret with this name or provider already exists "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 "503": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Service unavailable - secrets feature disabled summary: Create a new secret tags: - secrets /api/secrets/{id}: delete: description: Remove a secret and its encrypted value from storage. operationId: deleteSecret parameters: - description: The UUID of the secret in: path name: id required: true schema: format: uuid type: string responses: "204": description: Secret deleted successfully "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Forbidden - user does not own this secret "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Secret not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error "503": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Service unavailable - secrets feature disabled summary: Delete secret tags: - secrets get: description: Returns metadata for a specific secret. Does not return the plaintext secret value. operationId: getSecret parameters: - description: The UUID of the secret in: path name: id required: true schema: format: uuid type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/SecretResponse' description: Success "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Forbidden - user does not own this secret "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Secret not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error "503": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Service unavailable - secrets feature disabled summary: Get secret metadata tags: - secrets patch: description: Update an existing secret's name and/or value. Both fields are optional; only provided fields will be updated. operationId: updateSecret parameters: - description: The UUID of the secret in: path name: id required: true schema: format: uuid type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateSecretRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/SecretResponse' description: Secret updated 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": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Forbidden - user does not own this secret "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Secret not found "409": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Conflict - a secret with this name already exists "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error "503": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Service unavailable - secrets feature disabled summary: Update secret tags: - secrets /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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized 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 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Setting not found 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 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 "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized - Authentication required "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 summary: List background tasks tags: - task /api/tasks/{task_id}: 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized - Authentication required "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 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. 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 "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error 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. 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 "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized 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: text/plain: schema: type: string description: Bad request (e.g., invalid filename). "401": content: text/plain: schema: type: string description: Unauthorized. "404": content: text/plain: schema: type: string description: File not found or invalid path. "500": content: text/plain: schema: type: string description: General error 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). "401": content: text/plain: schema: type: string description: Unauthorized. "404": content: text/plain: schema: type: string description: File not found. "500": content: text/plain: schema: type: string description: Internal server error. 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: text/plain: schema: type: string description: Bad request (e.g., invalid filename). "401": content: text/plain: schema: type: string description: Unauthorized. "404": content: text/plain: schema: type: string description: File not found or invalid path. "500": content: text/plain: schema: type: string description: General error 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: text/plain: schema: type: string description: Missing or invalid 'file' parameter. "401": content: text/plain: schema: type: string description: Unauthorized. "403": content: 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 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: text/plain: schema: type: string description: Missing or invalid parameters. "401": content: text/plain: schema: type: string description: Unauthorized. "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 summary: Move or rename a user data file tags: - user /api/userdata/{file}/publish: 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) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "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 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 "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 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized summary: ComfyUI userdata storage info tags: - user /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. operationId: getVhsQueryVideo parameters: - description: Name of the video file to query in: query name: filename required: true schema: type: string 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/BindingErrorResponse' description: | Missing required query parameter. Produced by the oapi-codegen wrapper via echo.NewHTTPError, so the body shape matches Echo's default HTTPError serialization rather than ErrorResponse. "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized security: - ApiKeyAuth: [] - BearerAuth: [] - CookieAuth: [] 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. Cookie auth is allowed on this endpoint because it's used by img/video tags in browsers. 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 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 "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: [] 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "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 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "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 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 "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 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "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 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 "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 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 "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 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 "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 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 "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "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 summary: Get a published workflow by share ID tags: - workflows /api/workspace/api-keys: get: description: | Returns API keys for the workspace. Owners see all keys; members see only their own. The workspace is determined from the authenticated user's token. operationId: listWorkspaceAPIKeys responses: "200": content: application/json: schema: $ref: '#/components/schemas/ListWorkspaceAPIKeysResponse' description: List of API keys "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Forbidden "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: List workspace API keys tags: - workspaces post: description: | Creates a new workspace-scoped API key. The plaintext key is returned once and cannot be retrieved again. Any workspace member can create keys. The workspace is determined from the authenticated user's token. operationId: createWorkspaceAPIKey requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateWorkspaceAPIKeyRequest' required: true responses: "201": content: application/json: schema: $ref: '#/components/schemas/CreateWorkspaceAPIKeyResponse' description: API key created (plaintext returned once) "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not a workspace member "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workspace not found "422": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Validation error "429": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Key limit reached "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Create a workspace API key tags: - workspaces /api/workspace/api-keys/{id}: delete: description: | Revokes a workspace API key by ID. Owners can revoke any key; members can only revoke their own keys. operationId: revokeWorkspaceAPIKey parameters: - description: API key ID to revoke in: path name: id required: true schema: format: uuid type: string responses: "204": description: API key revoked "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not authorized to revoke this key "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: API key not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Revoke a workspace API key tags: - workspaces /api/workspace/invites: get: description: | Returns all pending invites for a workspace. Requires owner role. The workspace is determined from the authenticated user's token. operationId: listWorkspaceInvites responses: "200": content: application/json: schema: $ref: '#/components/schemas/ListInvitesResponse' description: List of pending invites "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Owner role required "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: List pending invites tags: - workspaces post: description: | Creates an invite for a new member. Requires owner role. The workspace is determined from the authenticated user's token. operationId: createWorkspaceInvite requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateInviteRequest' required: true responses: "201": content: application/json: schema: $ref: '#/components/schemas/PendingInvite' description: Invite created "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Owner role required or personal workspace (invites not allowed) "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workspace not found "409": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invite already exists "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: - BearerAuth: [] summary: Create a workspace invite tags: - workspaces /api/workspace/invites/{inviteId}: delete: description: | Deletes a pending invite. Requires owner role. The workspace is determined from the authenticated user's token. operationId: revokeWorkspaceInvite parameters: - description: Invite ID to revoke in: path name: inviteId required: true schema: type: string responses: "204": description: Invite revoked "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Owner role required "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workspace or invite not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Revoke a workspace invite tags: - workspaces /api/workspace/leave: post: description: | Removes the current user from the workspace. Cannot leave as the only owner. The workspace is determined from the authenticated user's token. operationId: leaveWorkspace responses: "204": description: Successfully left workspace "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Cannot leave as the only owner or cannot leave personal workspace "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workspace not found or not a member "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Leave a workspace tags: - workspaces /api/workspace/members: get: description: | Returns paginated list of workspace members. Requires membership. The workspace is determined from the authenticated user's token. operationId: listWorkspaceMembers parameters: - description: Pagination offset (0-based) in: query name: offset schema: default: 0 minimum: 0 type: integer - description: Maximum number of members to return in: query name: limit schema: default: 20 maximum: 100 minimum: 1 type: integer responses: "200": content: application/json: schema: $ref: '#/components/schemas/ListMembersResponse' description: List of members "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not a member of this workspace "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workspace 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: - BearerAuth: [] summary: List workspace members tags: - workspaces /api/workspace/members/{user_id}/api-keys: delete: description: | Revokes all active API keys for a specific member in the workspace. Only workspace owners can perform this action. Useful for offboarding. The workspace is determined from the authenticated user's token. operationId: bulkRevokeWorkspaceMemberAPIKeys parameters: - description: Firebase UID of the member whose keys to revoke (must be non-empty) in: path name: user_id required: true schema: minLength: 1 type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/BulkRevokeAPIKeysResponse' description: Keys revoked successfully "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Not authorized (must be workspace owner) "422": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Validation error (e.g. empty user_id) "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Bulk revoke a member's API keys tags: - workspaces /api/workspace/members/{userId}: delete: description: | Removes a member from the workspace. Requires owner role. The workspace is determined from the authenticated user's token. operationId: removeWorkspaceMember parameters: - description: User ID to remove in: path name: userId required: true schema: type: string responses: "204": description: Member removed "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Owner role required or cannot remove yourself "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workspace or member not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Remove a member from workspace tags: - workspaces /api/workspaces: get: description: Returns all workspaces the authenticated user is a member of operationId: listWorkspaces responses: "200": content: application/json: schema: $ref: '#/components/schemas/ListWorkspacesResponse' description: List of workspaces "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Feature not enabled for user "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: List user's workspaces tags: - workspaces post: description: Creates a new team workspace with the authenticated user as owner operationId: createWorkspace requestBody: content: application/json: schema: $ref: '#/components/schemas/CreateWorkspaceRequest' required: true responses: "201": content: application/json: schema: $ref: '#/components/schemas/Workspace' description: Workspace created "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Feature not enabled for user "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: - BearerAuth: [] summary: Create a team workspace tags: - workspaces /api/workspaces/{id}: delete: description: | Soft deletes a workspace. Requires owner role. Cannot delete personal workspaces. operationId: deleteWorkspace parameters: - description: Workspace ID (w-{uuid} format) in: path name: id required: true schema: type: string responses: "204": description: Workspace deleted "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Owner role required or cannot delete personal workspace "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workspace not found "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Delete workspace tags: - workspaces get: description: Returns details of a specific workspace operationId: getWorkspace parameters: - description: Workspace ID (w-{uuid} format) in: path name: id required: true schema: type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/Workspace' description: Workspace details "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workspace not found or user not a member "500": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Internal server error security: - BearerAuth: [] summary: Get workspace details tags: - workspaces patch: description: Updates workspace properties. Requires owner role. operationId: updateWorkspace parameters: - description: Workspace ID (w-{uuid} format) in: path name: id required: true schema: type: string requestBody: content: application/json: schema: $ref: '#/components/schemas/UpdateWorkspaceRequest' required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/Workspace' description: Workspace updated "401": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Unauthorized "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Owner role required "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Workspace 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: - BearerAuth: [] summary: Update workspace tags: - workspaces /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: '[local-only] Returns the filesystem paths ComfyUI loads models and assets from, keyed by folder type. Local ComfyUI only; cloud pods have ephemeral storage.' 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 x-runtime: - local /internal/logs: get: description: '[local-only] Returns ComfyUI log entries from the in-memory log buffer. Local ComfyUI only; cloud logs flow to Datadog.' operationId: getInternalLogs responses: "200": content: text/plain: schema: type: string description: Log text summary: Get server logs as text x-runtime: - local /internal/logs/raw: get: description: '[local-only] Returns the raw ComfyUI log buffer plus size metadata. Local ComfyUI only; cloud logs flow to Datadog.' 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 x-runtime: - local /internal/logs/subscribe: patch: description: '[local-only] Subscribes or unsubscribes the current client from live log streaming over the WebSocket. Local ComfyUI only.' 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 x-runtime: - local /oauth/authorize: get: description: | Two modes: - **Initial entry** (OAuth params present): validates client/redirect/resource/scopes, persists a server-side `oauth_authorization_requests` row, and either redirects (no session / unverified email) to the configured frontend login URL carrying only the opaque `oauth_request_id`, or returns the JSON consent challenge for the frontend to render. - **Resume** (`oauth_request_id` present): loads the server-side row, fails closed if expired/consumed/unknown, returns the JSON consent challenge. Browser-replayed OAuth params are intentionally ignored. The frontend (BE-638) renders the consent UI from the JSON payload and POSTs the user's decision back to this endpoint. operationId: getOAuthAuthorize parameters: - in: query name: response_type schema: type: string - in: query name: client_id schema: type: string - in: query name: redirect_uri schema: type: string - in: query name: scope schema: type: string - description: | RFC 6749 §10.12 marks `state` as RECOMMENDED. Our hardening makes it REQUIRED on the initial-entry path (omitted only on the resume path where `oauth_request_id` is supplied instead). This parameter is `required: false` at the spec level only because the operation is dual-mode (initial entry vs. resume); the runtime parser (services/ingest/server/implementation/oauth/protocol/request.go) rejects empty `state` on the initial-entry path with a stable `invalid_request` 400. in: query name: state schema: type: string - in: query name: code_challenge schema: type: string - in: query name: code_challenge_method schema: type: string - in: query name: resource schema: type: string - in: query name: oauth_request_id schema: type: string responses: "200": content: application/json: schema: $ref: '#/components/schemas/OAuthConsentChallenge' description: | Consent challenge payload (cookie present, email verified). Frontend renders the consent UI from this payload and POSTs back to /oauth/authorize. "302": description: Redirect to login (no session / unverified email) or to registered redirect_uri (pre-validated client error) headers: Location: schema: type: string "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Invalid authorize request (pre-redirect failure — unknown client, redirect mismatch, malformed params) "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: OAuth disabled security: [] summary: Begin or resume an OAuth 2.1 authorization request tags: - oauth post: description: | JSON-only consent submission. The handler verifies the per-row CSRF token, atomically marks the authorization request consumed (single-use covers both allow and deny paths), then returns the redirect URL the browser must navigate to. The URL contains either `code` + original `state` for allow, or the RFC 6749 §5.2 error and `state` for deny. Workspace membership is re-checked at submission time. Consent is persisted keyed by `(comfy_user_id, client_id, resource_id, workspace_id)`; broadening the previously approved scope set requires a fresh consent flow. operationId: postOAuthAuthorize requestBody: content: application/json: schema: properties: csrf_token: type: string decision: enum: - allow - deny type: string oauth_request_id: format: uuid type: string workspace_id: type: string required: - oauth_request_id - csrf_token - decision - workspace_id type: object required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/OAuthAuthorizeRedirectResponse' description: Redirect URL for the frontend to navigate to (allow → with code+state; deny → with error+state) "400": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Bad request (CSRF mismatch, expired/consumed request, inaccessible workspace) "403": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: Scope broadening on consent re-grant — fresh consent flow required "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: OAuth disabled security: [] summary: Submit OAuth consent decision tags: - oauth /oauth/register: post: description: | Public, unauthenticated, insert-only RFC 7591 §3.1 client registration. Used by MCP-spec-compliant clients (Claude Desktop, Claude Code, Cursor, Windsurf) to self-register a public OAuth client without ops involvement. Policy: - Public clients only — `token_endpoint_auth_method` is forced to `none`. Confidential-client registration is out of scope this phase. - Server-owned `resource_grants`. Caller-supplied `scope` or `resource_grants` is rejected as `invalid_client_metadata` (would be a privilege-escalation surface). Dynamic clients receive the same scopes the active MCP resource publishes. - Application-type-aware redirect URI policy. `application_type=native` accepts loopback (`127.0.0.1`, `::1`, `localhost`) and reverse-DNS-shaped custom schemes; `application_type=web` accepts HTTPS to hosts in `OAUTH_DCR_HTTPS_HOSTS` only. `application_type` is OPTIONAL on the request — omit it to default to `native` (the MCP SDK omits it); a present value must be `native` or `web`, and any other value rejects with `invalid_client_metadata`. - Anti-impersonation: reserved client names (Claude/Cursor/etc.) are rejected from third parties via NFKC-folded compare. - Generated `client_id` carries the `comfy-dyn-` prefix to distinguish dynamic from seeded clients in audit logs. - Cache-Control: `no-store` on every 201 and 400 response (the response carries fresh credentials and rejection reasons). operationId: postOAuthRegister requestBody: content: application/json: schema: $ref: '#/components/schemas/OAuthRegisterRequest' required: true responses: "201": content: application/json: schema: $ref: '#/components/schemas/OAuthRegisterResponse' description: Registered. Body echoes the metadata RFC 7591 §3.2.1 requires. headers: Cache-Control: description: Always "no-store" per RFC 6749 §5.1 instinct (response carries fresh client_id) schema: type: string Pragma: description: Always "no-cache" schema: type: string "400": content: application/json: schema: $ref: '#/components/schemas/OAuthRegisterBadRequestResponse' description: | Bad request. Two shapes possible: `OAuthRegisterError` (RFC 7591 §3.2.2, emitted by the handler for invalid client metadata, missing application_type, reserved client_name, etc.) OR `BindingErrorResponse` (emitted by the strict-server binding layer when the request body fails OpenAPI-schema validation — malformed JSON, missing required fields, `additionalProperties: false` violations). headers: Cache-Control: description: Always "no-store" schema: type: string Pragma: description: Always "no-cache" schema: type: string "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: OAuth disabled "503": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: No active MCP resource is configured — DCR cannot mint a usable client until ops seeds an active oauth_resources row. security: [] summary: Dynamic Client Registration (RFC 7591) tags: - oauth /oauth/token: post: description: | OAuth 2.1 token endpoint (RFC 6749 §3.2). Public clients only — `client_secret` is rejected. Two grant types are supported: - `authorization_code` — exchanges the code minted by `/oauth/authorize` (with PKCE verifier) for an access token + first refresh token. Single-use; reuse fails closed. - `refresh_token` — rotates the refresh token. Old token immediately invalid; presenting an already-rotated token revokes the entire token family and emits a security metric. Both grant types re-validate canonical user state, current workspace membership, and the resource's `active` flag at every mint. A code or refresh token bound to a deactivated resource fails closed. Errors follow RFC 6749 §5.2. Logs never contain raw codes, refresh tokens, or minted JWTs. Per RFC 6749 §5.1, every 200 and 400 response carries `Cache-Control: no-store` and `Pragma: no-cache` so intermediaries cannot cache token-bearing or state-change-reason responses. operationId: postOAuthToken requestBody: content: application/x-www-form-urlencoded: schema: properties: client_id: type: string client_secret: type: string code: type: string code_verifier: type: string grant_type: enum: - authorization_code - refresh_token type: string redirect_uri: type: string refresh_token: type: string scope: type: string required: - grant_type - client_id type: object required: true responses: "200": content: application/json: schema: $ref: '#/components/schemas/OAuthTokenResponse' description: New token pair headers: Cache-Control: description: Always "no-store" per RFC 6749 §5.1 schema: type: string Pragma: description: Always "no-cache" per RFC 6749 §5.1 schema: type: string "400": content: application/json: schema: $ref: '#/components/schemas/OAuthTokenError' description: RFC 6749 §5.2 error headers: Cache-Control: description: Always "no-store" per RFC 6749 §5.1 schema: type: string Pragma: description: Always "no-cache" per RFC 6749 §5.1 schema: type: string "404": content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' description: OAuth disabled security: [] summary: Exchange authorization code or refresh token for a resource-bound Cloud JWT tags: - oauth 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 secret management (API keys, tokens) name: secrets - description: User settings management name: settings - description: User feedback management name: feedback - description: System operations and monitoring name: system - description: Administrative operations name: admin - description: Authentication and session management name: auth - description: User information and management name: user - description: Background task management name: task - description: Workspace management name: workspaces - description: ComfyHub - workflow publishing and profile management name: hub - 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 - description: Workflow template assets proxied from versioned GCS storage name: templates - description: OAuth 2.1 authorization-server endpoints for public PKCE clients name: oauth - description: | Routes served by raw Echo handlers that bypass the generated ServerInterface. Documented here purely as a URL inventory for drift detection (BE-123); excluded from Go codegen. See the comment above this tag declaration for per-route migration status. name: runtime-only - description: | Routes served ONLY by local ComfyUI (x-runtime: [local]); the cloud runtime does not route them — single-user / local-filesystem / dev-mode concerns with no cloud analogue. Documented here so this spec is the complete cross-runtime contract: the cloud→core projection (BE-1157) includes them and core stays a subset of this spec (BE-752 / BE-1155). Excluded from Go codegen and exempt from the route-drift "documented ⟹ registered in server.go" check — they are contract documentation, not cloud routes. Distinct from `runtime-only` (which cloud DOES serve via raw Echo and must register). name: local-only