Comfy Router is not generally available yet. The routes below —
POST /v1/models/{provider}/{model} and its catalog and schema siblings — are
not serving requests yet: an authenticated call answers 404 today. This page
documents the contract they will serve, and is published ahead of that rollout so
the integration is ready to write against. It is not a description of behaviour
you can exercise right now.https://api.comfy.org. The route is POST /v1/models/{provider}/{model}, the request body is the model’s own native JSON input, and a 200 carries the model’s own native JSON output. Router does not wrap either, so a call you already have written against the partner’s API becomes a Router call by changing the host.
Why this page uses bfl/flux-2-pro
bfl/flux-2-pro returns in about 3.1s at p50, which is the fastest measured path on the Router and is what makes a five-minute first result realistic — a slower model would spend that budget waiting rather than reading.
It is a convenience, not a requirement. Every other model on the Router is called exactly the same way: same route, same credential header, same error buckets, same X-Comfy-Request-Id. Only the model ID, the fields inside the request body, and the shape of the result you read back change. Gemini, for instance, clears comfortably at 72.8s p95 — Router holds the connection for the whole generation rather than returning a job handle to poll. There is no edge ceiling cutting a long call short, but Router does bound the call itself: its own server deadline (10 minutes by default) is the longest it will hold a connection, after which it answers 504 / deadline_exceeded and does not bill. Swap the ID and read that model’s fields from its own schema (below).
Get a key
Router authenticates with a Comfy API key. Create one at platform.comfy.org/profile/api-keys, then put it in the environment — both samples below readCOMFY_API_KEY and neither takes a key as a literal, so a copy-pasted snippet cannot carry your credential into a commit.
401 with X-Comfy-Error-Type: unauthorized; one whose workspace cannot run the model comes back 403 / forbidden.
Python
Requires Python 3.9+ andhttpx:
quickstart.py and run it with python quickstart.py:
TypeScript
Requires Node 18+ (for built-infetch, AbortSignal.timeout and crypto.randomUUID) and tsx to run TypeScript directly:
quickstart.mts — the .mts extension is load-bearing, because the file uses top-level await and that needs an ES module — and run it with npx tsx quickstart.mts:
Reading the 422
The 422 is the one error worth understanding before your first real call, because it is the one you cause. It means Router checked your body against the model’s own input schema and rejected it — a required field missing, a value outside a bound, an image too small. That check runs BEFORE any provider call, so a 422 costs nothing: no partner spend, no billing question to answer afterwards. It is not the same as a 400, which is a request-level failure (a malformed cursor, an unreadable envelope) rather than a per-field one.
Its body is the fal/FastAPI detail[] shape: an array with one entry per offending field, each keeping its own loc (the path to the field), msg, type (the specific, provider-level reason — missing, value_error, image_too_small) and, where the reason carries a bound, ctx. That per-field granularity is why the samples above keep the array as data instead of flattening it into the exception message.
A model whose input schema has not been authored yet resolves to a documented
permissive fallback that admits any JSON object, so it will forward a body
rather than answer
422. The samples above show the shape you handle once a
schema exists; treat the 422 block as the error path, not as a guaranteed
response to that particular body.error_type field of its own, so on a 422 the X-Comfy-Error-Type header is the only machine-readable bucket. Both samples read the bucket from the header first for exactly that reason, which is also what makes one error class enough to cover every failure Router can return.
X-Comfy-Request-Id is on every response — success, 4xx and 5xx alike — and is the id to quote in a support request. Both samples attach it to the exception rather than making you re-run with header logging on to find it.
Where the model’s fields come from
prompt is the only field bfl/flux-2-pro requires; width, height, seed and output_format are the ones you will reach for next. Rather than reproducing a field list that can drift, read the model’s schema live:
/openapi.json to its invocation path, and generate against what comes back.
Next
- Comfy Router API reference — every endpoint, every parameter, and all fourteen error buckets.
- Comfy Router limitations — what Router does not do today, and what to use instead.