https://api.comfy.org
Every endpoint below is authenticated. Send Authorization: Bearer <jwt>.
Endpoints
GET /v1/models
List the models Comfy Router can run.
Comfy Router’s model catalog - one page of the canonical model IDs that POST /v1/models/{provider}/{model} accepts. An SDK calls this on cold start to discover what is runnable, and the model_not_found suggestions come from the same catalog, so an ID listed here that then 404s on invocation would be worse than either failure alone. That agreement is structural rather than a promise: an entry’s provider and model are the two path segments of the invocation route and reference the SAME schema components that route’s path parameters do, and id is those two segments joined by /.
Parameters
Responses
GET /v1/models/{provider}/{model}
Read one partner model’s catalog entry by canonical model ID.
Per-model detail for a single Comfy Router model, so a caller can check one model without walking the whole paginated catalog. The SDKs use it to look a model up immediately before invoking it.
Parameters
Responses
POST /v1/models/{provider}/{model}
Run a partner model synchronously by canonical model ID.
Comfy Router’s canonical, model-ID-addressed entry point. The request body is the partner model’s OWN native JSON input and the success response is that model’s OWN native JSON output: Router forwards both unchanged instead of imposing a Comfy-shaped envelope, so a caller can move between the partner’s API and Router by changing the host. This is the SYNCHRONOUS path, mirroring POST https://fal.run/{id} - the response carries the finished result. A queued counterpart, /v1/queue/models/{provider}/{model}, is planned and would put fal’s fal.run / queue.fal.run split onto a single host; it is not part of this contract yet.
Parameters
Request body
application/json — RouterModelInput (required)
The partner model’s native JSON input, forwarded to the provider unchanged.
Responses
GET /v1/models/{provider}/{model}/openapi.json
Read one partner model’s input schema as an OpenAPI document.
The per-model input schema for a single Comfy Router model, served as a standalone OpenAPI document, so a caller - an SDK, a codegen tool, or an agent - can discover a model’s arguments without reading Comfy’s prose docs. It mirrors fal’s per-model schema endpoint, and it is the discovery mechanism the SDK quickstart depends on.
Parameters
Responses
Error buckets
Coarse, machine-readable bucket for a Router failure, mirrored on theX-Comfy-Error-Type response header so a caller can branch without parsing the body. The set is closed at fourteen values: the six request-level buckets invalid_input, content_policy_violation, provider_error, provider_timeout, insufficient_credits and model_not_found, plus the transport-level unauthorized, forbidden, concurrency_limit_exceeded, client_disconnected, internal_error, deadline_exceeded, not_enabled and service_unavailable.
Request-level buckets
Raised for a request Router accepted and then could not complete.Transport-level buckets
Raised by Router itself, before or around the call to the model.Response headers
Per-model input schemas
A model’s own input fields are not reproduced here. Read them live fromGET /v1/models/{provider}/{model}/openapi.json, which serves the same document the server validates the call against, so what is published and what is enforced cannot drift apart. Take a model ID from GET /v1/models, append /openapi.json to its invocation path, and generate against the document you get back.
Schemas
RouterChargesOnPolicyRejection
Whether a call this model REFUSES on content-policy grounds is nevertheless charged to the caller. Providers differ, the difference is invisible at call time, and a user who sees an error and a charge for the same call has no way to have known - so it is stated per model, before the call, rather than left to per-provider folklore. Type:string
RouterErrorResponse
Router’s request-level error body: what is returned when the request never reached the model, or failed for a reason the model itself did not report - auth, quota, an unknown model ID, or provider transport. A model-level validation failure has its own shape,RouterValidationErrorResponse, because flattening a FastAPI detail[] array into this detail string would destroy the per-field granularity an SDK branches on.
RouterErrorType
Coarse, machine-readable bucket for a Router failure, mirrored on theX-Comfy-Error-Type response header so a caller can branch without parsing the body. The set is closed at fourteen values: the six request-level buckets invalid_input, content_policy_violation, provider_error, provider_timeout, insufficient_credits and model_not_found, plus the transport-level unauthorized, forbidden, concurrency_limit_exceeded, client_disconnected, internal_error, deadline_exceeded, not_enabled and service_unavailable.
Type: string
RouterModelBilling
Per-model billing FACTS a caller needs before invoking - not prices. Usage and cost figures never appear here.RouterModelDetail
Per-model detail for one Comfy Router model: everything the catalog listing reports for it, plus the per-model fields that only the single-model route carries. ComposesRouterModelListEntry, RouterModelDetailFields.
Type: object
RouterModelDetailFields
The half ofRouterModelDetail the catalog listing does NOT carry: per-model fields worth one lookup but not worth repeating on every entry of a paginated catalog page.
RouterModelId
A canonical Comfy Router model ID,{provider}/{model} - exactly the value that addresses the model on POST /v1/models/{provider}/{model}, so a caller can interpolate it into that path without re-deriving it from anything. Its pattern is RouterProviderSegment and RouterModelSegment joined by a single /, and maxLength is their sum plus that separator.
Type: string — pattern: ^[a-z0-9]+([._-][a-z0-9]+)*/[a-z0-9]+([._-][a-z0-9]+)*$, maxLength: 193
RouterModelInput
A partner model’s native JSON input document, forwarded to the provider as-is. Its concrete shape is owned by the partner rather than by Comfy, so this is an open object: Router does not narrow, rename, or re-envelope the fields. It is a named component (never an inline anonymous object) because ComfyUI’s spec-driven codegen needs a class to generate. Type:object
RouterModelInputSchemaDocument
A standalone OpenAPI document describing ONE Comfy Router model’s input - the bodyPOST /v1/models/{provider}/{model} accepts for that model. It is what GET /v1/models/{provider}/{model}/openapi.json returns.
Type: object
RouterModelListEntry
One entry in the Router model catalog: the identity of a runnable model, and nothing else. The per-model detail route composes this same entry rather than restating it, which is why the name is...ListEntry and not ...Summary - there must be exactly one definition of what a catalog entry is. Per-model detail and the per-model input/output schemas are their own routes, so this shape stays the minimum a caller needs in order to invoke the model - deliberately, because this is the payload an SDK fetches on cold start. id is provider and model joined by /; the two fields are carried separately as well so a caller composes the invocation path without splitting a string.
RouterModelListResponse
One page of the Router model catalog.RouterModelOutput
A partner model’s native JSON output document, returned to the caller as-is. Its concrete shape is owned by the partner rather than by Comfy, so this is an open object: Router does not narrow, rename, or re-envelope the fields. It is a named component (never an inline anonymous object) because ComfyUI’s spec-driven codegen needs a class to generate. Type:object
RouterModelSegment
Lowercasemodel segment of the canonical {provider}/{model}[/{variant}] model ID - the model to run within that provider. Shared by the invocation route’s model path parameter and a catalog entry’s model field, for the same no-drift reason as RouterProviderSegment.
Type: string — pattern: ^[a-z0-9]+([._-][a-z0-9]+)*$, maxLength: 128
RouterPageCursor
An OPAQUE cursor into a Router list. It is produced by the server and only ever round-tripped: it is not an offset, not a model ID, not ordered, and not stable across catalog rebuilds, so parsing one, incrementing one, or persisting one beyond the walk it came from are all outside the contract. Cursor rather than offset because the catalog is a moving list - an offset walk silently skips or repeats entries when entries are added or removed mid-walk, and a caller cannot tell that it happened. Type:string — pattern: ^[A-Za-z0-9._~+/=-]+$, minLength: 1, maxLength: 512
RouterProviderSegment
Lowercaseprovider segment of the canonical {provider}/{model}[/{variant}] model ID - the partner whose model is being addressed. The invocation route’s provider path parameter and a catalog entry’s provider field both reference this one schema, which is what keeps the listed IDs and the accepted IDs from drifting apart.
Type: string — pattern: ^[a-z0-9]+([._-][a-z0-9]+)*$, maxLength: 64
RouterValidationErrorContext
The violated bound for oneRouterValidationErrorDetail, carried from the provider verbatim - for example {"limit_value": 8} alongside greater_than, {"min_width": 512} alongside image_too_small, or {"max_size_bytes": 10485760} alongside file_too_large. The key set is specific to the provider and the error type, so this is deliberately an open object: narrowing it to a fixed field list, or folding it into the msg string, is precisely how a ported integration compiles and then silently loses the branch that read the bound. Absent when the error type carries no bound.
Type: object
RouterValidationErrorDetail
One model-level validation failure, in the fal/FastAPI form.type carries the SPECIFIC provider reason - value_error, missing, image_too_small, unsupported_audio_format, greater_than, file_too_large and the rest - which is the granularity RouterErrorType’s coarse bucket cannot express. It is an open string and not an enum for the same reason: the provider vocabulary runs to roughly 48 values across two tiers and grows on the provider’s release cycle, not ours, and an unmodelled value must reach the caller rather than fail deserialization.
RouterValidationErrorInput
The offending input value, echoed back verbatim so a caller can see what was rejected without re-deriving it fromloc. Any JSON type - string, number, boolean, array, object or null - so this schema is deliberately left untyped rather than narrowed to an object. Absent when the provider does not echo the input back.
RouterValidationErrorResponse
Router’s model-level422 body, in the fal/FastAPI form: the request was well-formed enough to reach the model and the model rejected its contents. Note it carries no error_type of its own - that is what X-Comfy-Error-Type on the response is for, so a client can read the coarse bucket off the header without first deciding which of the two Router error bodies it received.