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

# 监听渲染

> 通过服务器发送事件监听渲染状态。

服务先发送状态快照，再每 10–15 秒发送心跳，进入 `ready`、`failed` 或 `cancelled` 后关闭流。断开后可使用 `Last-Event-ID` 恢复快照后的事件。若事件历史已过期，先调用[获取视频](/zh/v1/api-reference/videos/get)（`GET /v1/videos/{render_id}`）读取当前状态，再重新连接。

## 请求参数

| 参数              | 类型     |  必填 | 说明                                                     |
| --------------- | ------ | :-: | ------------------------------------------------------ |
| `render_id`     | string |  是  | 创建渲染或视频列表返回的完整 ID，通常以 `render_` 开头。此连接仅报告该任务的事件。       |
| `Last-Event-ID` | string |  否  | 上一次已完整处理的 SSE 事件 ID，请放入请求头。重连时从该事件之后继续发送保留的历史；新建连接可省略。 |

## 响应

返回 `200 OK` 和 `text/event-stream` 响应体。业务事件的 `data` 为 JSON，心跳可能不带 `data`。

| 事件           | `data` 内容 | 说明                         |
| ------------ | --------- | -------------------------- |
| `snapshot`   | 渲染事件数据    | 连接后立即发送。                   |
| `queued`     | 渲染事件数据    | 已受理，尚未处理。                  |
| `processing` | 渲染事件数据    | 开始处理。                      |
| `progress`   | 渲染事件数据    | `progress` 或 `stage` 发生变化。 |
| `ready`      | 渲染事件数据    | 终态，输出 URL 就绪，随后关闭流。        |
| `failed`     | 渲染事件数据    | 终态，`error` 有值，随后关闭流。       |
| `cancelled`  | 渲染事件数据    | 终态，随后关闭流。                  |
| `heartbeat`  | 无         | 仅保持连接，不含业务数据。              |

渲染事件的 `data` 字段如下：

| 字段                        | 类型             | 始终返回 | 说明                                                    |
| ------------------------- | -------------- | :--: | ----------------------------------------------------- |
| `event_id`                | string         |   是  | 用作 `Last-Event-ID`，从该事件之后恢复。                          |
| `sequence`                | integer        |   是  | 在单个渲染任务内单调递增。                                         |
| `id`                      | string         |   是  | 渲染任务 ID。                                              |
| `status`                  | string         |   是  | `queued`、`processing`、`ready`、`failed` 或 `cancelled`。 |
| `stage`                   | string 或 null  |   是  | 可用时提供大致阶段。                                            |
| `progress`                | integer 或 null |   是  | 可用时为 0–100 的进度。                                       |
| `video_url` / `alpha_url` | string 或 null  |   是  | `ready` 时返回相应输出链接。                                    |
| `occurred_at`             | string         |   是  | ISO 8601 事件时间。                                        |
| `completed_at`            | string 或 null  |   是  | ISO 8601 完成时间。                                        |
| `error`                   | object 或 null  |   是  | `failed` 时有值。                                         |

## 示例

<CodeGroup>
  ```bash cURL theme={null}
  curl -N "https://apis.viggle.ai/v1/renders/render_789ghi/events" \
    -H "Authorization: Bearer $VIGGLE_API_KEY" \
    -H "Accept: text/event-stream"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://apis.viggle.ai/v1/renders/render_789ghi/events", {
    headers: { Authorization: `Bearer ${process.env.VIGGLE_API_KEY}`, Accept: "text/event-stream" },
  });
  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = "";
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    buffer += decoder.decode(value, { stream: true });
    // Split on blank lines to get whole SSE frames, then parse `event:`/`data:`.
  }
  ```

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

  with requests.get(
      "https://apis.viggle.ai/v1/renders/render_789ghi/events",
      headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}", "Accept": "text/event-stream"},
      stream=True,
  ) as response:
      response.raise_for_status()
      for line in response.iter_lines(decode_unicode=True):
          if line:
              print(line)
  ```
</CodeGroup>

<Tip>
  能够保持长连接时，可使用本接口减少[获取视频](/zh/v1/api-reference/videos/get)的轮询延迟与请求量，状态判断方式不变。
</Tip>

## 下一步

收到 `ready` 事件后，使用[下载渲染结果](/zh/v1/api-reference/renders/download)，或直接读取事件中的 `video_url`/`alpha_url`。


## OpenAPI

````yaml zh/openapi.yaml GET /v1/renders/{render_id}/events
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/{render_id}/events:
    parameters:
      - $ref: '#/components/parameters/RenderId'
      - $ref: '#/components/parameters/RequestId'
      - $ref: '#/components/parameters/SourceChannel'
    get:
      tags:
        - Renders
      summary: 监听渲染
      description: 通过服务器发送事件监听渲染状态。
      operationId: watchRender
      parameters:
        - $ref: '#/components/parameters/LastEventId'
      responses:
        '200':
          description: 请求成功。
          headers:
            Cache-Control:
              schema:
                type: string
              example: no-cache
            X-Accel-Buffering:
              schema:
                type: string
              example: 'no'
            X-Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            text/event-stream:
              schema:
                type: string
                description: UTF-8 编码的服务器发送事件流。
          x-sse-event-name:
            $ref: '#/components/schemas/RenderEventName'
          x-sse-events:
            snapshot:
              $ref: '#/components/schemas/RenderEventData'
            queued:
              $ref: '#/components/schemas/RenderEventData'
            processing:
              $ref: '#/components/schemas/RenderEventData'
            progress:
              $ref: '#/components/schemas/RenderEventData'
            ready:
              $ref: '#/components/schemas/RenderEventData'
            failed:
              $ref: '#/components/schemas/RenderEventData'
            cancelled:
              $ref: '#/components/schemas/RenderEventData'
            heartbeat:
              description: 保持连接的心跳事件，无必填数据。
        '401':
          $ref: '#/components/responses/V1Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '429':
          $ref: '#/components/responses/RateLimited'
        '500':
          $ref: '#/components/responses/InternalServerError'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  parameters:
    RenderId:
      name: render_id
      in: path
      required: true
      description: 创建或列出渲染时返回的公开 ID，通常以 render_ 开头，必须属于当前调用者。
      schema:
        type: string
        minLength: 1
      example: render_123
    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
    LastEventId:
      name: Last-Event-ID
      in: header
      required: false
      description: 客户端最后完整处理的 SSE 事件 ID。重连时传入，以便在历史仍保留时从该事件之后继续。
      schema:
        type: string
        minLength: 1
  headers:
    RequestId:
      description: 用于支持排查和追踪的稳定请求 ID。
      schema:
        type: string
  responses:
    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'
    NotFound:
      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'
  schemas:
    ErrorResponse:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          description: 草稿流程的顶层错误，包含稳定错误码、说明、重试建议、关联 ID 和错误详情。
          allOf:
            - $ref: '#/components/schemas/ErrorBody'
    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
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: API key or OAuth access token
      description: 服务端 SDK 使用项目 API 密钥，Remote MCP 使用 OAuth 访问令牌。不要在浏览器代码中暴露项目密钥。

````