> ## Documentation Index
> Fetch the complete documentation index at: https://docs.runflow.io/llms.txt
> Use this file to discover all available pages before exploring further.

# ComfyUI Deploy FAQ

> Answers to the common questions about deploying and calling ComfyUI workflows on Runflow: beta access, setup, calling your endpoint, GPUs, and billing.

Quick answers to the questions we hear most about ComfyUI Deploy. For the full walkthrough (install, configure, deploy, call), see [Deploy a ComfyUI workflow](/guides/comfyui-deploy). For the bare API, see [ComfyUI workflows API](/api/comfyui-workflows).

<Note>
  **Beta.** ComfyUI Deploy is in beta. Access to create and run deployed workflows is enabled per organization (see [How do I get access?](#access-and-beta)). The plugin, API surface, and pricing are stable but may still change; breaking changes are called out in [the changelog](https://github.com/runflow-io/ComfyUI-Runflow/releases) before they ship.
</Note>

## Access and beta

<AccordionGroup>
  <Accordion title="Is ComfyUI Deploy generally available?">
    Not yet. It is in beta, and creating or running deployed workflows is enabled per organization. The ComfyUI workflows area is visible to everyone in the dashboard, but an organization has to be enrolled before it can deploy or dispatch runs.
  </Accordion>

  <Accordion title="How do I get access?" defaultOpen>
    Open the ComfyUI workflows section in [the dashboard](https://app.runflow.io). If your organization is not enrolled yet, you will see a beta gate with a **Request Beta Access** button. Click it to register your interest. The Runflow team enrolls organizations from there; once your organization is enrolled the page shows your workflows and the API stops returning the beta error.
  </Accordion>

  <Accordion title="My API call returns 403 COMFYUI_DEPLOY_BETA_NOT_ENABLED. Why?">
    Creating a workflow and dispatching a run are gated on your organization being enrolled in the beta. Until then, both return `403` with the error code `COMFYUI_DEPLOY_BETA_NOT_ENABLED`. Read endpoints (listing and fetching workflows) are not gated. The gate also applies when you try to run another organization's public workflow, so being able to see a workflow does not by itself let you run it. Request access in the dashboard, and the same calls will succeed once you are enrolled.
  </Accordion>

  <Accordion title="My organization is in the beta. Does that cover my whole team?">
    Yes. Beta access is granted per organization, so every member of an enrolled organization can use ComfyUI Deploy. Any of your organization's API keys with the right scopes can deploy and call endpoints, and runs bill to the organization regardless of which member or key triggered them.
  </Accordion>
</AccordionGroup>

## Install and setup

<AccordionGroup>
  <Accordion title="I installed the plugin but there is no Runflow category in the node picker.">
    ComfyUI loaded before the plugin was on disk, the plugin landed in the wrong `custom_nodes/` directory, or you only refreshed the browser tab. A browser refresh is not enough: the Python process has to re-exec. Confirm the plugin is under `custom_nodes/`, then fully restart the ComfyUI server process. After the restart a **Runflow** category appears in the node picker.
  </Accordion>

  <Accordion title="Where do I put my API key, and why not on the Deploy node?">
    Put it under ComfyUI **Settings, Runflow, Connection** (the `Runflow.ApiKey` field). That storage is local to your machine and is never written into a workflow file. The Deploy node also exposes `host` and `api_key` widgets, but ComfyUI persists widget values into the workflow JSON, so a key typed there travels with every export, screenshot, and paste. Leave those widgets empty for normal use.

    <Warning>
      Before you click Deploy on a workflow you did not author, clear both the `host` and `api_key` widgets on the Deploy node (or delete and recreate the node). A workflow from a stranger can pre-fill `host` to send your key to their server.
    </Warning>
  </Accordion>

  <Accordion title="What API key scopes do I need?">
    It depends on what you do. Publishing a brand-new endpoint needs `comfyui-workflows:read` plus `comfyui-workflows:create`. Redeploying to the same slug from the same client also needs `comfyui-workflows:edit`. Deleting endpoints needs `comfyui-workflows:delete`. The Deploy button uses `read` to detect an existing slug, then `create` (new) or `edit` (replace). Issue the narrowest set you need: `edit` lets a key replace the graph of any existing endpoint your organization owns, so rotate the key on any suspicion of a leak. Dispatching a run (calling your deployed endpoint) uses the standard `runs:create` scope, the same as any model run, which is separate from the `comfyui-workflows:*` deploy and manage scopes above. [Create a key](https://app.runflow.io/settings/api-keys).
  </Accordion>

  <Accordion title="Should I pin a plugin version?">
    There are no version tags published yet; the plugin tracks `main`. If you need a hard guarantee against future renames of node classes, widgets, or settings, pin the commit SHA after you clone. Watch [the releases page](https://github.com/runflow-io/ComfyUI-Runflow/releases) for breaking changes.
  </Accordion>
</AccordionGroup>

## Deploying your workflow

<AccordionGroup>
  <Accordion title="How is my endpoint slug derived from the name?">
    The slug comes from the Deploy node's `endpoint_name`: lowercased, whitespace mapped to `-`, and anything outside `a-z`, `0-9`, `-`, `_` stripped. So `Background Removal v2.1` becomes `background-removal-v21` (the `.` is dropped). The default name is `default`, so rename it before deploying or you will publish to a slug literally called `default`. Pick a name without surprises.
  </Accordion>

  <Accordion title="I renamed my endpoint and now there is a duplicate, or my old one is gone.">
    Renaming `endpoint_name` changes the slug, which creates a new endpoint rather than updating the old one. To replace an existing endpoint, keep the same name and rely on the `comfyui-workflows:edit` scope so the deploy overwrites the same slug in place.
  </Accordion>

  <Accordion title="Deploy failed. What do the common errors mean?">
    The plugin shows the underlying error in a browser alert. The usual causes:

    * **Alert about an unconfigured key or URL.** `Runflow.ApiKey` is blank in Settings (and the node's `api_key` widget is also blank), or `Runflow.ApiUrl` was cleared. Save the key under Settings and deploy again.
    * **A `failed` alert citing `401` or an invalid key.** The key is missing, revoked, or for the wrong environment. Reissue it and re-save under Settings.
    * **`lookup failed` or `403` on redeploy.** Deploy first looks up the existing slug, then replaces it. A key with `create` but no `read` fails at the lookup; a key with `read` but no `edit` fails at the replace. Use `read`, `create`, and `edit` together for iterative deploys.
    * **`endpoint_name must be URL-safe`.** The slug came out empty after stripping characters. Pick a name with at least one letter or number.
  </Accordion>

  <Accordion title="Can I deploy or manage workflows without the plugin (CI or automation)?">
    Yes. The plugin is the convenient path, but the workflow resource has a REST surface you can call directly with any Runflow key that has the right scopes. Create with a `POST` to the workflows collection, replace the graph or swap GPU mode with a `PATCH`, and soft-delete with a `DELETE`. See [ComfyUI workflows API](/api/comfyui-workflows) for the full endpoint list and request bodies.
  </Accordion>

  <Accordion title="How do I take down an endpoint, and what happens to its runs?">
    Delete the workflow with `DELETE /v1/comfyui-workflows/{id}` (needs the `comfyui-workflows:delete` scope). The delete is a soft delete: new runs are rejected with `404` on the dispatch route, but the workflow's historical runs stay reachable through `GET /v1/runs/{id}`.
  </Accordion>
</AccordionGroup>

## Calling your deployed workflow

<AccordionGroup>
  <Accordion title="What URL do I call to run my deployed workflow?" defaultOpen>
    Dispatch a run against your workflow's canonical owner and slug path. `your-org` is your organization slug (shown at the top of the dashboard, derived from your API key) and `your-endpoint` is what `endpoint_name` slugified to:

    ```
    curl -X POST "https://api.runflow.io/v1/comfyui-workflows/your-org/your-endpoint/runs" \
      -H "Authorization: Bearer $RUNFLOW_API_KEY" \
      -H "Content-Type: application/json" \
      -d '{
        "input": {
          "prompt": "a sea otter holding a smooth pebble",
          "width": 1024,
          "height": 1024
        },
        "callback_url": "https://your-server.com/webhook"
      }'
    ```

    The response is intentionally minimal: `{ "run_id": "...", "status": "queued" }`. Track the run by polling `GET /v1/runs/{id}` until its `status_code` reaches a terminal state (`succeeded` or `failed`), or by passing a `callback_url`. See [ComfyUI workflows API](/api/comfyui-workflows) for the request body fields.
  </Accordion>

  <Accordion title="How do I pass inputs, and which input types are supported?">
    The `input` object is keyed by the `input_id` of each Runflow Input node in your workflow. The plugin ships typed input nodes: `Runflow Input (String)`, `(Int)`, `(Float)`, `(Boolean)`, `(Image)`, and `(File)`. Set a meaningful `input_id` on each one in your workflow; two inputs of the same type that keep the default id will collide. Send values under those same keys at call time.
  </Accordion>

  <Accordion title="How do I send an image or a file as input?">
    Use a `Runflow Input (Image)` or `Runflow Input (File)` node, then send its value as either a `runflow://assets/{uuid}` reference to a previously uploaded asset or any `https://` URL (plain `http://` is rejected). A `runflow://` asset used for an *image* input must be a PNG, JPEG, WebP, or GIF; a `Runflow Input (File)` accepts any file type. Runflow does not fetch or size-check an external URL when you submit the run; the worker downloads it at run time, so an unreachable or wrong-type URL surfaces as a run failure rather than a submit error.
  </Accordion>

  <Accordion title="What does the response look like, and how do I get my outputs?">
    A completed run's `output` carries `kind: "comfyui_outputs"` and an `outputs` array — one entry per emitted artifact file, each labeled by the `output_id` of the Runflow Output node that produced it. A node that emits several files (a batch, say) yields several entries that share one `output_id`, so treat `output_id` as a node label, not a unique key:

    ```json theme={"dark"}
    {
      "id": "01J0...",
      "status_code": "succeeded",
      "output": {
        "kind": "comfyui_outputs",
        "outputs": [
          {
            "output_id": "image",
            "url": "https://...",
            "content_type": "image/png",
            "size_bytes": 1048576
          },
          {
            "output_id": "image",
            "url": "https://...",
            "content_type": "image/png",
            "size_bytes": 1041923
          }
        ]
      }
    }
    ```

    Iterate the whole array and group by `output_id` when you need per-node outputs. Each entry's `url` is presigned and time-limited; download or copy outputs to your own storage on receipt. If a URL expires before you fetch it, re-request the run with `GET /v1/runs/{id}` and Runflow returns freshly signed URLs.
  </Accordion>

  <Accordion title="Is the API synchronous, or do I poll? What about callbacks?">
    Dispatch is asynchronous. Pass a `callback_url` and Runflow POSTs the terminal run to it once the run reaches a final state, or omit it and poll `GET /v1/runs/{id}` until the status is terminal. See [Runs](/concepts/runs) for the lifecycle and [Callbacks](/concepts/callbacks) plus [Verify callback signatures](/guides/verify-callback-signatures) for the webhook pattern.
  </Accordion>
</AccordionGroup>

## GPUs and billing

<AccordionGroup>
  <Accordion title="How is ComfyUI Deploy billed?">
    Deployed workflows bill per second of GPU wall-time: from when a worker picks up your run until it returns a result. There is no fixed per-call price, because the workflow is yours. The charge is applied once per run, to the organization that calls the run (the API key's organization), not the workflow's owner. Idle workers cost nothing, because the platform scales to zero between runs.
  </Accordion>

  <Accordion title="Which GPU does my workflow run on? Can I choose?">
    GPU selection is set on the workflow, not per run, through its `gpu_mode`. In `auto` (the default) the platform routes each run to the cheapest GPU that fits the workflow's memory needs and promotes to a larger one if a run runs out of memory. In `explicit` the workflow is pinned to a chosen set of GPU models. You can switch `gpu_mode` with a `PATCH` to the workflow (owner only); changing the specific set of GPUs an explicit workflow is pinned to is done by redeploying it. The GPU types currently available and their rates are on [runflow.io/pricing](https://www.runflow.io/pricing).
  </Accordion>

  <Accordion title="What are the exact per-GPU rates, and how much will a run cost?">
    Rates are per GPU second and depend on the GPU your run lands on. The authoritative, current rate card lives at [runflow.io/pricing](https://www.runflow.io/pricing); check there before sizing a budget. Total cost for a run is the GPU seconds it used multiplied by that GPU's rate, which is why a faster GPU is not always more expensive overall. To estimate your own workflow, run it once and read the cost and GPU seconds back from `GET /v1/runs/{id}`, then multiply by your expected volume.
  </Accordion>

  <Accordion title="If my run fails, am I still charged?">
    It depends on where it failed. If a worker picked up your run and then it failed during execution, or the worker was lost after claiming the job, you are billed for the GPU time that was actually consumed, because the platform pays its GPU provider for that time. Failures that happen before any worker starts (input validation, no compatible GPU available, or being rejected at admission for balance or pricing) are not charged. Cancelled runs are not charged.
  </Accordion>

  <Accordion title="Why was my run rejected before it even started?">
    Before dispatch, Runflow checks that your organization has a positive credit balance and that every GPU your run could land on has an active price. A non-positive balance is rejected with `402`. A workflow pinned to a GPU that is inactive or unpriced is rejected with `422`; redeploy it with an available GPU. These checks run before any work starts, so a rejected run is never charged.
  </Accordion>

  <Accordion title="Why is my first run after a quiet period slow (cold start)?">
    The platform keeps a deployed workflow's worker warm only while runs are arriving, then spins it down. The next run after an idle window pays a cold start while the worker boots and loads the model weights, and that startup time is part of the billed GPU wall-time. For latency-sensitive work, send a warming run on a schedule or keep the playground open during a session.
  </Accordion>

  <Accordion title="Where do I see the GPU seconds and cost for a run?">
    `GET /v1/runs/{id}` returns the cost and a cost breakdown for completed ComfyUI runs, including the GPU models used and the GPU seconds consumed per model. The webhook delivery payload does not carry cost — it has the run's `status`, `output`, and `duration_ms` — so call `GET /v1/runs/{id}` for the cost and the per-GPU breakdown. To attribute spend per pipeline, set a `metadata` object when you create the run; it is echoed back on both the webhook and the run record.
  </Accordion>

  <Accordion title="Is there a maximum run duration?">
    Yes. Runs are bounded by a platform execution-time cap; a run that hits it is stopped. Because billing meters only the GPU time actually consumed, a run stopped at the cap is billed for the GPU seconds it used up to that point. If a workflow legitimately needs a longer ceiling, contact Runflow.
  </Accordion>
</AccordionGroup>

## Limits and behavior

<AccordionGroup>
  <Accordion title="Can I use private or gated models, or private custom nodes?">
    A deployed workflow has to be reproducible on the worker, and Runflow enforces that when you run it, not when you deploy it. Deploy itself does not check reproducibility, so a non-reproducible workflow saves and deploys cleanly, then its first run is rejected with `422`. At run time Runflow rejects a custom node that has no pinned commit or whose origin is not `https://` (a short allowlist of Runflow-internal origins aside), and rejects a model with no `sha256` (the worker resolves model weights by that hash from its cache, so a public download URL is not required). ComfyUI itself must report an origin and commit. In practice this means public, pinned dependencies: a private repository the worker cannot clone fails the run. Local working-copy edits are recorded for audit but do not by themselves block a run.
  </Accordion>

  <Accordion title="My workflow runs locally but fails on Runflow. Why?">
    The worker does not have your local-only models or custom nodes. Click **Auto setup** locally first to confirm the workflow resolves all of its dependencies (only on workflows you trust, since Auto setup runs `git clone` and `pip install` from URLs declared by the workflow). Models declared as download URLs in the workflow's `properties.models` deploy without a local copy, but each still needs a `sha256` to run: a URL-only entry with no hash is rejected at run time with an `invalid_sha` error. Widget-selected models must exist locally or carry a URL fallback, and likewise need a `sha256`.
  </Accordion>

  <Accordion title="Is it safe to redeploy while runs are in flight?">
    Yes. Redeploy replaces the workflow in place under the same slug. Each run snapshots the workflow at the moment it is created, and that snapshot is what executes, so a run already in flight is unaffected by a redeploy that lands while it is running.
  </Accordion>

  <Accordion title="Is my deployed workflow private, or can other people see and run it?">
    Workflows are private to your organization by default (`is_public` is `false` on create). A private workflow's graph and endpoint are not visible or runnable by other organizations. Making a workflow public lets anyone who has its exact owner and slug load and run it by direct link, but it does not appear in Runflow's browseable catalog unless the Runflow team approves it for listing. Either way, callers still need their own beta access and credits to run it.
  </Accordion>

  <Accordion title="Are there rate limits?">
    Yes. The API applies a request-rate limit; if you exceed it, calls return `429` with the error code `RATE_LIMITED`. Retry with backoff (exponential backoff is a safe default). Separately, when all suitable GPU workers are busy, a dispatched run waits in `queued` until one frees up rather than being rejected. See [Rate limits](/concepts/rate-limits) for more, and use the contact link there if you need a higher limit.
  </Accordion>

  <Accordion title="Can I cancel a run that is already in progress?">
    Not in the current version. There is no customer-facing way to cancel an in-progress ComfyUI run today; runs end on their own when they complete, fail, or hit the maximum duration.
  </Accordion>

  <Accordion title="How do I keep my own ComfyUI server secure?">
    ComfyUI ships with no authentication, and custom nodes can run arbitrary code on the host, so a ComfyUI port reachable from the public internet is a real risk. The Runflow settings panel has two controls for this: **password authentication** and a **port exposure scan** that reports your listen binding and checks whether your ports are reachable from the internet. Password auth takes two steps: set a username and password, *and* turn on the **Enable password authentication** toggle, which is off by default. Only with the toggle on and both fields set does the plugin require HTTP Basic auth on every request; a username and password alone leave the server open. If a port is open, enable password auth (toggle included), put ComfyUI behind a firewall or an authenticated proxy, or bind to localhost only.

    <Warning>
      The port exposure scan sends your public IP address to a third-party service (portchecker.io) so it can probe your ports from outside. No workflow data is sent.
    </Warning>
  </Accordion>
</AccordionGroup>

## Getting help

<AccordionGroup>
  <Accordion title="I'm stuck or think I found a bug. Where do I get help?">
    The main place to reach us is the [Runflow Discord community](https://discord.gg/Vm6ardjC7T). For bugs in the ComfyUI-Runflow plugin (the node package) you can also open an issue on [GitHub](https://github.com/runflow-io/ComfyUI-Runflow/issues), and for account or billing questions you can [talk to the team](https://cal.com/team/runflow/talk-to-founders). Including your organization slug, the endpoint slug, and a run id (when a specific run is involved) helps us respond faster.
  </Accordion>
</AccordionGroup>

## Related

<CardGroup cols={2}>
  <Card title="Deploy a ComfyUI workflow" icon="rocket" href="/guides/comfyui-deploy">The full install, configure, deploy, and call walkthrough.</Card>
  <Card title="ComfyUI workflows API" icon="code" href="/api/comfyui-workflows">The REST surface: dispatch, manage, inputs and outputs.</Card>
  <Card title="Runs" icon="play" href="/concepts/runs">Run lifecycle, polling, and callbacks.</Card>
  <Card title="Pricing" icon="dollar-sign" href="https://www.runflow.io/pricing">The current GPU rate card.</Card>
</CardGroup>
