> ## 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.

# Mint an asset over existing bytes (dedup fast-path)

> Zero-byte fast-path: mints a new asset UUID over a blob the platform
already has, identified by its blake3 hash.

Trust boundary: resolves only against blobs the platform itself
ingested and hashed, and only those the calling account is authorized
to use — the client hash is a lookup key, never an authority to
register new content. A miss and "exists but not yours" are
deliberately indistinguishable (`404` `blob_not_found`).




## OpenAPI

````yaml /openapi-v2.yaml post /api/v2/assets/from-hash
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/assets/from-hash:
    post:
      tags:
        - assets
      summary: Mint an asset over existing bytes (dedup fast-path)
      description: |
        Zero-byte fast-path: mints a new asset UUID over a blob the platform
        already has, identified by its blake3 hash.

        Trust boundary: resolves only against blobs the platform itself
        ingested and hashed, and only those the calling account is authorized
        to use — the client hash is a lookup key, never an authority to
        register new content. A miss and "exists but not yours" are
        deliberately indistinguishable (`404` `blob_not_found`).
      operationId: assetFromHash
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - hash
              properties:
                hash:
                  type: string
                  example: blake3:9f8a1c0d...
                file_path:
                  type: string
                  example: photo.png
                tags:
                  type: array
                  items:
                    type: string
                expires_in:
                  type: integer
                  minimum: 60
                  maximum: 604800
                  description: >-
                    Optional retention override in seconds (60s–7d): the asset's
                    `expires_at` becomes now + `expires_in`, replacing the
                    platform's default retention. Implementations without
                    configurable retention ignore it. The bounds apply to this
                    override only — the platform default is operator-configured
                    and may lie outside them.
                  example: 86400
      responses:
        '200':
          description: An identical reference already existed; returned as-is.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Asset'
        '201':
          description: Asset minted over the existing blob.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Asset'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          description: '`blob_not_found` — no blob the caller may mint from.'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '422':
          description: >-
            `invalid_request` on a deployment: the `file_path`, `tags` or
            `expires_in` is malformed.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorEnvelope'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/UpstreamError'
components:
  schemas:
    Asset:
      type: object
      description: >-
        A user-owned record identified by a server-assigned UUID, backing an
        immutable blob whose content carries a server-computed blake3 hash.
        `hash` may be computed lazily: an asset record (and its retrievable
        bytes) can exist before its hash is filled in.
      required:
        - id
        - hash
        - size_bytes
        - content_type
        - created_at
        - url
        - url_expires_at
      properties:
        id:
          type: string
          example: 9f8a1c0d-2b3e-4f56-8a7b-1c2d3e4f5a6b
        hash:
          type: string
          nullable: true
          description: '`blake3:<hex>`; null while lazily computed.'
          example: blake3:9f8a1c0d...
        size_bytes:
          type: integer
          format: int64
          example: 4816293
        content_type:
          type: string
          example: image/png
        file_path:
          type: string
          nullable: true
          example: photo.png
        created_new:
          type: boolean
          description: >-
            On create responses: distinguishes a brand-new blob (true) from a
            dedup hit against bytes the platform already had (false).
        created_at:
          type: string
          format: date-time
        url:
          type: string
          format: uri
          description: Short-lived content URL (signed, or proxy-served).
        url_expires_at:
          type: string
          format: date-time
        expires_at:
          type: string
          format: date-time
          nullable: true
          description: >-
            Retention deadline for the asset itself (distinct from
            `url_expires_at`, the signed URL's validity). Null or absent means
            the asset is non-expiring. On a dedup-hit create response the
            deadline may be later than now + the requested/default retention:
            re-referencing content extends its retention, never shortens it.
        job_id:
          type: string
          nullable: true
          description: >-
            ID of the job that produced this asset. Absent for uploaded assets,
            which have no producing job.
    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), `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_stopped` (422 — terminal deployment state; a retry

        cannot succeed without operator action), `invalid_request` (422:

        a malformed asset upload or asset-from-hash field), `content_blocked`
        (451:

        content moderation flagged the asset's bytes) and `sso_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). 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
              description: >-
                Machine-readable detail for the code. When it carries
                `node_errors`, that is keyed by node id and each value is a
                `JobNodeError`, the same shape as a job's `error.node_errors`,
                whether the refusal came at submit (for example
                `unknown_node_class`, a node class the deployment's build does
                not contain) or from ComfyUI after dispatch.
              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
  responses:
    Unauthorized:
      description: '`unauthorized` — missing or invalid credentials.'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorEnvelope'
    Forbidden:
      description: >-
        `forbidden` — authenticated but not allowed. On a serverless deployment,
        also `sso_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'
  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 answers `401` with a message
        saying so. Self-hosted accepts unauthenticated requests by default and
        can be configured with a static bearer token.

````

This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.