https://api.comfy.org
Every endpoint below is authenticated. Send X-API-Key: <api-key> or Authorization: Bearer <jwt>.
Comfy API keys can also be sent as Bearer tokens. X-API-Key takes precedence when both credential headers are supplied. See authentication headers for the key/JWT distinction and the Quickstart for access requirements.
Endpoints
GET /v2/models
List the models Comfy Router can run.
List available model IDs and billing facts. Use next_cursor while has_more is true.
Parameters
Responses
GET /v2/models/{provider}/{model}
Read one partner model’s catalog entry by canonical model ID.
Read details for one model without listing the full catalog.
Parameters
Responses
POST /v2/models/{provider}/{model}
Run a partner model synchronously by canonical model ID.
Run a model and receive its finished result in the same response.
Parameters
Request body
application/json — RouterModelInput (required)
The partner model’s native JSON input, forwarded to the provider unchanged.
Responses
GET /v2/models/{provider}/{model}/openapi.json
Read one partner model’s input and output schemas as an OpenAPI document.
Read one model’s input and output schemas as a standalone OpenAPI document.
Parameters
Responses
POST /v2/models/{provider}/{model}/requests
Submit a partner model run to the queue and return immediately.
Comfy Router’s QUEUED delivery mode. The request body is the same partner-native JSON input POST /v2/models/{provider}/{model} accepts for this model - one body shape, one per-model schema, two delivery modes - but this route does NOT hold the connection for the result. It admits the run, answers 201 with a handle, and the caller collects the result later through the three reads below.
Parameters
Request body
application/json — RouterModelInput (required)
The partner model’s native JSON input, identical to the body the synchronous route accepts for this model. Validated against the model’s own input schema BEFORE the run is admitted, so a body the model would reject is a 422 here rather than a queued request that fails minutes later.
Responses
GET /v2/models/{provider}/{model}/requests/{request_id}
Collect the result of one submitted request.
The collect endpoint. On a request that has finished successfully it returns the partner model’s OWN native output, byte for byte what the synchronous route’s 200 carries for the same model and the same input - so the two delivery modes produce one result shape and a caller can move between them without a second parser.
Parameters
Responses
PUT /v2/models/{provider}/{model}/requests/{request_id}/cancel
Ask for one submitted request to be cancelled.
Asks Comfy to stop a request that has not finished. It is a REQUEST, not a guarantee, and the 202 says exactly that: CANCELLATION_REQUESTED means the ask was accepted, not that the run has stopped. A run already on the wire at a partner may complete anyway - and a partner generation that completes is charged, whether or not anyone collected it - so a caller who needs to know what actually happened reads the status endpoint afterwards, where a cancellation that took effect is COMPLETED carrying an error_type like every other terminal outcome.
Parameters
Responses
GET /v2/models/{provider}/{model}/requests/{request_id}/status
Read the queue state of one submitted request.
The poll endpoint. It answers with the request’s current state and never with the result, so a client can watch a long generation without transferring its output on every poll - the result is collected once, from the read below, when this says COMPLETED.
Parameters
Responses
Table descriptions are brief. Use Using the Comfy Router API for model selection, validation, retries, and billing, and Headers for header behavior.
Error buckets
Machine-readable Router error category, also sent in theX-Comfy-Error-Type header.
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
Result assets
A model can return asset URLs, inline bytes, or both. The providers below copy selected assets onto Comfy storage and replace their URLs. This behavior depends on the model; there is no request header that selects it.
These lifetimes start when the URL is signed, not when you open it. Cached or replayed URLs can have less time remaining; replay does not renew them. Download the asset promptly. Only the assets named in each row are copied:
byteplus/seedream-* and byteplus/seededit-* images are not covered by the BytePlus video row.
Veo (veo/*) has a separate storage path. In response.videos[], read whichever member is present: bytesBase64Encoded contains the clip inline, while gcsUri contains a Comfy-signed HTTPS link when the environment is configured for direct provider writes to Comfy storage. That link is valid for 24 hours from the response. The latter case writes the asset directly rather than copying it, so Veo is not in the rehosting table.
Other models return provider asset references or inline bytes. Provider URLs follow the provider’s expiry, which can be much shorter than the lifetimes above and is not specified by the Router contract.
Copying is best effort per asset. If one copy fails, that entry keeps its provider reference; the response can contain both Comfy and provider URLs, with no explicit per-asset copy-status field. The generation still succeeds and is charged. Do not infer every URL’s lifetime from one successfully rehosted asset.
Whether a result is Comfy-hosted also decides whether a completed call can still be replayed from its Idempotency-Key record later; the Idempotency-Key parameter above says what a retry is answered with when it cannot be.
Per-model input and output schemas
Read each model’s fields fromGET /v2/models/{provider}/{model}/openapi.json. The operation’s requestBody describes input validation; its 200 response describes the output shape and media type when authored. When x-comfy-input-schema-authored is false, Router accepts any JSON object without model-specific prevalidation. Provider requirements still apply. The output schemas describe results; Router does not validate returned provider payloads against them. An unauthored output may use */* rather than application/json; inspect the response content type before decoding it.
Schemas
RouterChargesOnPolicyRejection
Whether a content-policy refusal is charged for this model. Treat an unknown value as potentially charged. Type:string
RouterErrorResponse
Error body for authentication, access, model lookup, quota, and provider transport failures.RouterErrorType
Machine-readable Router error category, also sent in theX-Comfy-Error-Type header.
Type: string
RouterModelBilling
Billing behavior to check before invoking a model. It does not include prices or usage.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
Optional fields returned by the model-details endpoint.RouterModelId
The model ID used inPOST /v2/models/{provider}/{model}.
Type: string — Model ID, e.g. anthropic/claude-opus-4-6, Up to 193 characters
RouterModelInput
The model input object. Read the selected model’s OpenAPI document for fields and validation. Type:object
RouterModelInputSchemaDocument
A standalone OpenAPI document for one model’s input and output. Type:object
RouterModelListEntry
A model’s ID and billing facts.RouterModelListResponse
One page of the Router model catalog.RouterModelOutput
The model result object. Read the selected model’s output schema for its exact shape. Type:object
RouterModelSegment
The model portion of a{provider}/{model} model ID.
Type: string — Alphanumeric slug, e.g. claude-opus-4-6, Up to 128 characters
RouterPageCursor
An opaque catalog cursor. Pass it back unchanged ascursor.
Type: string — Opaque cursor returned as next_cursor, 1–512 characters
RouterProviderSegment
The provider portion of a{provider}/{model} model ID.
Type: string — Alphanumeric slug, e.g. anthropic, Up to 64 characters
RouterQueueCancelResponse
The answer to a cancellation ask on the two statuses that describe a request this route resolved - the202 and the 400. One body shape across both rather than a success envelope plus an error envelope, because both are the same statement - what cancelling found - and a client that has to parse a different type per status code gains nothing from the split.
RouterQueueCancelStatus
What a cancellation ask found, for the two outcomes that describe a request this route actually resolved. Both are mirrored by the HTTP status, so a client may branch on either. Type:string
RouterQueuePosition
How many requests are ahead of this one in the queue, at the instant the response was composed. Zero means this request is at the front. Type:integer — At least 0
RouterQueueRequestId
Identifier of one queued Router request - the handle a caller polls, cancels and collects a result by. Type:string — pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$, uuid, Up to 36 characters
RouterQueueStatus
The state of a queued Router request. EXACTLY THREE VALUES, and unlikeRouterErrorType this one IS a closed enum, because the two schemas are closed in opposite directions on purpose. RouterErrorType classifies failures and its set is expected to grow, so a generated client that hard-rejected an unrecognised bucket would fail hardest exactly when something had already gone wrong. This one is a lifecycle, and a lifecycle with a fourth state added later is a breaking change to every polling loop written against it whether it is declared as an enum or not - so it is declared as one, and the constraint is stated where a client can see it.
Type: string
RouterQueueStatusFields
The half ofRouterQueueStatusResponse that is not the URL block: one queued request’s identity, its current state, and - when that state is terminal and the run did not succeed - the coarse bucket saying why.
RouterQueueStatusResponse
One queued request’s current state, composed with the same three URLs the submission returned. ComposesRouterQueueUrls, RouterQueueStatusFields.
Type: object
RouterQueueSubmitFields
The half ofRouterQueueSubmitResponse that is not the URL block: the new request’s identity and its state at the instant it was admitted.
RouterQueueSubmitResponse
The handle returned when a run is admitted to the queue: the request’s identity and state, composed with the three URLs that address the rest of its lifetime. ComposesRouterQueueUrls, RouterQueueSubmitFields.
Type: object
RouterQueueUrls
The three URLs that address the rest of one queued request’s lifetime, returned on every response that carries a live handle so a client never composes a queue URL itself.RouterValidationErrorContext
Provider-supplied details about the validation rule that failed. Type:object
RouterValidationErrorDetail
One field-level validation failure.RouterValidationErrorInput
The rejected input value, when the provider includes it.RouterValidationErrorResponse
The422 validation error body. Read X-Comfy-Error-Type for its category.