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

# Job status (the polling workhorse)

> Returns the full job object: current status, the latest progress
snapshot, and every output committed so far (`outputs` populates
incrementally while the job runs). This is the authoritative,
resumable view of a job; everything on the SSE stream is derived
from it.




## OpenAPI

````yaml /openapi-v2.yaml get /api/v2/jobs/{id}
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}.comfy.org
    description: Serverless deployment (URL shape not final)
    variables:
      deployment:
        default: my-deployment
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/{id}:
    get:
      tags:
        - jobs
      summary: Job status (the polling workhorse)
      description: |
        Returns the full job object: current status, the latest progress
        snapshot, and every output committed so far (`outputs` populates
        incrementally while the job runs). This is the authoritative,
        resumable view of a job; everything on the SSE stream is derived
        from it.
      operationId: getJob
      parameters:
        - $ref: '#/components/parameters/JobId'
      responses:
        '200':
          description: The job.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Job'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/UpstreamError'
components:
  parameters:
    JobId:
      name: id
      in: path
      required: true
      schema:
        type: string
      example: job_01JZTGXW9Q2M4R8V0B1N3P5D7F
  schemas:
    Job:
      type: object
      description: >-
        One execution of a workflow. Durable from creation until `expires_at`;
        `outputs` populates incrementally during execution.
      required:
        - id
        - status
        - created_at
        - started_at
        - completed_at
        - expires_at
        - queue_position
        - progress
        - outputs
        - error
        - urls
      properties:
        id:
          type: string
          example: job_01JZTGXW9Q2M4R8V0B1N3P5D7F
        status:
          $ref: '#/components/schemas/JobStatus'
        created_at:
          type: string
          format: date-time
        started_at:
          type: string
          format: date-time
          nullable: true
        completed_at:
          type: string
          format: date-time
          nullable: true
        expires_at:
          type: string
          format: date-time
          description: Retention deadline — a platform property, not an API constant.
        queue_position:
          type: integer
          nullable: true
        progress:
          allOf:
            - $ref: '#/components/schemas/Progress'
          nullable: true
          description: The latest progress snapshot; same data the SSE stream pushes.
        outputs:
          type: array
          items:
            $ref: '#/components/schemas/Output'
        error:
          allOf:
            - $ref: '#/components/schemas/JobError'
          nullable: true
        metrics:
          type: object
          description: >-
            Values are nullable (a metric not yet available — e.g.
            `execution_ms` before a job starts running — is `null`, not
            omitted); the example below is deliberately all-non-null purely to
            work around a Spectral/nimma lint-tooling crash on a literal `null`
            inside a schema `example` combined with
            `additionalProperties.nullable: true` — the schema itself is
            unchanged and still allows null values at runtime.
          additionalProperties:
            type: integer
            nullable: true
          example:
            queue_ms: 9000
            execution_ms: 42000
        urls:
          $ref: '#/components/schemas/JobUrls'
    JobStatus:
      type: string
      enum:
        - queued
        - running
        - succeeded
        - canceling
        - canceled
        - failed
        - expired
      description: |
        Lifecycle: queued → running → succeeded | failed | expired;
        a cancel request moves running → canceling → canceled.
        Terminal states: succeeded, canceled, failed, expired.
    Progress:
      type: object
      description: >-
        Server-computed progress snapshot (node-count and sampler-step
        weighted). Complete per snapshot — one fully re-syncs a client.
      required:
        - value
        - nodes_done
        - nodes_total
      properties:
        value:
          type: number
          format: double
          minimum: 0
          maximum: 1
          description: Overall fraction, server-computed.
          example: 0.42
        nodes_done:
          type: integer
          example: 11
        nodes_total:
          type: integer
          example: 31
        current_node:
          type: string
          nullable: true
          example: '12'
        current_node_class:
          type: string
          nullable: true
          example: KSampler
        step:
          type: integer
          nullable: true
          example: 21
        steps:
          type: integer
          nullable: true
          example: 50
        message:
          type: string
          nullable: true
          example: KSampler 21/50
    Output:
      type: object
      description: >-
        A committed job output. Outputs are assets: `id` is the asset UUID,
        retrievable via GET /api/v2/assets/{id} for as long as the job is
        retained. `hash` is lazily computed and may be null on the retrieval hot
        path.
      required:
        - node_id
        - name
        - type
        - content_type
        - size_bytes
        - id
        - hash
        - url
        - url_expires_at
      properties:
        node_id:
          type: string
          example: '9'
        name:
          type: string
          example: ComfyUI_00001_.png
        type:
          $ref: '#/components/schemas/OutputType'
        content_type:
          type: string
          example: image/png
        size_bytes:
          type: integer
          format: int64
          example: 1848320
        id:
          type: string
          description: Asset UUID.
          example: asset_01JZV9R4N8...
        hash:
          type: string
          nullable: true
          description: '`blake3:<hex>`; null until lazily computed.'
        url:
          type: string
          format: uri
        url_expires_at:
          type: string
          format: date-time
    JobError:
      type: object
      description: Execution failure detail, carried in `job.error` (not an HTTP error).
      required:
        - code
        - message
      properties:
        code:
          type: string
          example: node_execution_error
        message:
          type: string
        node_id:
          type: string
          nullable: true
        class_type:
          type: string
          nullable: true
        traceback:
          type: string
          nullable: true
    JobUrls:
      type: object
      description: >-
        Embedded follow-up links — follow these, don't build URLs. A link is
        either an absolute URL or a host-relative reference (leading `/`) that
        already includes any prefix the serving surface is mounted under (e.g. a
        serverless gateway's `/deployment/{deployment_id}/api/v2`). Clients MUST
        resolve a host-relative link against the request origin (scheme +
        authority), never against a configured base URL — joining it to a base
        URL that carries the same mount prefix duplicates the prefix.
      required:
        - self
        - events
        - cancel
      properties:
        self:
          type: string
          format: uri-reference
        events:
          type: string
          format: uri-reference
        cancel:
          type: string
          format: uri-reference
    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),
        `queue_full` (429 + Retry-After), `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) and
        `deployment_stopped` (422 — terminal deployment state; a retry
        cannot succeed without operator action). A 429 is disambiguated
        by `error.code` alone; 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'
            details:
              type: object
              nullable: true
              additionalProperties: true
              example:
                node_errors:
                  '12':
                    - field: model
                      reason: missing_input
    OutputType:
      type: string
      enum:
        - image
        - video
        - audio
        - text
        - file
        - latent
      description: Normalized output kind — nothing silently dropped.
  responses:
    Unauthorized:
      description: '`unauthorized` — missing or invalid credentials.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Forbidden:
      description: '`forbidden` — authenticated but not allowed.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    NotFound:
      description: '`not_found`.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    RateLimited:
      description: >-
        `rate_limited` — the caller has exceeded the request rate limit for this
        account. Account/rate-scoped, not job-specific — this can be returned
        even for a job id the caller doesn't own or that doesn't exist, without
        revealing which.
      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'
  headers:
    RetryAfter:
      schema:
        type: integer
      description: Seconds to wait before retrying.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        `Authorization: Bearer <api-key>` — account-scoped API keys on Cloud and
        serverless. Self-hosted accepts unauthenticated requests by default and
        can be configured with a static bearer token.

````