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

# 准备渲染

> 准备渲染草稿，并获取待上传素材的直传计划。

开始草稿渲染流程。`prepare` 返回短期有效的直传 URL，无需在 JSON 中嵌入媒体字节。将角色和动作文件直接上传到这些 URL，再携带 `draft_id` 调用[渲染视频](/zh/v1/api-reference/renders/create)的 JSON 模式。

## 请求参数

使用 `application/json`。

| 参数                                               | 类型      |            必填            | 说明                                                                        |
| ------------------------------------------------ | ------- | :----------------------: | ------------------------------------------------------------------------- |
| `character`                                      | object  |             是            | 角色来源描述，三选一：直传元数据、公开 HTTPS URL、已就绪的可复用角色 ID。                               |
| `motion`                                         | object  |             是            | 动作来源描述：直传元数据、公开 HTTPS URL、已就绪动作 ID 或官方动作模板 ID。                            |
| `character.kind` / `motion.kind`                 | string  |             是            | 来源类型：`upload`、`url`、`asset`；动作还支持 `official_motion`。该值决定其他必填字段。           |
| `character.filename` / `motion.filename`         | string  |      `kind=upload` 时     | 含扩展名的原始文件名，用于后续上传识别及校验。                                                   |
| `character.content_type` / `motion.content_type` | string  |      `kind=upload` 时     | MIME 类型，如 `image/png` 或 `video/mp4`。直传时 `Content-Type` 需保持相同。             |
| `character.bytes` / `motion.bytes`               | integer |      `kind=upload` 时     | 大于 0 的精确文件字节数，上传对象大小将与此值核对。                                               |
| `character.url` / `motion.url`                   | string  |       `kind=url` 时       | 可公开访问的 HTTPS 素材 URL，草稿准备及提交期间应保持可访问。                                      |
| `character.asset_id` / `motion.asset_id`         | string  |      `kind=asset` 时      | 当前调用者拥有的就绪素材 ID，角色槽使用角色 ID，动作槽使用动作 ID。                                    |
| `motion.motion_id`                               | string  | `kind=official_motion` 时 | 官方 Viggle 动作模板 ID，仅适用于动作槽。                                                |
| `output`                                         | object  |             否            | 输出设置，省略时使用默认背景处理和源宽高比。                                                    |
| `output.background_mode`                         | string  |             否            | `original`、`green`、`white` 或 `transparent`。`green`/`white` 会转换为对应颜色的纯色背景。 |
| `output.aspect_ratio`                            | string  |             否            | 当前仅支持 `source`。虽然枚举包含 `16:9`、`9:16`、`1:1`，但由于流程尚不支持重新构图，传入这些值会被拒绝，不会静默忽略。 |

`kind: "upload"` 仅声明上传槽，此时不发送文件内容。先提供 `filename`、`content_type` 和 `bytes`，随后向返回的 URL `PUT` 原始字节。省略 `output` 时使用默认背景和宽高比，与[直接 multipart 渲染](/zh/v1/api-reference/renders/create)一致。

## 响应参数

返回 `200 OK`。

| 字段                           | 类型     | 始终返回 | 说明                                                       |
| ---------------------------- | ------ | :--: | -------------------------------------------------------- |
| `draft_id`                   | string |   是  | 提交到[渲染视频](/zh/v1/api-reference/renders/create)的 JSON 模式。 |
| `state`                      | string |   是  | 有上传槽时为 `awaiting_uploads`，否则为 `ready_to_create`。         |
| `uploads`                    | array  |   是  | 每个上传槽对应一项。全部使用 `url`/`asset`/`official_motion` 时为空。      |
| `uploads[].slot`             | string |   是  | `character` 或 `motion`。                                  |
| `uploads[].upload_handle`    | string |   是  | 创建渲染时在 `upload_completions` 中原样传回。                       |
| `uploads[].method`           | string |   是  | 固定为 `PUT`。                                               |
| `uploads[].url`              | string |   是  | 短期有效的直传 URL。                                             |
| `uploads[].required_headers` | object |   是  | `PUT` 请求所需的请求头，格式为 `{name: value}`。                      |
| `uploads[].expires_at`       | string |   是  | 上传 URL 的 ISO 8601 过期时间。                                  |

```json theme={null}
{
  "draft_id": "draft_abc123",
  "state": "awaiting_uploads",
  "uploads": [
    {
      "slot": "character",
      "upload_handle": "up_1",
      "method": "PUT",
      "url": "https://uploads.viggle.ai/draft_abc123/character?sig=...",
      "required_headers": { "Content-Type": "image/png" },
      "expires_at": "2026-07-31T09:30:00+00:00"
    }
  ]
}
```

## 示例

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://apis.viggle.ai/v1/renders/prepare" \
    -H "Authorization: Bearer $VIGGLE_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
          "character": {"kind":"upload","filename":"character.png","content_type":"image/png","bytes":204800},
          "motion": {"kind":"asset","asset_id":"mot_456def"}
        }'
  ```

  ```python Python theme={null}
  import os, requests

  response = requests.post(
      "https://apis.viggle.ai/v1/renders/prepare",
      headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}"},
      json={
          "character": {"kind": "upload", "filename": "character.png", "content_type": "image/png", "bytes": 204800},
          "motion": {"kind": "asset", "asset_id": "mot_456def"},
      },
  )
  response.raise_for_status()
  draft = response.json()

  for upload in draft["uploads"]:
      with open("character.png", "rb") as f:
          put = requests.put(upload["url"], data=f, headers=upload["required_headers"])
      put.raise_for_status()
  ```
</CodeGroup>

## 下一步

在 `expires_at` 之前，携带 `uploads[].required_headers`，将每个文件的原始字节 `PUT` 到 `uploads[].url`。然后以 `Content-Type: application/json` 调用[渲染视频](/zh/v1/api-reference/renders/create)，提交 `draft_id` 及每个已上传槽对应的 `upload_completions`。


## OpenAPI

````yaml zh/openapi.yaml POST /v1/renders/prepare
openapi: 3.0.3
info:
  title: Viggle API
  description: 使用 AI 生成角色动画视频。
  version: 2.0.0
  contact:
    name: Viggle Support
    url: https://viggle.ai
servers:
  - url: https://apis.viggle.ai
    description: 生产服务器
security:
  - bearerAuth: []
tags:
  - name: Renders
    description: 准备输入、创建渲染、观察进度并获取结果。
  - name: Credits
    description: 查询当前调用者可用的积分余额。
  - name: Characters
    description: 创建、列出、查询和删除可复用角色。type 决定是否同时提取 3D vsplat，就绪后通过导出接口获取下载链接。
  - name: Motions
    description: 创建、列出、查询和删除可复用动作，也可从官方模板导入。type 决定是否提取或生成 3D 动画，就绪后通过导出接口获取下载链接。
  - name: Videos
    description: 生成 MiniMax H3 视频（vid_）或角色动画视频（anim_），并统一查询调用者的 H3、角色动画及角色动作渲染（render_）结果。
paths:
  /v1/renders/prepare:
    post:
      tags:
        - Renders
      summary: 准备渲染
      operationId: prepareRender
      parameters:
        - $ref: '#/components/parameters/RequestId'
        - $ref: '#/components/parameters/SourceChannel'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PrepareRenderRequest'
      responses:
        '200':
          description: 请求成功。
          headers:
            X-Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PrepareRenderResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/V1Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  parameters:
    RequestId:
      name: X-Request-Id
      in: header
      required: false
      description: 可选的调用者自定义关联 ID，最长 128 字符。服务会在响应头返回实际使用的值，便于追踪和支持排查。
      schema:
        type: string
        minLength: 1
        maxLength: 128
    SourceChannel:
      name: X-Viggle-Source
      in: header
      required: false
      description: 可选来源标签，最长 128 字符，用于识别 SDK、集成、产品入口或内部工作流。
      schema:
        type: string
        minLength: 1
        maxLength: 128
  schemas:
    PrepareRenderRequest:
      type: object
      additionalProperties: false
      required:
        - character
        - motion
      properties:
        character:
          description: 角色来源描述，三选一：直传元数据、公开 HTTPS URL、已就绪的可复用角色 ID。
          allOf:
            - $ref: '#/components/schemas/CharacterSource'
        motion:
          description: 动作来源描述：直传元数据、公开 HTTPS URL、已就绪动作 ID 或官方动作模板 ID。
          allOf:
            - $ref: '#/components/schemas/MotionSource'
        output:
          description: 输出设置，省略时使用默认背景处理和源宽高比。
          allOf:
            - $ref: '#/components/schemas/RenderOutputOptions'
    PrepareRenderResponse:
      type: object
      additionalProperties: false
      required:
        - draft_id
        - state
        - uploads
      properties:
        draft_id:
          type: string
          description: 提交到[渲染视频](/zh/v1/api-reference/renders/create)的 JSON 模式。
          minLength: 1
        state:
          type: string
          description: 有上传槽时为 `awaiting_uploads`，否则为 `ready_to_create`。
          enum:
            - awaiting_uploads
            - ready_to_create
        uploads:
          type: array
          description: 每个上传槽对应一项。全部使用 `url`/`asset`/`official_motion` 时为空。
          items:
            $ref: '#/components/schemas/UploadPlan'
    CharacterSource:
      oneOf:
        - $ref: '#/components/schemas/UploadSource'
        - $ref: '#/components/schemas/UrlSource'
        - $ref: '#/components/schemas/AssetSource'
    MotionSource:
      oneOf:
        - $ref: '#/components/schemas/UploadSource'
        - $ref: '#/components/schemas/UrlSource'
        - $ref: '#/components/schemas/AssetSource'
        - $ref: '#/components/schemas/OfficialMotionSource'
    RenderOutputOptions:
      type: object
      additionalProperties: false
      properties:
        background_mode:
          description: >-
            `original`、`green`、`white` 或 `transparent`。`green`/`white`
            会转换为对应颜色的纯色背景。
          type: string
          enum:
            - original
            - green
            - white
            - transparent
        aspect_ratio:
          description: >-
            当前仅支持 `source`。虽然枚举包含
            `16:9`、`9:16`、`1:1`，但由于流程尚不支持重新构图，传入这些值会被拒绝，不会静默忽略。
          type: string
          enum:
            - source
            - '16:9'
            - '9:16'
            - '1:1'
    UploadPlan:
      type: object
      additionalProperties: false
      required:
        - slot
        - upload_handle
        - method
        - url
        - required_headers
        - expires_at
      properties:
        slot:
          type: string
          description: '`character` 或 `motion`。'
          enum:
            - character
            - motion
        upload_handle:
          type: string
          description: 创建渲染时在 `upload_completions` 中原样传回。
          minLength: 1
        method:
          type: string
          description: 固定为 `PUT`。
          enum:
            - PUT
        url:
          type: string
          format: uri
          description: 短期有效的直传 URL。
        required_headers:
          type: object
          description: '`PUT` 请求所需的请求头，格式为 `{name: value}`。'
          additionalProperties:
            type: string
        expires_at:
          type: string
          format: date-time
          description: 上传 URL 的 ISO 8601 过期时间。
    ErrorResponse:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          description: 草稿流程的顶层错误，包含稳定错误码、说明、重试建议、关联 ID 和错误详情。
          allOf:
            - $ref: '#/components/schemas/ErrorBody'
    UploadSource:
      type: object
      additionalProperties: false
      required:
        - kind
        - filename
        - content_type
        - bytes
      properties:
        kind:
          type: string
          description: 来源类型。通过返回的直传计划上传素材时设为 upload。
          enum:
            - upload
        filename:
          type: string
          description: 包含扩展名的原始文件名，用于识别和校验上传素材。
          minLength: 1
        content_type:
          type: string
          description: 上传文件的 MIME 类型，如 image/png 或 video/mp4，必须与上传请求头匹配。
          minLength: 1
        bytes:
          type: integer
          format: int64
          description: 精确文件字节数，上传对象大小将与此声明核对。
          minimum: 1
    UrlSource:
      type: object
      additionalProperties: false
      required:
        - kind
        - url
      properties:
        kind:
          type: string
          description: 来源类型。需要 Viggle 从远程 HTTPS 地址下载时设为 url。
          enum:
            - url
        url:
          type: string
          format: uri
          description: 素材的公开 HTTPS URL，准备渲染期间必须保持可访问。
          pattern: ^https://
    AssetSource:
      type: object
      additionalProperties: false
      required:
        - kind
        - asset_id
      properties:
        kind:
          type: string
          description: 来源类型。复用当前账户中的已有角色或动作时设为 asset。
          enum:
            - asset
        asset_id:
          type: string
          description: 就绪的可复用素材 ID。角色槽使用角色 ID，动作槽使用动作 ID。
          minLength: 1
    OfficialMotionSource:
      type: object
      additionalProperties: false
      required:
        - kind
        - motion_id
      properties:
        kind:
          type: string
          description: 来源类型。使用 Viggle 官方模板目录中的动作时设为 official_motion。
          enum:
            - official_motion
        motion_id:
          type: string
          description: 用作驱动动作的官方动作模板 ID。
          minLength: 1
    ErrorBody:
      type: object
      additionalProperties: false
      required:
        - code
        - message
        - retryable
        - request_id
        - details
        - remediation
      properties:
        code:
          description: 恢复方法
          allOf:
            - $ref: '#/components/schemas/ErrorCode'
        message:
          type: string
          description: 供人阅读的描述，不要解析其文本做逻辑判断。
        retryable:
          type: boolean
          description: 重试相同请求是否可能成功。
        request_id:
          type: string
          description: 用于关联 Viggle 日志与支持排查。仅当异步工作进程无法恢复原请求 ID 时为 `null`。
        details:
          type: object
          description: 补充结构化信息，可能为空。
          additionalProperties: true
        remediation:
          description: >-
            `{action, retry_after_ms}`，表示下一步操作。除非建议定时重试，否则 `retry_after_ms` 为
            `null`。
          allOf:
            - $ref: '#/components/schemas/ErrorRemediation'
    ErrorCode:
      description: 草稿渲染流程的错误码集合。资源操作将相应错误映射为 ResourceError 说明的小写下划线形式。
      type: string
      enum:
        - UNAUTHENTICATED
        - INVALID_CREDENTIAL
        - FORBIDDEN
        - INVALID_REQUEST
        - INVALID_CHARACTER
        - INVALID_MOTION
        - UNSUPPORTED_MEDIA
        - CONTENT_POLICY_VIOLATION
        - UPLOAD_REQUIRED
        - UPLOAD_MISMATCH
        - UPLOAD_EXPIRED
        - DRAFT_NOT_FOUND
        - DRAFT_ALREADY_CONSUMED
        - RENDER_NOT_FOUND
        - RENDER_NOT_CANCELLABLE
        - CHARACTER_NOT_FOUND
        - MOTION_NOT_FOUND
        - MOTION_NOT_READY
        - MOTION_TEMPLATE_NOT_FOUND
        - AVATAR_NOT_FOUND
        - ANIMATION_NOT_FOUND
        - EXTRACTION_UNAVAILABLE
        - EXTRACTION_FAILED
        - IDEMPOTENCY_KEY_REUSED
        - INSUFFICIENT_CREDITS
        - RATE_LIMITED
        - SERVICE_BUSY
        - INTERNAL_ERROR
    ErrorRemediation:
      type: object
      additionalProperties: false
      required:
        - action
        - retry_after_ms
      properties:
        action:
          type: string
          description: 建议的下一步操作，供程序或人工读取，例如稍后重试、重新上传或修正输入。
        retry_after_ms:
          type: integer
          description: 建议重试等待的毫秒数；无需定时重试时为 null。
          nullable: true
          format: int64
          minimum: 0
  headers:
    RequestId:
      description: 用于支持排查和追踪的稳定请求 ID。
      schema:
        type: string
  responses:
    BadRequest:
      description: 请求失败，详情见错误响应。
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    V1Unauthorized:
      description: 请求失败，详情见错误响应。
      headers:
        WWW-Authenticate:
          schema:
            type: string
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    Forbidden:
      description: 请求失败，详情见错误响应。
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    UnprocessableEntity:
      description: 请求失败，详情见错误响应。
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    RateLimited:
      description: 请求失败，详情见错误响应。
      headers:
        Retry-After:
          schema:
            type: integer
            minimum: 0
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    InternalServerError:
      description: 请求失败，详情见错误响应。
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    ServiceUnavailable:
      description: 请求失败，详情见错误响应。
      headers:
        Retry-After:
          schema:
            type: integer
            minimum: 0
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key or OAuth access token
      description: 服务端 SDK 使用项目 API 密钥，Remote MCP 使用 OAuth 访问令牌。不要在浏览器代码中暴露项目密钥。

````