> ## Documentation Index
> Fetch the complete documentation index at: https://dripart-chore-mintlify-theme-mint.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Use Wan 3.0 Video with Comfy Router

> Python, TypeScript and cURL snippets for calling wan/wan3.0-video over HTTP through Comfy Router, plus the request fields and the result shape

API Reference for Wan 3.0 Video. Wan 3.0 Video generates from a prompt alone or from a media list of first and last frames, reference images, videos and audio, addressed in the prompt as Image 1, Video 1 and Audio 1.

## Quick start

Create a key in [your Comfy workspace](https://platform.comfy.org/profile/api-keys?onboarding=router) and export it as `COMFY_API_KEY`. The Python and TypeScript snippets use the Comfy SDKs (`pip install comfy-sdk` and `npm install @comfyorg/sdk`); the cURL snippet is the same call over raw HTTP.

**Model ID:** `wan/wan3.0-video`

**Endpoint:** `POST https://api.comfy.org/v2/models/wan/wan3.0-video`

<Tabs defaultTabIndex={1}>
  <Tab title="Wait for the result">
    <CodeGroup>
      ```python Python theme={null}
      import asyncio
      from comfy_sdk import AsyncComfy

      # Reads COMFY_API_KEY from the environment.
      # The SDK automatically creates an idempotency key and reuses it for automatic retries.
      async def main():
          async with AsyncComfy() as client:
              result = await client.models.run(
                  "wan/wan3.0-video",
                  {
                      "input": {
                          "prompt": "the robot lowers its raised arm and steps toward the camera, the flat orange backdrop holds steady",
                          "media": [
                              {
                                  "type": "first_frame",
                                  "url": "https://raw.githubusercontent.com/Comfy-Org/workflow_templates/main/input/pink_robot_front.png",
                              },
                          ],
                      },
                      "parameters": {
                          "resolution": "720P",
                          "duration": 5,
                      },
                  },
              )

          print("video:", result["output"]["video_url"])

      asyncio.run(main())
      ```

      ```typescript TypeScript theme={null}
      import { comfy } from "@comfyorg/sdk";

      // Reads COMFY_API_KEY from the environment.
      // The SDK automatically creates an idempotency key and reuses it for automatic retries.
      type Result = { output: { video_url: string } };
      const result = await comfy.models.run<Result>("wan/wan3.0-video", {
        input: {
          prompt: "the robot lowers its raised arm and steps toward the camera, the flat orange backdrop holds steady",
          media: [
            {
              type: "first_frame",
              url: "https://raw.githubusercontent.com/Comfy-Org/workflow_templates/main/input/pink_robot_front.png",
            },
          ],
        },
        parameters: {
          resolution: "720P",
          duration: 5,
        },
      });
      if (result.kind !== "json") throw new Error("expected a JSON result");

      console.log("video:", result.data.output.video_url);
      ```

      ```bash cURL theme={null}
      curl https://api.comfy.org/v2/models/wan/wan3.0-video \
        -H "X-API-Key: $COMFY_API_KEY" \
        -H "Idempotency-Key: $(uuidgen)" \
        -H "Content-Type: application/json" \
        -d "{\"input\": {\"prompt\":\"the robot lowers its raised arm and steps toward the camera, the flat orange backdrop holds steady\",\"media\":[{\"type\":\"first_frame\",\"url\":\"https://raw.githubusercontent.com/Comfy-Org/workflow_templates/main/input/pink_robot_front.png\"}]}, \"parameters\": {\"resolution\":\"720P\",\"duration\":5}}"
      ```
    </CodeGroup>
  </Tab>

  <Tab title="Queue and collect later">
    The same body, sent to `POST https://api.comfy.org/v2/models/wan/wan3.0-video/requests`. Router answers `201` with a `request_id` as soon as the run is admitted, and the result is collected once it is ready, from this process or another one. [Queued delivery](/development/comfy-router/queue) walks through status, cancellation and collection.

    <CodeGroup>
      ```python Python theme={null}
      import asyncio
      from comfy_sdk import AsyncComfy

      # Reads COMFY_API_KEY from the environment.
      # Each submit() call mints its own Idempotency-Key and reuses it for automatic retries.
      async def main():
          async with AsyncComfy() as client:
              handle = await client.models.submit(
                  "wan/wan3.0-video",
                  {
                      "input": {
                          "prompt": "the robot lowers its raised arm and steps toward the camera, the flat orange backdrop holds steady",
                          "media": [
                              {
                                  "type": "first_frame",
                                  "url": "https://raw.githubusercontent.com/Comfy-Org/workflow_templates/main/input/pink_robot_front.png",
                              },
                          ],
                      },
                      "parameters": {
                          "resolution": "720P",
                          "duration": 5,
                      },
                  },
              )
              print("request_id:", handle.request_id)  # with the model ID, all another process needs

              # Poll until the request completes, waiting the Retry-After the server names.
              async for update in handle.iter_events():
                  print(update.status, update.queue_position)

              # The provider's own payload, the same value models.run() returns.
              # A request that failed or was cancelled raises the typed Router error here.
              result = await handle.get()

          print("video:", result["output"]["video_url"])

      asyncio.run(main())
      ```

      ```typescript TypeScript theme={null}
      import { comfy } from "@comfyorg/sdk";

      // Reads COMFY_API_KEY from the environment.
      // Each submit() call mints its own Idempotency-Key and reuses it for automatic retries.
      type Result = { output: { video_url: string } };
      const handle = await comfy.models.submit<Result>("wan/wan3.0-video", {
        input: {
          prompt: "the robot lowers its raised arm and steps toward the camera, the flat orange backdrop holds steady",
          media: [
            {
              type: "first_frame",
              url: "https://raw.githubusercontent.com/Comfy-Org/workflow_templates/main/input/pink_robot_front.png",
            },
          ],
        },
        parameters: {
          resolution: "720P",
          duration: 5,
        },
      });
      console.log("requestId:", handle.requestId); // with the model ID, all another process needs

      // Poll until the request completes, waiting the Retry-After the server names.
      for await (const update of handle.events()) {
        console.log(update.status, update.queuePosition);
      }

      // The same result models.run() returns. A request that failed or was cancelled rejects here.
      const result = await handle.get();
      if (result.kind !== "json") throw new Error("expected a JSON result");

      console.log("video:", result.data.output.video_url);
      ```

      ```bash cURL theme={null}
      # 1. Submit. Router answers 201 with request_id, status_url, response_url and cancel_url.
      curl https://api.comfy.org/v2/models/wan/wan3.0-video/requests \
        -H "X-API-Key: $COMFY_API_KEY" \
        -H "Idempotency-Key: $(uuidgen)" \
        -H "Content-Type: application/json" \
        -d "{\"input\": {\"prompt\":\"the robot lowers its raised arm and steps toward the camera, the flat orange backdrop holds steady\",\"media\":[{\"type\":\"first_frame\",\"url\":\"https://raw.githubusercontent.com/Comfy-Org/workflow_templates/main/input/pink_robot_front.png\"}]}, \"parameters\": {\"resolution\":\"720P\",\"duration\":5}}"

      # 2. Poll until status is COMPLETED, waiting the Retry-After seconds each response names.
      REQUEST_ID="<request_id from the 201 body>"
      curl -i https://api.comfy.org/v2/models/wan/wan3.0-video/requests/$REQUEST_ID/status \
        -H "X-API-Key: $COMFY_API_KEY"

      # 3. Collect. 200 with the model's native output, 202 with the status body while it is still running.
      curl https://api.comfy.org/v2/models/wan/wan3.0-video/requests/$REQUEST_ID \
        -H "X-API-Key: $COMFY_API_KEY"
      ```
    </CodeGroup>
  </Tab>
</Tabs>

## Serving providers

This model is served by Comfy Router directly unless the request names another provider. The providers below serve it too, on the same endpoint and with the same model ID, selected with the `model_provider` query parameter.

* **Comfy** (default): `POST https://api.comfy.org/v2/models/wan/wan3.0-video`
* **Higgsfield**, as `higgsfield/higgsfield-wan-3`: `POST https://api.comfy.org/v2/models/wan/wan3.0-video?model_provider=higgsfield`

`strict_mode` defaults to false, so Router translates the native request body documented on this page into the provider's own schema and translates the response back. See [`model_provider`, `strict_mode` and `fallback_provider`](/development/comfy-router/reference#post-v2modelsprovidermodel) in the API reference, and [Serving providers](/development/comfy-router/providers) for every model routed this way.

## Schema

### Input

<ParamField body="input" type="object" required>
  Enter basic information, such as prompt words, etc.
</ParamField>

<ParamField body="input.audio_url" type="string">
  Audio file download URL. Supported formats: mp3 and wav. Cannot be used with reference\_video\_urls.
</ParamField>

<ParamField body="input.img_url" type="string">
  First frame image URL or Base64 encoded data.
  Required for the wan2.5-i2v-preview and wan2.6-i2v models only. The
  happyhorse-1.x i2v spellings do NOT take their first frame here: they
  take it as a `media` element of type `first_frame` (see `media` below),
  and an `img_url` body that succeeds on wan2.6-i2v is refused by the
  provider on happyhorse-1.0-i2v and happyhorse-1.1-i2v.
  Image formats: JPEG, JPG, PNG, BMP, WEBP. Resolution: 360-2000 pixels.
  File size: max 10MB.
</ParamField>

<ParamField body="input.media" type="object[]">
  Media asset list for the wan2.7, wan3.0 and happyhorse-1.x models. Specifies reference
  materials (image, audio, video) for video generation. Each element contains a type and
  url field.
  Supported type values vary by model:

  * wan2.7-i2v: first\_frame, last\_frame, driving\_audio, first\_clip
  * wan2.7-r2v: reference\_image, reference\_video
  * wan2.7-videoedit: video, reference\_image
  * wan3.0-video: first\_frame (max 1), last\_frame (max 1), reference\_image (max 10),
    reference\_video (max 5 clips, total duration \<= 15s), reference\_audio (max 5 clips,
    total duration \<= 15s), file (max 1, cannot be used with link), link (max 1, cannot
    be used with file). The reference\_\*/file/link types and first\_frame/last\_frame types
    are mutually exclusive within the same request. The array order defines the reference
    order of assets in the prompt (Image 1, Video 1, Audio 1, ...).
  * happyhorse-1.x-i2v: first\_frame only, exactly 1. At least 300x300 pixels,
    JPEG/JPG/PNG/WEBP, max 20MB, a public URL or a data:\{MIME\_type};base64,... URL.
    These spellings take NO img\_url; the first frame goes here.
  * happyhorse-1.x-r2v: reference\_image only, 1 to 9 of them. Shortest side at least
    400 pixels, max 20MB, a public URL or a data: URL. reference\_video is NOT an input
    type for this operation.
  * happyhorse-1.x-video-edit: video
    The per-asset "max 20MB" figures above are the PARTNER's ceiling on the image it
    ends up with, and they apply as written when the asset is a public URL, because
    those bytes never travel through Comfy. An INLINE data: URL does travel through
    Comfy and meets a transport ceiling as well: a Comfy Router POST body is
    capped at 100 MiB in total and answered 413 past it, and base64 inflates a payload
    by about 4/3, so a single inline asset above roughly 75 MB is refused before
    any of the partner rules here are reached. At that size a single asset at the
    partner's own 20MB ceiling fits inline comfortably, so the partner rule is what
    binds for one asset — the transport ceiling binds across several of them, since
    the 100 MiB Router cap bounds the WHOLE request rather than each element. Send
    anything near these ceilings as a public URL.
</ParamField>

<ParamField body="input.media[].type" type="string" required>
  Media asset type

  Possible values: `first_frame`, `last_frame`, `driving_audio`, `first_clip`, `reference_image`, `reference_video`, `reference_audio`, `video`, `file`, `link`
</ParamField>

<ParamField body="input.media[].url" type="string" required>
  URL of the media file: a public HTTP/HTTPS URL, an OSS temporary URL, or — where the model's entry in the `media` description above says so, as the happyhorse-1.x i2v and r2v spellings do — an inline `data:{MIME_type};base64,...` URL. See that description for the per-model size and pixel floors, and for the 100 MiB Router request-body cap that bounds an inline payload in aggregate.
</ParamField>

<ParamField body="input.negative_prompt" type="string">
  Reverse prompt words are used to describe content that you do not want to see in the video screen
</ParamField>

<ParamField body="input.prompt" type="string">
  Text prompt words. Support Chinese and English, length not exceeding 800 characters
  (up to 20,000 characters for wan3.0-video; content exceeding the limit is truncated).
  For wan2.6-r2v with multiple reference videos, use 'character1', 'character2', etc. to refer to subjects
  in the order of reference videos. Example: "Character1 sings on the roadside, Character2 dances beside it"
  For wan3.0-video reference mode, use 'Image 1', 'Video 1', 'Audio 1', etc. to refer to media assets
  in the corresponding order within the media array.
</ParamField>

<ParamField body="input.reference_video_urls" type="string[]">
  Reference video URLs for wan2.6-r2v model only. Array of 1-3 video URLs.
  Input restrictions:

  * Format: mp4, mov
  * Quantity: 1-3 videos
  * Single video length: 2-30 seconds
  * Single file size: max 30MB
  * Cannot be used with audio\_url
    Reference duration: Single video max 5s, two videos max 2.5s each, three videos proportionally less.
    Billing: Based on actual reference duration used.
</ParamField>

<ParamField body="input.template" type="string">
  Video effect template name. Optional. Currently supported: squish, flying, carousel. When used, prompt parameter is ignored.
</ParamField>

<ParamField body="model" type="string">
  The ID of the model to call. NOT constrained on this component: Comfy Router fills it from the `{model}` path segment of `POST /v2/models/wan/{model}`, so a Router caller omits it. A direct v1 call to `POST /proxy/wan/api/v1/services/aigc/video-generation/video-synthesis` MUST supply it, and the enum of accepted spellings lives on that operation's own component, `WanVideoGenerationRequest`.
</ParamField>

<ParamField body="parameters" type="object">
  Video processing parameters
</ParamField>

<ParamField body="parameters.audio" type="boolean" default="true">
  Whether to add audio to the video
</ParamField>

<ParamField body="parameters.audio_setting" type="string" default="&#x22;auto&#x22;">
  Video audio setting for wan2.7-videoedit model.

  * auto (default): Model intelligently judges based on prompt content
  * origin: Forcefully preserve the original audio from the input video

    Possible values: `auto`, `origin`
</ParamField>

<ParamField body="parameters.duration" type="integer" default="5">
  The duration of the video generated, in seconds:

  * wan2.5 models: 5 or 10 seconds
  * wan2.6-t2v, wan2.6-i2v: 5, 10, or 15 seconds
  * wan2.6-r2v: 5 or 10 seconds only (no 15s support)
  * wan2.7-i2v, wan2.7-t2v: integer in \[2, 15]
  * wan2.7-r2v, wan2.7-videoedit: integer in \[2, 10]
  * wan3.0-video: integer in \[2, 30] without video input; with video input the total
    input video duration + output video duration must not exceed 30 seconds; -1 enables
    smart duration mode where the model picks a suitable duration

    Range: `-1` to `30`
</ParamField>

<ParamField body="parameters.prompt_extend" type="boolean" default="true">
  Is it enabled prompt intelligent rewriting. Default is true
</ParamField>

<ParamField body="parameters.ratio" type="string">
  Aspect ratio of the generated video. For wan2.7 and wan3.0 models only.
  For wan2.7 models, defaults based on the resolution tier if not provided.
  For wan3.0-video, adaptive (the default) automatically recommends a suitable
  aspect ratio based on the input media proportions and intent.

  Possible values: `adaptive`, `16:9`, `9:16`, `1:1`, `4:3`, `3:4`
</ParamField>

<ParamField body="parameters.resolution" type="string">
  Resolution level. Supported values vary by model:

  * wan2.5-i2v-preview: 480P, 720P, 1080P
  * wan2.6-i2v: 720P, 1080P only (no 480P support)
  * wan2.7 models (i2v, t2v, r2v, videoedit): 720P, 1080P (default 1080P)
  * wan3.0-video, wan3.0-video-prime: 480P, 720P, 1080P (upstream default 1080P)
    This proxy rejects video generation requests that provide neither resolution
    nor size, because the resolution tier selects the billing rate.

    Possible values: `480P`, `720P`, `1080P`
</ParamField>

<ParamField body="parameters.seed" type="integer">
  Random number seed, used to control the randomness of the model generated content

  Range: `0` to `2147483647`
</ParamField>

<ParamField body="parameters.shot_type" type="string" default="&#x22;single&#x22;">
  Intelligent multi-lens control. Only active when prompt\_extend is enabled.
  For wan2.6 and wan2.7-r2v models.

  * single: Single-shot video (default)
  * multi: Multi-shot video

    Possible values: `multi`, `single`
</ParamField>

<ParamField body="parameters.size" type="string">
  Video resolution in format width*height. Supported resolutions vary by model:
  For wan2.5 T2V: 480P (480*832, 832*480, 624*624), 720P, 1080P sizes
  For wan2.6 T2V/R2V (no 480P):
  720P: 1280*720, 720*1280, 960*960, 1088*832, 832*1088
  1080P: 1920*1080, 1080*1920, 1440*1440, 1632*1248, 1248*1632
</ParamField>

<ParamField body="parameters.watermark" type="boolean" default="false">
  Whether to add a watermark logo, the watermark is located in the lower right corner
</ParamField>

Generated from the schema Router serves at `GET /v2/models/wan/wan3.0-video/openapi.json`, the same document it validates a call against before the request reaches the provider.

### Output

<ResponseField name="output" type="object" required />

<ResponseField name="output.actual_prompt" type="string">
  Actual prompt after intelligent rewriting (for video tasks)
</ResponseField>

<ResponseField name="output.check_audio" type="string">
  Audio URL for I2V tasks with audio generation
</ResponseField>

<ResponseField name="output.code" type="string">
  The error code for the failed request (not returned if request is successful)
</ResponseField>

<ResponseField name="output.end_time" type="string">
  Task completion time
</ResponseField>

<ResponseField name="output.message" type="string">
  Detailed information about the failed request (not returned if request is successful)
</ResponseField>

<ResponseField name="output.orig_prompt" type="string">
  Original input prompt (for video tasks)
</ResponseField>

<ResponseField name="output.results" type="object[]">
  List of task results for image generation tasks
</ResponseField>

<ResponseField name="output.results[].actual_prompt" type="string">
  Actual prompt after intelligent rewriting (if enabled)
</ResponseField>

<ResponseField name="output.results[].code" type="string">
  Image error code (returned when some tasks fail)
</ResponseField>

<ResponseField name="output.results[].message" type="string">
  Image error information (returned when some tasks fail)
</ResponseField>

<ResponseField name="output.results[].orig_prompt" type="string">
  Original input prompt
</ResponseField>

<ResponseField name="output.results[].url" type="string">
  Generated image URL address
</ResponseField>

<ResponseField name="output.scheduled_time" type="string">
  Task execution time
</ResponseField>

<ResponseField name="output.submit_time" type="string">
  Task submission time
</ResponseField>

<ResponseField name="output.task_id" type="string" required>
  Task ID
</ResponseField>

<ResponseField name="output.task_metrics" type="object">
  Task result statistics for image generation tasks
</ResponseField>

<ResponseField name="output.task_metrics.FAILED" type="integer">
  Number of failed tasks
</ResponseField>

<ResponseField name="output.task_metrics.SUCCEEDED" type="integer">
  Number of successful tasks
</ResponseField>

<ResponseField name="output.task_metrics.TOTAL" type="integer">
  Total number of tasks
</ResponseField>

<ResponseField name="output.task_status" type="string" required>
  Task status

  Possible values: `PENDING`, `RUNNING`, `SUCCEEDED`, `FAILED`, `CANCELED`, `UNKNOWN`
</ResponseField>

<ResponseField name="output.video_url" type="string">
  Video URL for completed video generation tasks. Link validity period 24 hours
</ResponseField>

<ResponseField name="request_id" type="string" required>
  Unique request identifier
</ResponseField>

<ResponseField name="usage" type="object">
  Output information statistics. Only successful results are counted
</ResponseField>

<ResponseField name="usage.SR" type="integer">
  Video resolution level (I2V and wan3.0-video tasks)
</ResponseField>

<ResponseField name="usage.duration" type="number">
  Duration of generated video in seconds (I2V and wan3.0-video tasks)
</ResponseField>

<ResponseField name="usage.fps" type="integer">
  Frame rate of the generated video (wan3.0-video tasks)
</ResponseField>

<ResponseField name="usage.image_count" type="integer">
  Number of generated images (T2I and I2I tasks)
</ResponseField>

<ResponseField name="usage.input_video_duration" type="number">
  Duration of the input video in seconds, 0.0 when no video input (wan3.0-video tasks)
</ResponseField>

<ResponseField name="usage.output_video_duration" type="number">
  Duration of the output video in seconds (wan3.0-video tasks)
</ResponseField>

<ResponseField name="usage.ratio" type="string">
  Aspect ratio of the generated video, e.g. 16:9 (wan3.0-video tasks)
</ResponseField>

<ResponseField name="usage.size" type="string">
  Image resolution (T2I and I2I tasks)
</ResponseField>

<ResponseField name="usage.video_count" type="integer">
  Number of generated videos (T2V tasks)
</ResponseField>

<ResponseField name="usage.video_duration" type="number">
  Duration of generated video in seconds (T2V tasks)
</ResponseField>

<ResponseField name="usage.video_ratio" type="string">
  Video resolution ratio (T2V tasks)
</ResponseField>

<ResponseField name="code" type="string">
  Error code for a failed request, reported at the ROOT of the envelope rather than under `output` (not returned if the request succeeded).
</ResponseField>

<ResponseField name="message" type="string">
  Detailed information about a failed request, reported at the ROOT of the envelope rather than under `output` (not returned if the request succeeded). Read this before falling back to `output.message`.
</ResponseField>

## Examples

### Input

```json theme={null}
{
  "input": {
    "prompt": "the robot lowers its raised arm and steps toward the camera, the flat orange backdrop holds steady",
    "media": [
      {
        "type": "first_frame",
        "url": "https://raw.githubusercontent.com/Comfy-Org/workflow_templates/main/input/pink_robot_front.png"
      }
    ]
  },
  "parameters": {
    "resolution": "720P",
    "duration": 5
  }
}
```

### Output

```json theme={null}
{
  "output": {
    "task_id": "0385dc79-5ff8-4d82-bcb6-7c1a9f2e4d60",
    "task_status": "SUCCEEDED",
    "submit_time": "2027-01-01T00:00:00.000Z",
    "scheduled_time": "2027-01-01T00:00:01.000Z",
    "end_time": "2027-01-01T00:01:04.000Z",
    "orig_prompt": "the robot lowers its raised arm and steps toward the camera, the flat orange backdrop holds steady",
    "actual_prompt": "the robot lowers its raised arm and steps toward the camera, the flat orange backdrop holds steady, smooth studio lighting, subtle camera push in",
    "video_url": "https://.../generated.mp4"
  },
  "request_id": "7574ee8f-38a3-4b1e-9280-11c33ab46e51",
  "usage": {
    "SR": 720,
    "duration": 5
  }
}
```

The video URL is valid for 24 hours. Download the video promptly if you need to keep it.

## Before you ship

The SDKs create an `Idempotency-Key` and reuse it for automatic retries. For manual retries, reuse the original key. Router can hold the connection for up to 10 minutes.

When a request fails, Router sends an `X-Comfy-Error-Type` response header explaining why. A `422` means Router rejected the input before calling the provider, and a `413` means the request body was larger than Router accepts. Download generated assets promptly because [result URLs can expire](/development/comfy-router/reference#result-assets).

Any size limit named in a field description above is the provider's own bound on that field, quoted from the provider's specification. Router applies a separate cap to the whole request body, which base64-encoded media counts against: see [request body size](/development/comfy-router/limitations#request-bodies-are-capped).

This page documents one partner model called through Comfy Router. The same `comfy-sdk` / `@comfyorg/sdk` package also ships a second client, for running a whole ComfyUI workflow graph on Comfy Cloud: `Comfy(api_key=...)` / `new Comfy({ apiKey })`, with `client.workflows`, `client.assets` and `client.jobs`. See [Comfy SDKs](/development/api-development/sdks).

<CardGroup cols={3}>
  <Card title="Headers" icon="list" href="/development/comfy-router/headers">
    Authentication, idempotency, request IDs, error buckets, retry pacing, spend limits.
  </Card>

  <Card title="Using the Router API" icon="code" href="/development/comfy-router/api">
    Model discovery, validation errors, retries, and billing.
  </Card>

  <Card title="Limitations" icon="triangle-exclamation" href="/development/comfy-router/limitations">
    What Router does not do today, and what to use instead.
  </Card>
</CardGroup>
