ViewComfy API Rules — Cursor Rules | Neura Market
    Neura MarketNeura Market/Cursor
    ChatGPTChatGPTClaudeClaudeGeminiGeminiCursorCursorGrokGrokPerplexityPerplexityDeepSeekDeepSeek
    CoPilotCoPilotStable DiffusionStable DiffusionMidjourneyMidjourney
    View All Directories
    OverviewRulesPromptsMCPsAgentsBlogVideosGuidesCoursesCommunityExtensionsTrendingGenerate
    CursorRulesViewComfy API Rules
    Back to Rules
    Backend

    ViewComfy API Rules

    April 15, 2026
    0 copies 0 downloads

    The ViewComfy API is a serverless API built using the FastAPI framework that can run custom ComfyUI workflows. The Python version makes requests using the httpx library,

    Rule Content
    You are an expert in Python, FastAPI integrations and web app development. You are tasked with helping integrate the ViewComfy API into web applications using Python.
    
    The ViewComfy API is a serverless API built using the FastAPI framework that can run custom ComfyUI workflows. The Python version makes requests using the httpx library,
    
    When implementing the API, remember that the first time you call it, you might experience a cold start. Moreover, generation times can vary between workflows; some might be less than 2 seconds, while some might take several minutes.
    
    When calling the API, the params object can't be empty. If nothing else is specified, change the seed value.
    
    The data comes back from the API with the following format: { "prompt_id": "string", # Unique identifier for the prompt "status": "string", # Current execution status "completed": bool, # Whether execution is complete "execution_time_seconds": float, # Time taken to execute "prompt": dict, # Original prompt configuration "outputs": [ # List of output files (optional) { "filename": "string", # Name of the output file "content_type": "string", # MIME type of the file "data": "string", # Base64 encoded file content "size": int # File size in bytes }, # ... potentially multiple output files ] }
    
    ViewComfy documentation:
    
    ================================================
    FILE: other_resources/guide_to_setting_up_and_using_ViewComfy_API.md
    ================================================
    Deploying your workflow
    The first thing you will need to do is to deploy your ComfyUI workflow on your ViewComfy dashboard using the workflow_api.json file.
    
    Calling the workflow with the API
    The ViewComfy API is a REST API that can be called with a standard POST request but also supports streaming responses via Server-Sent Events. This second option allows for real-time tracking of the ComfyUI logs.
    
    Getting your API keys
    In order to use your API endpoint, you will first need to create your API keys from the ViewComfy dashboard.
    
    2. Extracting your workflow parameters
    
    Before setting up the request is to identify the parameters in your workflow. This is done by using ViewComfy_API/Python/workflow_parameters_maker.py from the example API code to flatten your workflow_api.json.
    
    
    The flattened json file should look like this:
    
    {
    "_3-node-class_type-info": "KSampler",
    "3-inputs-cfg": 6,
    
    …  
    
    "_6-node-class_type-info": "CLIP Text Encode (Positive Prompt)",  
    "6-inputs-clip": [  
        "38",  
        0  
    ],  
    "6-inputs-text": "A woman raising her head with hair blowing in the wind",  
    
    …  
    
    "_52-node-class_type-info": "Load Image",  
    "52-inputs-image": "<path_to_my_image>",  
    
    …  
    }
    
    
    This dictionary contains all the parameters in your workflow. The key for each parameter contains the node id from your workflow_api.json file, whether it is an input, and the parameter’s input name. Keys that start with “_” are just there to give you context on the node corresponding to id, they are not parameters.
    
    In this example, the first key-value pair shows that node 3 is the KSampler and that “3-inputs-cfg” sets its corresponding cfg value.
    
    **3. Updating the script with your parameter**
    
    First thing to do is to copy the ViewComfy endpoint from your dashboard and set it to view_comfy_api_url. You should also get the “Client ID” and “Client Secret” you made earlier, and set the client_id and client_secret values:
    
    view_comfy_api_url = "<Your_ViewComfy_endpoint>"
    client_id = "<Your_ViewComfy_client_id>"
    client_secret = "<Your_ViewComfy_client_secret>"
    
    
    You can then set the parameters using the keys from the json file you created in the previous step. In this example, we will change the prompt and the input image:
    
    params = {}
    params["6-inputs-text"] = "A flamingo dancing on top of a server in a pink universe, masterpiece, best quality, very aesthetic"
    params["52-inputs-image"] = open("/home/gbieler/GitHub/API_tests/input_img.png", "rb")
    
    
    **4. Calling the API**
    
    Once you are done adding your parameters to ViewComfy_API/Python/main.py, you can call the API by running:
    
    python main.py
    
    
    This will send your parameters to ViewComfy_API/Python/api.py where all the functions to call the API and handle the outputs are stored.
    
    By default the script runs the “infer_with_logs” function which returns the generation logs from ComfyUI via a streaming response. If you would rather call the API via a standard POST request, you can use “infer” instead.
    
    The result object returned by the API will contain the workflow outputs as well as the generation details.
    
    Your outputs will automatically be saved in your working directory.
    
    ================================================
    FILE: ViewComfy_API/README.MD
    ================================================
    # ViewComfy API Example
    
    ## API
    
    All the functions to call the API and handle the responses are in the api file (api.py). The main file (main.py) takes in the parameters that are specific from your workflow and in most cases will be the only file you need to edit.
    
    #### The API file has two endpoints:
    
    - infer: classic request-response endpoint where you wait for your request to finish before getting results back. 
    
    - infer_with_logs: receives real-time updates with the ComfyUI logs (eg. progress bar). To make use of this endpoint, you need to pass a function that will be called each time a log message is received.
    
    The endpoints can also take a workflow_api.json as a parameter. This is useful if you want to run a different workflow than the one you used when deploying.
    
    ### Get your API parameters
    
    To extract all the parameters from your workflow_api.json, you can run the workflow_api_parameter_creator function. This will create a dictionary with all of the parameters inside the workflow.
    
    ```python
    
    python workflow_parameters_maker.py --workflow_api_path "<Path to your workflow_api.json file>"
    
    Running the example
    Install the dependencies:
    
    
    pip install -r requirements.txt
    
    Add your endpoint and set your API keys:
    
    Change the view_comfy_api_url value inside main.py to the ViewComfy endpoint from your ViewComfy Dashboard. Do the same with the "client_id" and "client_secret" values using your API keys (you can also get them from your dashboard). If you want, you can change the parameters of the workflow inside main.py at the same time.
    
    Call the API:
    
    
    python main.py
    
    Using the API with a different workflow
    You can overwrite the default workflow_api.json when sending a request. Be careful if you need to install new node packs to run the new workflow. Having too many custom node packages can create some issues between the Python packages. This can increase ComfyUI start up time and in some cases break the ComfyUI installation.
    
    To use an updated workflow (that works with your deployment) with the API, you can send the new workflow_api.json as a parameter by changing the override_workflow_api_path value. For example, using python:
    
    override_workflow_api_path = "<path_to_your_new_workflow_api_file>"
    ================================================ FILE: ViewComfy_API/example_workflow/workflow_api(example).json
    { "3": { "inputs": { "seed": 268261030599666, "steps": 20, "cfg": 6, "sampler_name": "uni_pc", "scheduler": "simple", "denoise": 1, "model": [ "56", 0 ], "positive": [ "50", 0 ], "negative": [ "50", 1 ], "latent_image": [ "50", 2 ] }, "class_type": "KSampler", "_meta": { "title": "KSampler" } }, "6": { "inputs": { "text": "A flamingo dancing on top of a server in a pink universe, masterpiece, best quality, very aesthetic", "clip": [ "38", 0 ] }, "class_type": "CLIPTextEncode", "_meta": { "title": "CLIP Text Encode (Positive Prompt)" } }, "7": { "inputs": { "text": "Overexposure, static, blurred details, subtitles, paintings, pictures, still, overall gray, worst quality, low quality, JPEG compression residue, ugly, mutilated, redundant fingers, poorly painted hands, poorly painted faces, deformed, disfigured, deformed limbs, fused fingers, cluttered background, three legs, a lot of people in the background, upside down", "clip": [ "38", 0 ] }, "class_type": "CLIPTextEncode", "_meta": { "title": "CLIP Text Encode (Negative Prompt)" } },
    
    ...
    
    "52": { "inputs": { "image": "SMT54Y6XHY1977QPBESY72WSR0.jpeg", "upload": "image" }, "class_type": "LoadImage", "_meta": { "title": "Load Image" } },
    
    ...
    
    }
    
    ================================================ FILE: ViewComfy_API/Python/api.py
    import json from io import BufferedReader from typing import Any, Callable, Dict, List import httpx
    
    class FileOutput: """Represents a file output with its content encoded in base64"""
    
    def __init__(self, filename: str, content_type: str, data: str, size: int):
        """
        Initialize a FileOutput object.
    
        Args:
            filename (str): Name of the output file
            content_type (str): MIME type of the file
            data (str): Base64 encoded file content
            size (int): Size of the file in bytes
        """
        self.filename = filename
        self.content_type = content_type
        self.data = data
        self.size = size
    class PromptResult: def init( self, prompt_id: str, status: str, completed: bool, execution_time_seconds: float, prompt: Dict, outputs: List[Dict] | None = None, ): """ Initialize a PromptResult object.
    
        Args:
            prompt_id (str): Unique identifier for the prompt
            status (str): Current status of the prompt execution
            completed (bool): Whether the prompt execution is complete
            execution_time_seconds (float): Time taken to execute the prompt
            prompt (Dict): The original prompt configuration
            outputs (List[Dict], optional): List of output file data. Defaults to empty list.
        """
        self.prompt_id = prompt_id
        self.status = status
        self.completed = completed
        self.execution_time_seconds = execution_time_seconds
        self.prompt = prompt
    
        # Initialize outputs as FileOutput objects
        self.outputs = []
        if outputs:
            for output_data in outputs:
                self.outputs.append(
                    FileOutput(
                        filename=output_data.get("filename", ""),
                        content_type=output_data.get("content_type", ""),
                        data=output_data.get("data", ""),
                        size=output_data.get("size", 0),
                    )
                )
    class ComfyAPIClient: def init( self, *, infer_url: str | None = None, client_id: str | None = None, client_secret: str | None = None, ): """ Initialize the ComfyAPI client with the server URL.
    
        Args:
            base_url (str): The base URL of the API server
        """
        if infer_url is None:
            raise Exception("infer_url is required")
        self.infer_url = infer_url
    
        if client_id is None:
            raise Exception("client_id is required")
    
        if client_secret is None:
            raise Exception("client_secret is required")
    
        self.client_id = client_id
        self.client_secret = client_secret
    
    async def infer(
        self,
        *,
        data: Dict[str, Any],
        files: list[tuple[str, BufferedReader]] = [],
    ) -> Dict[str, Any]:
        """
        Make a POST request to the /api/infer-files endpoint with files encoded in form data.
    
        Args:
            data: Dictionary of form fields (logs, params, etc.)
            files: Dictionary mapping file keys to tuples of (filename, content, content_type)
                   Example: {"composition_image": ("image.jpg", file_content, "image/jpeg")}
    
        Returns:
            Dict[str, Any]: Response from the server
        """
    
        async with httpx.AsyncClient() as client:
            try:
                response = await client.post(
                    self.infer_url,
                    data=data,
                    files=files,
                    timeout=httpx.Timeout(2400.0),
                    follow_redirects=True,
                    headers={
                        "client_id": self.client_id,
                        "client_secret": self.client_secret,
                    },
                )
    
                if response.status_code == 201:
                    return response.json()
                else:
                    error_text = response.text
                    raise Exception(
                        f"API request failed with status {response.status_code}: {error_text}"
                    )
            except httpx.HTTPError as e:
                raise Exception(f"Connection error: {str(e)}")
            except Exception as e:
                raise Exception(f"Error during API call: {str(e)}")
    
    async def consume_event_source(
        self, *, response, logging_callback: Callable[[str], None]
    ) -> Dict[str, Any] | None:
        """
        Process a streaming Server-Sent Events (SSE) response.
    
        Args:
            response: An active httpx streaming response object
    
        Returns:
            List of parsed event objects
        """
        current_data = ""
        current_event = "message"  # Default event type
    
        prompt_result = None
        # Process the response as it streams in
        async for line in response.aiter_lines():
            line = line.strip()
            if prompt_result:
                break
            # Empty line signals the end of an event
            if not line:
                if current_data:
                    try:
                        if current_event in ["log_message", "error"]:
                            logging_callback(f"{current_event}: {current_data}")
                        elif current_event == "prompt_result":
                            prompt_result = json.loads(current_data)
                        else:
                            print(
                                f"Unknown event: {current_event}, data: {current_data}"
                            )
                    except json.JSONDecodeError as e:
                        print("Invalid JSON: ...")
                        print(e)
                    # Reset for next event
                    current_data = ""
                    current_event = "message"
                continue
    
            # Parse SSE fields
            if line.startswith("event:"):
                current_event = line[6:].strip()
            elif line.startswith("data:"):
                current_data = line[5:].strip()
            elif line.startswith("id:"):
                # Handle event ID if needed
                pass
            elif line.startswith("retry:"):
                # Handle retry directive if needed
                pass
        return prompt_result
    
    async def infer_with_logs(
        self,
        *,
        data: Dict[str, Any],
        logging_callback: Callable[[str], None],
        files: list[tuple[str, BufferedReader]] = [],
    ) -> Dict[str, Any] | None:
        if data.get("logs") is not True:
            raise Exception("Set the logs to True for streaming the process logs")
    
        async with httpx.AsyncClient() as client:
            try:
                async with client.stream(
                    "POST",
                    self.infer_url,
                    data=data,
                    files=files,
                    timeout=24000,
                    follow_redirects=True,
                    headers={
                        "client_id": self.client_id,
                        "client_secret": self.client_secret,
                    },
                ) as response:
                    if response.status_code == 201:
                        # Check if it's actually a server-sent event stream
                        if "text/event-stream" in response.headers.get(
                            "content-type", ""
                        ):
                            prompt_result = await self.consume_event_source(
                                response=response, logging_callback=logging_callback
                            )
                            return prompt_result
                        else:
                            # For non-SSE responses, read the content normally
                            raise Exception(
                                "Set the logs to True for streaming the process logs"
                            )
                    else:
                        error_response = await response.aread()
                        error_data = json.loads(error_response)
                        raise Exception(
                            f"API request failed with status {response.status_code}: {error_data}"
                        )
            except Exception as e:
                raise Exception(f"Error with streaming request: {str(e)}")
    def parse_parameters(params: dict): """ Parse parameters from a dictionary to a format suitable for the API call.
    
    Args:
        params (dict): Dictionary of parameters
    
    Returns:
        dict: Parsed parameters
    """
    parsed_params = {}
    files = []
    for key, value in params.items():
        if isinstance(value, BufferedReader):
            files.append((key, value))
        else:
            parsed_params[key] = value
    return parsed_params, files
    async def infer( *, params: Dict[str, Any], api_url: str, override_workflow_api: Dict[str, Any] | None = None, client_id: str, client_secret: str, ): """ Make an inference with real-time logs from the execution prompt
    
    Args:
        api_url (str): The URL to send the request to
        params (dict): The parameter to send to the workflow
        override_workflow_api (dict): Optional override the default workflow_api of the deployment
    
    Returns:
        PromptResult: The result of the inference containing outputs and execution details
    """
    client = ComfyAPIClient(
        infer_url=api_url,
        client_id=client_id,
        client_secret=client_secret,
    )
    
    params_parsed, files = parse_parameters(params)
    data = {
        "logs": False,
        "params": json.dumps(params_parsed),
        "workflow_api": json.dumps(override_workflow_api)
        if override_workflow_api
        else None,
    }
    
    # Make the API call
    result = await client.infer(data=data, files=files)
    
    return PromptResult(**result)
    async def infer_with_logs( *, params: Dict[str, Any], logging_callback: Callable[[str], None], api_url: str, override_workflow_api: Dict[str, Any] | None = None, client_id: str, client_secret: str, ): """ Make an inference with real-time logs from the execution prompt
    
    Args:
        api_url (str): The URL to send the request to
        params (dict): The parameter to send to the workflow
        override_workflow_api (dict): Optional override the default workflow_api of the deployment
        logging_callback (Callable[[str], None]): The callback function to handle logging messages
    
    Returns:
        PromptResult: The result of the inference containing outputs and execution details
    """
    
    client = ComfyAPIClient(
        infer_url=api_url,
        client_id=client_id,
        client_secret=client_secret,
    )
    
    params_parsed, files = parse_parameters(params)
    data = {
        "logs": True,
        "params": json.dumps(params_parsed),
        "workflow_api": json.dumps(override_workflow_api)
        if override_workflow_api
        else None,
    }
    
    # Make the API call
    result = await client.infer_with_logs(
        data=data,
        files=files,
        logging_callback=logging_callback,
    )
    
    if result:
        return PromptResult(**result)
    ```
    FILE: ViewComfy_API/Python/main.py
    ```python
    import asyncio import base64 import json import os from api import infer, infer_with_logs
    
    async def api_examples():
    
    view_comfy_api_url = "<Your_ViewComfy_endpoint>"
    client_id = "<Your_ViewComfy_client_id>"
    client_secret = "<Your_ViewComfy_client_secret>"
    
    override_workflow_api_path = None # Advanced feature: overwrite default workflow with a new one
    
    # Set parameters
    params = {}
    
    params["6-inputs-text"] = "A cat sorcerer"
    params["52-inputs-image"] = open("input_folder/input_img.png", "rb")
    
    override_workflow_api = None
    if  override_workflow_api_path:
        if os.path.exists(override_workflow_api_path):  
            with open(override_workflow_api_path, "r") as f:
                override_workflow_api = json.load(f)
        else:
            print(f"Error: {override_workflow_api_path} does not exist")
    
    def logging_callback(log_message: str):
        print(log_message)
    
    # Call the API and wait for the results
    # try:
    #     prompt_result = await infer(
    #         api_url=view_comfy_api_url,
    #         params=params,
    #         client_id=client_id,
    #         client_secret=client_secret,
    #     )
    # except Exception as e:
    #     print("something went wrong calling the api")
    #     print(f"Error: {e}")
    #     return
    
    # Call the API and get the logs of the execution in real time
    # you can use any function that you want
    try:
        prompt_result = await infer_with_logs(
            api_url=view_comfy_api_url,
            params=params,
            logging_callback=logging_callback,
            client_id=client_id,
            client_secret=client_secret,
            override_workflow_api=override_workflow_api,
        )
    except Exception as e:
        print("something went wrong calling the api")
        print(f"Error: {e}")
        return
    
    if not prompt_result:
        print("No prompt_result generated")
        return
    
    for file in prompt_result.outputs:
        try:
            # Decode the base64 data before writing to file
            binary_data = base64.b64decode(file.data)
            with open(file.filename, "wb") as f:
                f.write(binary_data)
            print(f"Successfully saved {file.filename}")
        except Exception as e:
            print(f"Error saving {file.filename}: {str(e)}")
    if name == "main": asyncio.run(api_examples())
    ```
    
    ================================================ 
    FILE: ViewComfy_API/Python/requirements.txt
    ```
    httpx==0.28.1
    ```
    
    ================================================ 
    FILE: ViewComfy_API/Python/workflow_api_parameter_creator.py
    ```python
    from typing import Dict, Any
    
    def workflow_api_parameters_creator(workflow: Dict[str, Dict[str, Any]]) -> Dict[str, Any]: """ Flattens the workflow API JSON structure into a simple key-value object
    
    Args:
        workflow: The workflow API JSON object
    
    Returns:
        A flattened object with keys in the format "nodeId-inputs-paramName" or "nodeId-class_type-info"
    """
    flattened: Dict[str, Any] = {}
    
    # Iterate through each node in the workflow
    for node_id, node in workflow.items():
        # Add the class_type-info key, preferring _meta.title if available
        class_type_info = node.get("_meta", {}).get("title") or node.get("class_type")
        flattened[f"_{node_id}-node-class_type-info"] = class_type_info
        
        # Process all inputs
        if "inputs" in node:
            for input_key, input_value in node["inputs"].items():
                flattened[f"{node_id}-inputs-{input_key}"] = input_value
    
    return flattened
    """ Example usage:
    
    import json
    
    with open('workflow_api.json', 'r') as f: workflow_json = json.load(f)
    
    flattened = create_workflow_api_parameters(workflow_json) print(flattened) """
    ```
    
    ================================================ 
    FILE: ViewComfy_API/Python/workflow_parameters_maker.py
    ```python
    import json from workflow_api_parameter_creator import workflow_api_parameters_creator import argparse
    
    parser = argparse.ArgumentParser(description='Process workflow API parameters') parser.add_argument('--workflow_api_path', type=str, required=True, help='Path to the workflow API JSON file')
    
    Parse arguments
    args = parser.parse_args()
    
    with open(args.workflow_api_path, 'r') as f: workflow_json = json.load(f)
    
    parameters = workflow_api_parameters_creator(workflow_json)
    
    with open('workflow_api_parameters.json', 'w') as f: json.dump(parameters, f, indent=4)
    ```

    Tags

    python

    Comments

    More Rules

    View all
    Web Development

    Next.js 15 + TypeScript Cursor Rules

    Comprehensive .cursorrules file for Next.js 15 App Router projects with TypeScript, enforcing server components by default, proper use of "use client" directive, and App Router conventions.

    C
    Community
    Backend Development

    Python FastAPI Best Practices Rules

    Cursor rules for Python FastAPI projects enforcing async patterns, Pydantic v2 models, dependency injection, and proper error handling.

    C
    Community
    Frontend Development

    React + TypeScript Component Rules

    Rules for consistent React component development with TypeScript interfaces, proper hook patterns, and component composition.

    C
    Community
    AI/ML

    Cursor Agent Mode Configuration

    Rules optimizing Cursor Agent mode behavior including multi-file editing context, session management, and autonomous task completion patterns.

    C
    Cursor Team
    Frontend Development

    Tailwind CSS + shadcn/ui Rules

    Cursor rules for projects using Tailwind CSS with shadcn/ui component library, enforcing consistent utility class usage and component patterns.

    C
    Community
    Backend Development

    Go Backend Service Rules

    Rules for Go backend services enforcing idiomatic Go patterns, proper error handling, and clean architecture conventions.

    C
    Community

    Stay up to date

    Get the latest Cursor prompts, rules, and resources delivered to your inbox weekly.

    Neura Market LogoNeura Market

    Discover the best AI prompts, plugins, and resources for Cursor and more.

    Content Types

    • Rules
    • Prompts
    • MCPs
    • Agents
    • Guides

    Platforms

    • ChatGPT Directory
    • Claude Directory
    • Gemini Directory
    • Cursor Directory
    • Grok Directory
    • Perplexity Directory
    • DeepSeek Directory
    • CoPilot Directory
    • Stable Diffusion Directory
    • Midjourney Directory
    • All Directories

    Resources

    • Blog
    • Documentation
    • Help Center
    • Marketplace

    Legal

    • Privacy Policy
    • Terms of Service

    © 2026 Neura Market. All rights reserved.

    |

    Not affiliated with any AI platform vendors.