List jobs, newest first
Lists jobs newest first. At a deployment's address, the jobs sent to
List jobs, newest first
Lists jobs newest first. At a deployment's address, the jobs sent to
that deployment; at the workspace address, every job in the caller's workspace. A caller never sees another workspace's jobs.
Filter by your own labels with metadata[<key>]=<value>, up to 3 times; a job is listed only when every pair matches exactly. A 4th filter, a repeated key, a key outside the key rule, or a value with a character no label may hold (a control character or a bidirectional embedding, override or isolate, as on submit) is refused 400 invalid_metadata_filter. A filter value must be URL-encoded; a raw ; or a bad % escape answers 400 invalid_metadata_filter.
Pages: pass the response's next_cursor back as cursor, with the same filters, to read the next page. next_cursor is absent on the last page. Each job appears once across the pages.
List items are a job's stored record, not the Job object: they carry no outputs and no urls. Read a job with GET /api/v2/jobs/{id} for its outputs.
Only the serverless platform lists jobs today. Comfy Cloud answers 501 not_implemented.
OpenAPI
````yaml /openapi-v2.yaml get /api/v2/jobs openapi: 3.0.3 info: title: Comfy API v2 version: 2.0.0
description: |
The official, versioned HTTP API for running ComfyUI workflows from external applications: upload inputs, submit a workflow, observe execution, retrieve results.
Design principles:
- Poll-first. Every capability is reachable via plain GET polling; the SSE stream is a live enhancement, never the source of truth.
- Everything is resumable. Submission is idempotent; job state and outputs are retrievable by ID until
expires_at. - UUID identity, content-addressed dedup. Assets are UUID-identified records over blobs keyed by a server-computed blake3 hash. The hash is nullable and may be computed lazily.
- Follow links, don't build URLs. Responses embed follow-up URLs.
Additive changes only within v2; breaking changes require v3. servers:
- url: http://127.0.0.1:8189 description: Self-hosted (comfy-api-proxy)
- url: https://cloud.comfy.org description: Comfy Cloud
- url: https://{deployment}.run.comfy.app description: Serverless deployment variables: deployment: description: >- DNS-safe deployment id (subdomain label). Staging uses {deployment}.stg.run.comfy.app. default: dep-1234abcd-56ef-7890-abcd-ef1234567890 security:
- bearerAuth: []
- {} tags:
- name: assets description: UUID-identified records over content-addressed blobs.
- name: jobs description: One execution of a workflow — durable, pollable, cancelable. paths: /api/v2/jobs: get: tags:
- jobs summary: List jobs, newest first description: | Lists jobs newest first. At a deployment's address, the jobs sent to that deployment; at the workspace address, every job in the caller's workspace. A caller never sees another workspace's jobs.
Filter by your own labels with metadata[<key>]=<value>, up to 3 times; a job is listed only when every pair matches exactly. A 4th filter, a repeated key, a key outside the key rule, or a value with a character no label may hold (a control character or a bidirectional embedding, override or isolate, as on submit) is refused 400 invalid_metadata_filter. A filter value must be URL-encoded; a raw ; or a bad % escape answers 400 invalid_metadata_filter.
Pages: pass the response's next_cursor back as cursor, with the same filters, to read the next page. next_cursor is absent on the last page. Each job appears once across the pages.
List items are a job's stored record, not the Job object: they carry no outputs and no urls. Read a job with GET /api/v2/jobs/{id} for its outputs.
Only the serverless platform lists jobs today. Comfy Cloud answers 501 not_implemented. operationId: listJobs parameters:
- name: limit in: query required: false description: >- Most jobs per page. Above 500 is read as 500; absent means 500. Not a positive integer:
422invalid_request. schema: type: integer minimum: 1 - name: cursor in: query required: false description: >- The previous page's
next_cursor, unchanged. Opaque: do not build or edit one. A cursor that is not well-formed is refused400invalid_cursor. Cursors are not signed, so a well-formed one is read as a position whether or not this list issued it. schema: type: string - name: metadata in: query required: false style: deepObject explode: true description: >- Exact-match label filters, written
metadata[client]=acme. Up to 3; all must match. schema: type: object maxProperties: 3 additionalProperties: type: string example: client: acme responses: '200': description: One page of jobs, newest first. content: application/json: schema: $ref: '#/components/schemas/JobList' '400': description: 'invalid_metadata_filterorinvalid_cursor.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '404': description: >-not_found: on a deployment's address, no deployment there that the caller's workspace owns. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '422': description: 'invalid_request:limitis not a positive integer.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '429': $ref: '#/components/responses/RateLimited' '500': $ref: '#/components/responses/UpstreamError' '501': description: 'not_implemented: this surface does not list jobs yet.' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' '503': $ref: '#/components/responses/DeploymentLookupUnavailable' components: schemas: JobList: type: object description: One page ofGET /api/v2/jobs. required: - jobs properties: jobs: type: array items: $ref: '#/components/schemas/JobListItem' next_cursor: type: string description: Pass as
cursorto read the next page. Absent on the last page. ErrorEnvelope: type: object description: | Shared error envelope with machine-readable codes. Core codes (v1):invalid_workflow(422),workflow_format_ui(422),missing_asset(422),hash_mismatch(409),blob_not_found(404),idempotency_key_reuse(422),upload_timed_out(422: an asset upload stopped sending or was too slow; retry from a faster connection),queue_full(429 + Retry-After),rate_limited(429 + Retry-After: the caller is past a request rate limit; retry),insufficient_credits(402),not_found(404),unauthorized(401),forbidden(403). Deployment-scoped surfaces add:deployment_not_ready(429 + Retry-After — the deployment can still reach ready; retry),deployment_unavailable(429 + Retry-After: the deployment is ready but its GPU provider is not taking work on it yet; retry),deployment_lookup_unavailable(503 + Retry-After, on any operation: the deployment the address names could not be looked up just now; nothing was done, so retry),database_unavailable(503 + Retry-After, only on a job submit: the job could not be saved just now and nothing was started, so retry),auth_unavailable(503 + Retry-After, on any operation: the credential could not be checked just now, which says nothing about the credential, so retry),output_unavailable(503 + Retry-After, only on a job status read: an output of the job could not be prepared just now; the job is unchanged, so retry afterRetry-After, and report the job if it keeps answering),deployment_stopped(422 — terminal deployment state; a retry cannot succeed without operator action),invalid_request(422: a malformed asset upload or asset-from-hash field, or a jobs-listlimitthat is not a positive integer),validation_error(422, Cloud: an asset upload or asset-from-hash field was refused, e.g. a tag over the tag limits),content_blocked(451: content moderation flagged the asset's bytes) andsso_required(403: the key is valid, but the account must sign in through its organization's single sign-on, which does not accept this key). Comfy Cloud's asset upload addsinvalid_content_type(422: the request is notmultipart/form-datawith a boundary),invalid_body(422: a malformed multipart body or upload field),validation_error(422: the platform refused the upload, for example an image over the size cap or a disallowed tag) andupload_busy(503 + Retry-After: the server is busy with other uploads and nothing was stored, so retry). Job labels add:metadata_invalid(422: a submittedmetadatabreaks a limit;details.keynames the key, except for too many pairs, which has nodetails),metadata_not_supported(422: this surface keeps no job labels yet),invalid_metadata_filter(400) andinvalid_cursor(400). A surface that does not list jobs yet answersnot_implemented(501). A 429 is disambiguated byerror.codealone; clients should treat any 429 + Retry-After as "back off and retry". required: - error properties: error: type: object required:
- code
- message properties: code: type: string example: invalid_workflow message: type: string example: 'Node 12 (KSampler): required input ''model'' is not connected' organization_id: type: string description: >- On
sso_required: the organization whose single sign-on governs this key, the one that holds the account, else the one that holds the key's workspace. It is theorganizationquery parameter of Comfy Cloud's single sign-on start; treat it as opaque. Absent when the organization is unknown, and on every other code. example: org_01HXYZEXAMPLE details: type: object nullable: true additionalProperties: true description: >- Machine-readable detail for the code. When it carriesnode_errors, that is keyed by node id and each value is aJobNodeError, the same shape as a job'serror.node_errors, whether the refusal came at submit (for exampleunknown_node_class, a node class the deployment's build does not contain) or from ComfyUI after dispatch. Withunknown_node_classerrors it carriesunknown_node_classes, the missing classes; withwaits_for_browsererrors,browser_wait_node_classes, the classes that wait for a browser. A submit refusal names at most fifty nodes. Forinvalid_node,invalid_inputsandinvalid_class_type, when it found more than fifty,node_errors_truncatedis true andmalformed_node_countcarries the full count; forwaits_for_browser,browser_wait_node_countdoes. Forunknown_node_classit names only nodes whose class is one of the at most ten listed inunknown_node_classes; when those nodes number more than fifty,node_errors_truncatedis true andunknown_node_countis how many nodes have a listed class. Nodes whose class is past those ten are neither named nor counted. example: node_errors: '12': class_type: SomeCustomNode errors: - type: unknown_node_class message: >- this deployment's build does not contain the node class SomeCustomNode. unknown_node_classes:
- SomeCustomNode JobListItem: type: object description: >- A job's stored record. The fields below are stable; an item may carry more, which a client should ignore rather than rely on. required:
- id
- status
- create_time
- update_time additionalProperties: true properties: id: type: string example: 7f3d2c1b-9a8e-4d6f-b012-3c4d5e6f7a8b status: $ref: '#/components/schemas/JobStatus' create_time: type: string format: date-time update_time: type: string format: date-time release_version: type: integer minimum: 1 description: >- The version of the release that ran the job. Absent where the serving surface does not report it or could not look it up at the time of the answer. example: 3 metadata: $ref: '#/components/schemas/JobMetadata' JobStatus: type: string enum:
- queued
- running
- succeeded
- canceling
- canceled
- failed
- expired description: | Lifecycle: queued → running → succeeded | failed | expired; a cancel request, or the deletion of the deployment the job is running on, moves running → canceling → canceled. Terminal states: succeeded, canceled, failed, expired. JobMetadata: type: object description: >- The labels the job was submitted with, exactly as sent. Absent when it was sent with none. additionalProperties: type: string example: client: acme responses: Unauthorized: description: >-
unauthorized: missing or invalid credentials. A credential that could not be checked answersauth_unavailable(503) instead. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' Forbidden: description: >-forbidden— authenticated but not allowed. On a serverless deployment, alsosso_required— the key is valid, but the account must sign in through its organization's single sign-on, which does not accept this key; it can come back on any operation. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' RateLimited: description: >-rate_limited— the caller has exceeded a request rate limit for this account. Account/rate-scoped, not resource-specific — this can be returned even for a job, asset or deployment the caller doesn't own or that doesn't exist. headers: Retry-After: $ref: '#/components/headers/RetryAfter' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' UpstreamError: description: >-upstream_error— an unexpected failure reaching or processing the request in this implementation's backing services. The message is always a generic, safe-to-display string; implementation detail (the specific upstream, its error text, transport failures) is never included here — see each implementation's own error-mapping notes. Every operation in this contract can fail this way. content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' DeploymentLookupUnavailable: description: >- On deployment-scoped surfaces,deployment_lookup_unavailable: the deployment this address names could not be looked up just now. The request was refused before it did anything (nothing was created, read, changed or canceled), so the same request can be sent again afterRetry-After. Every operation at a deployment's address can answer this way. A job submit can also answer this 503 withdatabase_unavailable: the job could not be saved just now and nothing was started, so the same request can be sent again afterRetry-After. No other operation answersdatabase_unavailable. On Comfy Cloud an asset upload can also answer this 503 withupload_busy: the server is busy with other uploads and nothing was stored, so the same upload can be sent again afterRetry-After. Any operation can also answer this 503 withauth_unavailable: the credential could not be checked just now, so the same request can be sent again afterRetry-After. A job status read can also answer it withoutput_unavailable: an output of the job could not be prepared just now, and the job is unchanged. A transient storage failure clears on a later read afterRetry-After; an output whose stored address is broken answers it on every read until the platform repairs the output. headers: Retry-After: $ref: '#/components/headers/RetryAfter' content: application/json: schema: $ref: '#/components/schemas/ErrorEnvelope' headers: RetryAfter: schema: type: integer description: Seconds to wait before retrying. securitySchemes: bearerAuth: type: http scheme: bearer description: >-Authorization: Bearer <credential>. The credential is one of: an account-scoped API key (comfyui-…), accepted on Cloud and serverless; a Comfy Cloud session JWT; or an OAuth access token issued for the Comfy Cloud resource. Which kinds a given deployment accepts is deployment configuration — an API key always works on Cloud and serverless, and a deployment that does not accept JWT bearers answers401with a message saying so. Self-hosted accepts unauthenticated requests by default and can be configured with a static bearer token.
````