All Products
Search
Document Center

Platform For AI:Verify ComfyUI API integration

Last Updated:Apr 01, 2026

Use the Developer Center in PAI ArtLab to confirm that your ComfyUI service accepts API calls and returns generated images. PAI ArtLab offers two ComfyUI editions with different call models — choose based on your deployment scenario.

Choose an edition

EditionInterfaceMulti-instance supportCall model
API editionAPI only, no web UIYesAsynchronous queue (EAS)
Exclusive editionAPI + web UISynchronous HTTP

Use the API edition when you need to scale across multiple ComfyUI instances. Use the Exclusive edition for single-instance deployments or interactive debugging.

API edition

The API edition has no web UI. Because ComfyUI is a stateful service, multi-instance deployments route requests through the Elastic Algorithm Service (EAS) asynchronous queue to ensure each request lands on the correct instance.

Prerequisites

Before you begin, ensure that you have:

  • A Python environment

  • The EAS SDK for the asynchronous queue service: pip install eas_prediction

Create the service and get call information

  1. Log on to the PAI ArtLab console. In the left-side navigation pane, choose Developer Center and click the Custom Service tab. Click Create Custom Service.

  2. For Service Edition, select ComfyUI (API Edition).

  3. When Status changes to Running, click Call Information. On the Response URL (Internet) tab, copy the URL, token, endpoint, and service ID.

    image

Submit a workflow request

Replace the four parameters at the top of the following code with the values from the Call Information panel, then run the script.

Sample code

import requests
from eas_prediction import QueueClient

# Replace with your actual call information
input_url = "http://115************.cn-shanghai.pai-eas.aliyuncs.com/api/predict/ai4d_comfyuiapi_1u38************"
token = "Yjha************"
endpoint = "115************.cn-shanghai.pai-eas.aliyuncs.com"
service_name = "ai4d_comfyuiapi_1u38************/sink"

# Build the authenticated session
session = requests.session()
session.headers.update({"Authorization": f"{token}"})

# Workflow definition — a text-to-image pipeline with six nodes:
# Node 3 (KSampler): runs diffusion sampling with the specified seed and steps
# Node 4 (CheckpointLoaderSimple): loads the 3dAnimationDiffusion checkpoint
# Node 5 (EmptyLatentImage): creates a 512x512 blank latent canvas
# Node 6 (CLIPTextEncode): encodes the positive text prompt
# Node 7 (CLIPTextEncode): encodes the negative prompt ("text, watermark")
# Node 8 (VAEDecode): decodes the latent image to pixel space
# Node 9 (SaveImage): saves the output with the "ComfyUI" filename prefix
work_flow = {
    "3": {
        "inputs": {
            "seed": 156680208700286,
            "steps": 20,
            "cfg": 8,
            "sampler_name": "euler",
            "scheduler": "normal",
            "denoise": 1,
            "model": ["4", 0],
            "positive": ["6", 0],
            "negative": ["7", 0],
            "latent_image": ["5", 0]
        },
        "class_type": "KSampler",
        "_meta": {"title": "K sampler"}
    },
    "4": {
        "inputs": {"ckpt_name": "3dAnimationDiffusion_v10.safetensors"},
        "class_type": "CheckpointLoaderSimple",
        "_meta": {"title": "Checkpoint loader (simple)"}
    },
    "5": {
        "inputs": {"width": 512, "height": 512, "batch_size": 1},
        "class_type": "EmptyLatentImage",
        "_meta": {"title": "Empty Latent"}
    },
    "6": {
        "inputs": {
            "text": "beautiful scenery nature glass bottle landscape, , purple galaxy bottle,",
            "clip": ["4", 1]
        },
        "class_type": "CLIPTextEncode",
        "_meta": {"title": "CLIP text encoder"}
    },
    "7": {
        "inputs": {"text": "text, watermark", "clip": ["4", 1]},
        "class_type": "CLIPTextEncode",
        "_meta": {"title": "CLIP text encoder"}
    },
    "8": {
        "inputs": {"samples": ["3", 0], "vae": ["4", 2]},
        "class_type": "VAEDecode",
        "_meta": {"title": "VAE decoding"}
    },
    "9": {
        "inputs": {"filename_prefix": "ComfyUI", "images": ["8", 0]},
        "class_type": "SaveImage",
        "_meta": {"title": "Save the image"}
    }
}

# Submit the task to the asynchronous queue
response = session.post(
    url=f'{input_url}/api_prompt?task_id=txt2img_test',
    json=work_flow
)
if response.status_code != 200:
    exit(f"send request error:{response.content}, response code:{response.status_code}")
else:
    print(f"send success, index is {response.content}")

# Poll the sink queue for the result
sink_queue = QueueClient(f'{endpoint}', f'{service_name}')
sink_queue.set_token(f'{token}')
sink_queue.init()

watcher = sink_queue.watch(0, 1, auto_commit=False)
for x in watcher.run():
    if 'task_id' in x.tags:
        print('index {} task_id is {}'.format(x.index, x.tags['task_id']))
        print(f'index {x.index} data is {x.data}')
        sink_queue.commit(x.index)

Retrieve the output image

  1. After the script completes, note the filename in the output. The task_id tag matches the value you passed in api_prompt?task_id=. The data field contains the generated image filename.

    image

  2. In ArtLab, hover over image in the upper-right corner. Click the link next to Storage to open the OSS bucket and copy the storage path.

    image

  3. Construct the full image URL using the format <OSS bucket path>/output/<filename>. Example:

    26****/data-115****************/output/ComfyUI_00000000_174427782695938_599ffc33-edea-4e64-bb60-28e834940f5c_.png

Exclusive edition

The Exclusive edition supports both API calls and web-based debugging. It uses a synchronous request model: submit a workflow to get a prompt_id, then query the history endpoint to retrieve the output.

Prerequisites

Before you begin, ensure that you have:

  • A Python environment

Create the service and get call information

  1. Log on to the PAI ArtLab console. In the left-side navigation pane, choose Developer Center and click the Custom Service tab. Click Create Custom Service.

  2. For Service Edition, select ComfyUI (Exclusive edition).

  3. When Service Status changes to Running, click Call Information. On the Internet Endpoint tab, copy the URL and token.

    image

Submit a workflow and retrieve the result

Replace the two parameters at the top of the following code with the values from the Call Information panel, then run the script. The script submits the workflow and prints the output filename.

Sample code

import requests

# Replace with your actual call information
url = "http://ai4d_comfyuiapi_1u38************.115************.cn-shanghai.pai-eas.aliyuncs.com/"
token = "Yjha************"

# Workflow definition — same six-node text-to-image pipeline:
# Node 3 (KSampler): runs diffusion sampling
# Node 4 (CheckpointLoaderSimple): loads the 3dAnimationDiffusion checkpoint
# Node 5 (EmptyLatentImage): creates a 512x512 blank latent canvas
# Node 6 (CLIPTextEncode): encodes the positive text prompt
# Node 7 (CLIPTextEncode): encodes the negative prompt
# Node 8 (VAEDecode): decodes the latent image to pixel space
# Node 9 (SaveImage): saves the output with the "ComfyUI" filename prefix
payload = {
    "prompt": {
        "3": {
            "inputs": {
                "seed": 156680208700286,
                "steps": 20,
                "cfg": 8,
                "sampler_name": "euler",
                "scheduler": "normal",
                "denoise": 1,
                "model": ["4", 0],
                "positive": ["6", 0],
                "negative": ["7", 0],
                "latent_image": ["5", 0]
            },
            "class_type": "KSampler",
            "_meta": {"title": "K sampler"}
        },
        "4": {
            "inputs": {"ckpt_name": "3dAnimationDiffusion_v10.safetensors"},
            "class_type": "CheckpointLoaderSimple",
            "_meta": {"title": "Checkpoint loader (simple)"}
        },
        "5": {
            "inputs": {"width": 512, "height": 512, "batch_size": 1},
            "class_type": "EmptyLatentImage",
            "_meta": {"title": "Empty Latent"}
        },
        "6": {
            "inputs": {
                "text": "beautiful scenery nature glass bottle landscape, , purple galaxy bottle,",
                "clip": ["4", 1]
            },
            "class_type": "CLIPTextEncode",
            "_meta": {"title": "CLIP text encoder"}
        },
        "7": {
            "inputs": {"text": "text, watermark", "clip": ["4", 1]},
            "class_type": "CLIPTextEncode",
            "_meta": {"title": "CLIP text encoder"}
        },
        "8": {
            "inputs": {"samples": ["3", 0], "vae": ["4", 2]},
            "class_type": "VAEDecode",
            "_meta": {"title": "VAE decoding"}
        },
        "9": {
            "inputs": {"filename_prefix": "ComfyUI", "images": ["8", 0]},
            "class_type": "SaveImage",
            "_meta": {"title": "Save the image"}
        }
    }
}

# Submit the workflow — the service returns a prompt_id for tracking
session = requests.session()
session.headers.update({"Authorization": f"{token}"})
prompt_url = url + "prompt"

response = session.post(url=f'{prompt_url}', json=payload)
if response.status_code != 200:
    raise Exception(response.content)

data = response.json()
prompt_id = data['prompt_id']
print(f"get data: {data}, get prompt id: {prompt_id}")

# Retrieve results using the prompt_id
history_url = f"{url}history/{prompt_id}"

session = requests.session()
session.headers.update({"Authorization": f"{token}"})

response = session.get(url=f'{history_url}')
if response.status_code != 200:
    raise Exception(response.content)

data = response.json()
print(data)

# Parse the output to get image filenames
for prompt_id, prompt_data in data.items():
    outputs = prompt_data.get("outputs", {})
    for node_id, node_data in outputs.items():
        images = node_data.get("images", [])
        for image in images:
            filename = image.get("filename")
            print(f"Node number: {node_id}, Image filename: {filename}")

Retrieve the output image

  1. After the script completes, note the filename in the output. The history response groups images by node ID. Each entry in outputs[node_id]["images"] contains a filename field with the saved image name.

    image

  2. In ArtLab, hover over image in the upper-right corner. Click the link next to Storage to open the OSS bucket and copy the storage path.

    image

  3. Construct the full image URL using the format <OSS bucket path>/output/<filename>. Example:

    26****/data-115****************/output/ComfyUI_00000000_174427782695938_599ffc33-edea-4e64-bb60-28e834940f5c_.png