RunComfy

Search

ComfyUI Workflows

ComfyUI Online

Try RunComfy, we help you focus on ART instead of red errors

RC ComfyUI Versions

RunComfy System Status

ComfyUI How-tos

ComfyUI
ComfyUI

ComfyUI Backend API (works with RunComfy Server API)

RunComfy offers two API approaches to suit various integration needs: RunComfy Server API and ComfyUI Backend API These APIs lets you spin up and fully control a dedicated ComfyUI backend. Start by using the Server API to manage machines through simple calls: POST to generate a server_id, poll the status endpoint until it reaches "Ready", and then access the ComfyUI Backend API directly for tasks like executing workflows, managing nodes, and retrieving outputs. This approach is perfect when you need complete oversight of the ComfyUI backend, such as for in-depth integrations with creative software like Krita, Photoshop, Blender, iClone, or other tools. RunComfy Serverless API This API turns any ComfyUI workflow into an on-demand, autoscaling endpoint, enabling simple API calls without any server setup or maintenance. It includes asynchronous job monitoring and versioning for rapid updates, making it ideal for efficient, scalable production setups that can be easily integrated into your apps. For more details, check our Serverless API documentation.

Get ComfyUI Backend URL

  1. From RunComfy website in the browser
    1. The url appears as https://www.runcomfy.com/comfyui/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx/servers/yyyyyyy-yyyy-yyyy-yyyyyyyyyyyy.
    2. The actual ComfyUI URL can be found in here, in a format of https://yyyyyyy-yyyy-yyyy-yyyyyyyyyyyy-comfyui.runcomfy.com.
  2. From RunComfy API
    1. It is the main_service_url in this response.
Note: Please use this ComfyUI URL in a trusted environment, DO NOT SHARE IT publicly.

Activate Development Mode

Ensure that "Enable Development Mode Options" is activated in the Settings menu.

image

Download the workflow_api.json file by clicking on the Save (API Format) button.

The following file is AnimateDiff + ControlNet + Auto Mask | Restyle Video, which will be used as an example.

workflow_api.json7.3KB

Upload Image as Input

Upload Video as Input

The response will be something like:

{
    "name": "zzzz.mp4",
    "subfolder": "",
    "type": "input"
}

The zzzz.mp4 is the file you uploaded via the API in the input folder. Sometimes it may contain suffixes like '(1)' or '(1)(1)' if a file with the same name already exists.

Queue prompt

Basic HTTP API:

  • Generate client_id
import uuid
client_id = str(uuid.uuid4())
  • Load workflow_api.json from your local disk and change the input to the file name which you just uploaded in input folder, and also modify the prompt text in the json if you need to.
import json

prompt_data = json.load(open("workflow_api.json"))

prompt_data['89']['inputs']['video'] = 'zzzz.mp4'
  • Call the queue prompt api
  • check status
    • Reference to https://github.com/comfyanonymous/ComfyUI/blob/master/script_examples/websockets_api_example.py for more details
import websocket
import uuid

ws = websocket.WebSocket()
ws.connect("ws://{}/ws?clientId={}".format('yyyyyyy-yyyy-yyyy-yyyyyyyyyyyy-comfyui.runcomfy.com', client_id))
while True:
    out = ws.recv()
    print(out)
status.txt426.2KB
  • Get Result
  • Explanation on the url path
    • If you want to get the file from the following path, /ComfyUI/output/subfolder1/subfolder2/test_00001_.png, try GET the following url, https://xxx-comfyui.runcomfy.com/api/view?filename=test_00001_.png&subfolder=subfolder1%2Fsubfolder2&type=output
RunComfy

ComfyUI

ComfyUI Online

ComfyUI Web

ComfyUI Workflows

ComfyUI Cloud

import requests

url = "https://yyyyyyy-yyyy-yyyy-yyyyyyyyyyyy-comfyui.runcomfy.com/upload/image"

payload = {'overwrite':'true', 'type':'input', 'subfolder':''} # you can safely remove the subfolder field here if you don't need it
files=[
  ('image',('zzzz.png',open('/folder_path/zzzz.png','rb'),'application/octet-stream'))
]
headers = {}

response = requests.post(url, headers=headers, data=payload, files=files)

print(response.json())
import requests

url = "https://yyyyyyy-yyyy-yyyy-yyyyyyyyyyyy-comfyui.runcomfy.com/upload/image"

payload = {'overwrite':'true', 'type':'input', 'subfolder':''} # you can safely remove the subfolder field here if you don't need it
files=[
  ('image',('zzzz.mp4',open('/folder_path/zzzz.mp4','rb'),'application/octet-stream'))
]
headers = {}

response = requests.post(url, headers=headers, data=payload, files=files)

print(response.json())
import requests

url = "https://yyyyyyy-yyyy-yyyy-yyyyyyyyyyyy-comfyui.runcomfy.com/prompt"

prompt = {
    "prompt": prompt_data,
    "client_id": client_id
}

headers = {}

response = requests.post(url, headers=headers, json=prompt)

print(response.json())

### response:
{'prompt_id': '10b3da78-cf5f-4ed7-885d-dccf5f3f3c69', 'number': 0, 'node_errors': {}}
import requests
import urllib.parse 

# see the explanation in the next section for the path
def get_image(filename, subfolder, folder_type):
    data = {"filename": filename, "subfolder": subfolder, "type": folder_type}
    url_value = urllib.parse.urlencode(data)
    url = "https://yyyyyyy-yyyy-yyyy-yyyyyyyyyyyy-comfyui.runcomfy.com/view?{}".format(url_value)
    response = requests.get(url)
    return response.content

# see the explanation in the next section for the path
def get_video(filename, subfolder, _format):
    data = {"filename": filename, "subfolder": subfolder, "format": _format}
    url_value = urllib.parse.urlencode(data)
    url = "https://yyyyyyy-yyyy-yyyy-yyyyyyyyyyyy-comfyui.runcomfy.com/view?{}".format(url_value)
    response = requests.get(url)
    return response.content

prompt_id = '10b3da78-cf5f-4ed7-885d-dccf5f3f3c69' # the response from POST https://comfyui_url/prompt

url = "https://yyyyyyy-yyyy-yyyy-yyyyyyyyyyyy-comfyui.runcomfy.com/history/{}".format(prompt_id)

headers = {}

response = requests.get(url, headers=headers)

data = response.json().get(prompt_id)

video_result = data.get('outputs').get('90').get('gifs')[0]
raw_video = get_video(video_result.get('filename'), video_result.get('subfolder'), video_result.get('format'))

with open(video_result.get('filename'), 'wb') as f:
    f.write(raw_video)

# GET ALL MEDIA OUTPUT FROM WORKFLOW
    
for node_id, node_output in data.get('outputs').items():
    if 'images' in node_output:
        for image in node_output['images']:
            raw_image = get_image(image.get('filename'), image.get('subfolder'), image.get('temp'))
            with open(f"./output/{image.get('filename')}", "wb") as f:
                f.write(raw_image)

    if 'gifs' in node_output:
        for video in node_output['gifs']:            
            raw_video = get_video(video.get('filename'), video.get('subfolder'), video.get('format'))
            with open(f"./output/{video.get('filename')}", "wb") as f:
                f.write(raw_video)
        
    if 'openpose_json' in node_output:
        pass