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

# Create Scene

> Build a 3D Gaussian-splat scene from a text prompt or a 360° panorama.

Send a JSON body with a `sessionId` and either a `prompt` or a `panoramaUri`. With a prompt, the scene model first generates a 360° panorama — optionally guided by reference images — and then builds the scene from it; with `panoramaUri`, it builds the scene from your panorama. The request is asynchronous: it answers immediately with a `queued` [Scene Task](/v1/api-reference/scenes/get) whose ID starts with `scn_`, and you poll [Get Scene Task](/v1/api-reference/scenes/get) until it finishes.

Instead of hosting your panorama at a `panoramaUri`, you can upload the image file with the request — see [Upload a panorama file](#upload-a-panorama-file).

A ready `pano` task gives you the scene as an `.spz` Gaussian splat, the panorama, and an `initial` image batch of posed views. Pass that batch's `batchId` to [Generate Scene Views](/v1/api-reference/scenes/generate) and [Reconstruct Scene](/v1/api-reference/scenes/reconstruct) to extend the scene.

<Note>
  **Pricing** (1 credit = $0.01): **6 credits ($0.06)\*\* for a scene from a `prompt`, whose panorama is generated first; **1 credit (\$0.01)** for a scene from your own `panoramaUri`. Credits are reserved when the task is submitted and refunded in full unless it finishes `ready`. See [Pricing](/v1/pricing#scene-model).
</Note>

## Sessions

Every scene request names a `sessionId` of your choosing. A session holds one scene and every image batch made for it:

* `sessionId` is 1–128 ASCII letters, digits, underscores, or hyphens. It is scoped to your account, so it can't collide with another customer's.
* A session runs **one task at a time**. Submitting while a task is still `queued` or `processing` answers `409`, before anything is charged, with that task's ID in `error.details.running_task_id` — poll it, then submit again.
* `referenceBatchIds` on `generate` and `reconstruct` only accept batches made in the same session; a batch from another session fails the task with `INVALID_REQUEST`.

## Request parameters

Send `application/json`, up to 1 MiB, or `multipart/form-data` to upload the panorama file itself — see [Upload a panorama file](#upload-a-panorama-file). Unknown fields are rejected.

| Parameter | Type | Required | Default | Description |
| - | - | :-: | - | - |
| `sessionId` | string | Yes | — | Session to build the scene in — see [Sessions](#sessions). |
| `prompt` | string | One of `prompt` / `panoramaUri` / `panorama` | — | Description of the scene, 1–1000 characters, not blank. The panorama is generated from it. |
| `referenceImages` | string\[] | No | `[]` | Up to 8 image URLs that guide panorama generation. Only with `prompt`. |
| `quality` | string | No | `low` | Panorama generation quality: `fast`, `low`, `medium`, or `high`. Only with `prompt`. |
| `panoramaUri` | string | One of `prompt` / `panoramaUri` / `panorama` | — | URL of an existing 360° panorama image to build the scene from. Can't be combined with `prompt`, `referenceImages`, or `quality`. |
| `panorama` | file | One of `prompt` / `panoramaUri` / `panorama` | — | Your 360° panorama image as a file — JPEG, PNG, or WebP, up to 50 MiB. Multipart only; see [Upload a panorama file](#upload-a-panorama-file). Can't be combined with `panoramaUri`, `prompt`, `referenceImages`, or `quality`. |
| `spzOutputUrl` | string | No | — | Your own upload URL for the `.spz` scene — see [Upload to your own storage](#upload-to-your-own-storage). |
| `outputUris` | object | No | — | Your own upload URLs per file: `spz`, `preview`, `panorama`. Can't be combined with `spzOutputUrl`. |

### Upload a panorama file

To build the scene from a panorama on your machine, send the request as `multipart/form-data` instead of JSON, with the image in a `panorama` file field:

* The other fields are the same as in the JSON body, each sent once. `sessionId`, `panoramaUri`, `prompt`, `quality`, and `spzOutputUrl` are plain text; `referenceImages` and `outputUris` carry their JSON value as text, for example `outputUris={"spz":"https://..."}`.
* Send at most one file, named `panorama`. It must be 1 byte to 50 MiB, and its content must be a JPEG, PNG, or WebP image — the type is detected from the bytes, not from the file name or its `Content-Type`.
* The file takes the place of `panoramaUri`: sending both is rejected, and so is a file together with `prompt`, `referenceImages`, or `quality`.
* It is priced the same as a scene from `panoramaUri`.

Viggle stores the file only once the rest of the request is valid, and the scene model reads it the way it reads a `panoramaUri`. An upload that stops arriving before the server's read deadline answers `408 UPLOAD_TIMEOUT`; retry it, or host the image and pass `panoramaUri` instead.

### URL rules

`panoramaUri`, `referenceImages`, `spzOutputUrl`, and `outputUris` are fetched or written by Viggle's servers, so each must be:

* `http` or `https`, without a username or password, with a valid port if one is given;
* on a host that resolves only to public internet addresses. Private, loopback, link-local, and carrier-grade NAT addresses are rejected with `400`.

### Upload to your own storage

`spzOutputUrl`, or `outputUris.spz` / `outputUris.preview` / `outputUris.panorama`, are URLs Viggle uploads the finished file to with an HTTP `PUT` — typically presigned upload URLs from S3, R2, or GCS. They are optional; without them, download the files from the task result while it is readable.

* `spzOutputUrl` is the same as `outputUris.spz`; send one or the other.
* An `.spz` sent to your URL is **not** kept by Viggle: the result's `spz.url` is your URL.
* A preview or panorama sent to your URL is also kept by Viggle, and the result still links to Viggle's signed copy.
* A `null` entry in `outputUris` is ignored. The same fields are accepted by every scene operation.

## Response parameters

Returns `200 OK` with a Scene Task — the same shape [Get Scene Task](/v1/api-reference/scenes/get) returns. It is usually `queued`, with `queuePosition` tasks ahead of it, or already `processing` if a slot was free. `credits` is what the task reserved — here 6, for a scene from a prompt:

```json theme={null}
{
  "id": "scn_0199f0c2-6a1e-7c3d-9b2a-4f5e6d7c8b9a.living-room-01",
  "sessionId": "living-room-01",
  "operation": "pano",
  "status": "queued",
  "credits": 6,
  "queuePosition": 0,
  "createdAt": 1791856740000,
  "completedAt": null,
  "result": null,
  "error": null
}
```

## Common errors

| Error | Cause |
| - | - |
| `400 INVALID_REQUEST` | A field is missing, invalid, or unknown, or a URL breaks the [URL rules](#url-rules). `message` names the field. No task starts. |
| `400 INVALID_REQUEST` (multipart) | The form is malformed, a field is sent twice, a JSON-valued field isn't valid JSON, a file other than one `panorama` is sent, or the panorama exceeds 50 MiB or isn't a JPEG, PNG, or WebP image. |
| `401 UNAUTHENTICATED` | Missing or invalid API key. |
| `402 INSUFFICIENT_CREDITS` | The balance can't cover the task's price. Nothing is queued. |
| `408 UPLOAD_TIMEOUT` | A multipart upload didn't finish arriving in time. Retryable. |
| `409 INVALID_REQUEST` | The session already has a task `queued` or `processing`. `error.details.running_task_id` is that task; poll it before submitting again. |
| `429 RATE_LIMITED` | Too many concurrent submissions on the same key. Retry shortly. |
| `503 SERVICE_BUSY` | The scene model is temporarily unavailable. Retryable. |

A task that starts can still fail later; see [Status and errors](/v1/api-reference/scenes/get#status-and-errors).

## Examples

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://apis.viggle.ai/v1/scenes/pano \
    -H "Authorization: Bearer $VIGGLE_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "sessionId": "living-room-01",
      "prompt": "A sunlit Scandinavian living room with a grey sofa and large windows",
      "quality": "low"
    }'
  ```

  ```python Python theme={null}
  import os, requests
  response = requests.post(
      "https://apis.viggle.ai/v1/scenes/pano",
      headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}"},
      json={
          "sessionId": "living-room-01",
          "prompt": "A sunlit Scandinavian living room with a grey sofa and large windows",
          "quality": "low",
      },
  )
  response.raise_for_status()
  task = response.json()
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch("https://apis.viggle.ai/v1/scenes/pano", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${process.env.VIGGLE_API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      sessionId: "living-room-01",
      prompt: "A sunlit Scandinavian living room with a grey sofa and large windows",
      quality: "low",
    }),
  });
  const task = await response.json();
  ```
</CodeGroup>

### From an existing panorama

```bash theme={null}
curl -X POST https://apis.viggle.ai/v1/scenes/pano \
  -H "Authorization: Bearer $VIGGLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "courtyard-01",
    "panoramaUri": "https://example.com/courtyard-360.jpg"
  }'
```

To place the panorama at a known position and scale in your own world, use [Create Scene from Custom Panorama](/v1/api-reference/scenes/custom-pano) instead.

### From a local panorama file

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST https://apis.viggle.ai/v1/scenes/pano \
    -H "Authorization: Bearer $VIGGLE_API_KEY" \
    -F sessionId=courtyard-01 \
    -F panorama=@courtyard-360.jpg
  ```

  ```python Python theme={null}
  import os, requests
  with open("courtyard-360.jpg", "rb") as f:
      response = requests.post(
          "https://apis.viggle.ai/v1/scenes/pano",
          headers={"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}"},
          data={"sessionId": "courtyard-01"},
          files={"panorama": f},
      )
  response.raise_for_status()
  task = response.json()
  ```

  ```javascript JavaScript theme={null}
  import { openAsBlob } from "node:fs";

  const form = new FormData();
  form.append("sessionId", "courtyard-01");
  form.append("panorama", await openAsBlob("courtyard-360.jpg"), "courtyard-360.jpg");
  const response = await fetch("https://apis.viggle.ai/v1/scenes/pano", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.VIGGLE_API_KEY}` },
    body: form,
  });
  const task = await response.json();
  ```
</CodeGroup>

Don't set `Content-Type` yourself: the client adds `multipart/form-data` with its boundary.

### With reference images and your own storage

```bash theme={null}
curl -X POST https://apis.viggle.ai/v1/scenes/pano \
  -H "Authorization: Bearer $VIGGLE_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "sessionId": "loft-01",
    "prompt": "An industrial loft with exposed brick and warm evening light",
    "referenceImages": ["https://example.com/loft-a.jpg", "https://example.com/loft-b.jpg"],
    "quality": "high",
    "outputUris": {
      "spz": "https://my-bucket.s3.amazonaws.com/scenes/loft-01.spz?X-Amz-Signature=...",
      "panorama": "https://my-bucket.s3.amazonaws.com/scenes/loft-01.png?X-Amz-Signature=..."
    }
  }'
```

## Next step

<CardGroup cols={2}>
  <Card title="Get Scene Task" icon="magnifying-glass" href="/v1/api-reference/scenes/get">
    Poll the task and read the result.
  </Card>

  <Card title="Quick Start: Scene Model" icon="rocket" href="/v1/guides/quickstart-scene">
    The full build, generate, and reconstruct flow.
  </Card>
</CardGroup>


## OpenAPI

````yaml openapi.yaml POST /v1/scenes/pano
openapi: 3.0.3
info:
  title: Viggle API
  description: Generate AI-powered character animation videos
  version: 2.0.0
  contact:
    name: Viggle Support
    url: https://viggle.ai
servers:
  - url: https://apis.viggle.ai
    description: Production server
security:
  - bearerAuth: []
tags:
  - name: Renders
    description: Prepare inputs, create renders, observe progress, and retrieve results.
  - name: Credits
    description: Read the credit balance available to the calling principal.
  - name: Characters
    description: |
      Create, list, inspect, and delete reusable character assets. `type`
      selects whether creation also extracts a 3D vsplat; export its
      download URL separately once ready.
  - name: Motions
    description: |
      Create, list, inspect, and delete reusable motion assets, and import one
      from an official motion template. `type` selects whether creation also
      extracts or generates a 3D animation; export its download URL
      separately once ready.
  - name: Videos
    description: >
      Generate a MiniMax H3 video from text, frames, or references (`vid_`

      prefix) or a character-animation video from a character image and/or
      driving video

      (`anim_` prefix), and read the unified view over every video the

      caller owns — H3 generations, character-animation generations, and

      character+motion Renders (`render_` prefix) — merged into one

      resource.
  - name: Images
    description: |
      Viggle Image — generate 1–6 PNG images from a text prompt with the
      `qwen` model, optionally guided by up to 8 reference images
      (`img_` prefix), and retrieve them by ID.
  - name: Scenes
    description: |
      Scene model — build a 3D Gaussian-splat scene (`.spz`) from a text
      prompt or a 360° panorama, generate new posed views of it, and
      reconstruct it from those views. Every operation is an asynchronous
      task (`scn_` prefix) read back by ID. A pano from a prompt costs 6
      credits; every other scene task costs 1. Credits are refunded in full
      unless the task finishes `ready`.
paths:
  /v1/scenes/pano:
    post:
      tags:
        - Scenes
      summary: Create a scene
      description: >
        Builds a 3D Gaussian-splat scene from `prompt` (a 360° panorama is
        generated

        first, optionally guided by `referenceImages`), from `panoramaUri`, or

        from a `panorama` file uploaded as `multipart/form-data`.

        Answers `200` at once with a `queued` `SceneTask`; poll

        `GET /v1/scenes/{task_id}`. A ready result has `spz`, `panorama`, and an

        `initial` `outputBatch`. Costs 6 credits from `prompt`, 1 from

        `panoramaUri`.
      operationId: createScene
      parameters:
        - $ref: '#/components/parameters/RequestId'
        - $ref: '#/components/parameters/SourceChannel'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ScenePanoRequest'
          multipart/form-data:
            schema:
              $ref: '#/components/schemas/ScenePanoForm'
      responses:
        '200':
          description: Scene task started.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SceneTask'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/V1Unauthorized'
        '402':
          $ref: '#/components/responses/PaymentRequired'
        '408':
          $ref: '#/components/responses/SceneUploadTimeout'
        '409':
          $ref: '#/components/responses/SceneSessionBusy'
        '429':
          $ref: '#/components/responses/RateLimited'
        '503':
          $ref: '#/components/responses/ServiceUnavailable'
components:
  parameters:
    RequestId:
      name: X-Request-Id
      in: header
      required: false
      description: >-
        Optional caller-supplied correlation ID, up to 128 characters. The
        service returns the effective value in the response header for tracing
        and support.
      schema:
        type: string
        minLength: 1
        maxLength: 128
    SourceChannel:
      name: X-Viggle-Source
      in: header
      required: false
      description: >-
        Optional source-channel label, up to 128 characters, used to attribute
        traffic to an SDK, integration, product surface, or internal workflow.
      schema:
        type: string
        minLength: 1
        maxLength: 128
  schemas:
    ScenePanoRequest:
      type: object
      additionalProperties: false
      description: |
        Body of `POST /v1/scenes/pano`. Send either `prompt` (optionally
        with `referenceImages` and `quality`) or `panoramaUri`, not both.
        `spzOutputUrl` and `outputUris` are mutually exclusive. Input URLs
        must be `http(s)`, without credentials, on a host that resolves
        only to public addresses.
      required:
        - sessionId
      properties:
        sessionId:
          $ref: '#/components/schemas/SceneSessionId'
        prompt:
          type: string
          minLength: 1
          maxLength: 1000
          description: >-
            Scene description; a 360° panorama is generated from it. Must not be
            blank.
        referenceImages:
          type: array
          maxItems: 8
          description: Image URLs that guide panorama generation. Only with `prompt`.
          items:
            type: string
            format: uri
        quality:
          type: string
          enum:
            - fast
            - low
            - medium
            - high
          default: low
          description: Panorama generation quality. Only with `prompt`.
        panoramaUri:
          type: string
          format: uri
          description: >-
            URL of an existing 360° panorama to build the scene from. Not
            combinable with `prompt`, `referenceImages`, or `quality`.
        spzOutputUrl:
          type: string
          format: uri
          description: Same as `outputUris.spz`.
        outputUris:
          $ref: '#/components/schemas/SceneOutputUris'
    ScenePanoForm:
      type: object
      additionalProperties: false
      description: |
        Multipart form of `POST /v1/scenes/pano`, for uploading the panorama
        file itself. The fields are those of the JSON body, each sent once;
        `referenceImages` and `outputUris` carry their JSON value as text.
        At most one file, `panorama`, is allowed, and it replaces
        `panoramaUri`: it can't be combined with `panoramaUri`, `prompt`,
        `referenceImages`, or `quality`. Priced as a scene from
        `panoramaUri`.
      required:
        - sessionId
      properties:
        sessionId:
          $ref: '#/components/schemas/SceneSessionId'
        panorama:
          type: string
          format: binary
          description: >-
            The 360° panorama image, used instead of `panoramaUri`: 1 byte to 50
            MiB, a JPEG, PNG, or WebP image as detected from its bytes. The only
            file the form may carry.
        panoramaUri:
          type: string
          format: uri
          description: >-
            URL of an existing 360° panorama. Not combinable with the `panorama`
            file, `prompt`, `referenceImages`, or `quality`.
        prompt:
          type: string
          minLength: 1
          maxLength: 1000
        referenceImages:
          type: string
          description: >-
            JSON array of up to 8 image URLs, as text, that guide panorama
            generation. Only with `prompt`.
        quality:
          type: string
          enum:
            - fast
            - low
            - medium
            - high
          default: low
        spzOutputUrl:
          type: string
          format: uri
          description: Same as `outputUris.spz`.
        outputUris:
          type: string
          description: >-
            `SceneOutputUris` as JSON text, for example `{"spz":
            "https://..."}`.
    SceneTask:
      type: object
      additionalProperties: false
      description: >
        A scene task (`scn_` prefix), returned by every `/v1/scenes`

        submission and by `GET /v1/scenes/{task_id}`. It starts `queued` (or

        `processing` when a GPU slot is free); `ready`, `failed`, and

        `cancelled` are terminal. Only a `ready` task keeps its credits. A task
        stays readable for about 72 hours

        after it finishes.
      required:
        - id
        - sessionId
        - operation
        - status
        - credits
        - createdAt
        - completedAt
        - result
        - error
      properties:
        id:
          type: string
          description: Task ID, `scn_{runId}.{sessionId}`.
        sessionId:
          type: string
        operation:
          type: string
          enum:
            - pano
            - generate
            - reconstruct
          description: A custom-pano task reports `pano`.
        status:
          type: string
          enum:
            - queued
            - processing
            - ready
            - failed
            - cancelled
        queuePosition:
          type: integer
          minimum: 0
          description: >-
            Only while `queued`: tasks waiting ahead of this one, 0 when it is
            next.
        credits:
          type: number
          minimum: 0
          description: >-
            Credits this task is charged: reserved at submission (6 for a pano
            from a prompt, 1 for any other task) and 0 once a task that did not
            finish `ready` is refunded.
        createdAt:
          type: integer
          format: int64
          nullable: true
          description: Start time, Unix milliseconds.
        completedAt:
          type: integer
          format: int64
          nullable: true
          description: End time, Unix milliseconds; null while queued or processing.
        result:
          description: Set only when `ready`.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/SceneResult'
        error:
          description: |
            Set only when `failed`. `code` is `INVALID_REQUEST` (not
            retryable — the model rejected the input, such as a batch from
            another session) or `PROCESSING_FAILED` (retryable).
          nullable: true
          allOf:
            - $ref: '#/components/schemas/ErrorBody'
    SceneSessionId:
      type: string
      minLength: 1
      maxLength: 128
      pattern: ^[A-Za-z0-9_-]+$
      description: |
        Session chosen by the caller, scoped to the caller's account. A
        session holds one scene and its image batches, and runs one task at
        a time: a submission while a task is still `processing` answers
        `409` with that task in `error.details.running_task_id`.
      example: living-room-01
    SceneOutputUris:
      type: object
      additionalProperties: false
      description: |
        The caller's own upload URLs; Viggle `PUT`s each finished file to
        its URL. Null entries are ignored. An `.spz` sent here is not kept
        by Viggle, and the result's `spz.url` is this URL; a preview or
        panorama sent here is also kept, and the result links to Viggle's
        copy. Each URL must be `http(s)`, without credentials, on a host
        that resolves only to public addresses.
      properties:
        spz:
          type: string
          format: uri
          nullable: true
        preview:
          type: string
          format: uri
          nullable: true
        panorama:
          type: string
          format: uri
          nullable: true
    SceneResult:
      type: object
      required:
        - operation
        - sessionId
        - spz
        - preview
        - panorama
        - outputBatch
        - referenceViewCount
        - newViewCount
        - seconds
      properties:
        operation:
          type: string
          enum:
            - pano
            - generate
            - reconstruct
        sessionId:
          type: string
        spz:
          description: >-
            The Gaussian-splat scene in SPZ format; set by `pano` and
            `reconstruct`.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/SceneFile'
        preview:
          description: A preview image, when the operation produced one.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/SceneFile'
        panorama:
          description: The panorama the scene was built from; set by `pano`.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/SceneFile'
        outputBatch:
          description: The batch this task added; null for `reconstruct`.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/SceneOutputBatch'
        referenceViewCount:
          type: integer
          description: Views read from `referenceBatchIds`.
        newViewCount:
          type: integer
          description: New views produced.
        seconds:
          type: object
          description: Processing time by stage, in seconds. Informational; keys vary.
          additionalProperties:
            type: number
    ErrorBody:
      type: object
      additionalProperties: false
      required:
        - code
        - message
        - retryable
        - request_id
        - details
        - remediation
      properties:
        code:
          description: Stable error category from the draft-based render error vocabulary.
          allOf:
            - $ref: '#/components/schemas/ErrorCode'
        message:
          type: string
          description: >-
            Human-readable explanation suitable for logs or presentation to a
            developer.
        retryable:
          type: boolean
          description: >-
            Whether retrying the operation without changing its semantic input
            may succeed.
        request_id:
          type: string
          description: >-
            Correlation identifier for tracing and support. Include it when
            reporting the failure.
        details:
          type: object
          description: Error-specific structured context; available keys depend on `code`.
          additionalProperties: true
        remediation:
          description: Suggested recovery action and optional retry delay.
          allOf:
            - $ref: '#/components/schemas/ErrorRemediation'
    ErrorResponse:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          description: >-
            Top-level draft-flow error payload containing the stable code,
            message, retry guidance, correlation ID, and error-specific details.
          allOf:
            - $ref: '#/components/schemas/ErrorBody'
    SceneFile:
      type: object
      additionalProperties: false
      required:
        - url
      properties:
        url:
          type: string
          format: uri
          description: >-
            Download URL. Viggle's signed URLs last 3 hours; fetch the task
            again for fresh ones. For an `.spz` sent to the caller's own URL,
            that URL.
    SceneOutputBatch:
      type: object
      additionalProperties: false
      required:
        - batchId
        - createdAt
        - manifest
      description: >-
        The image batch a `pano` or `generate` task added to the session. `kind`
        and `views` are missing on tasks that finished before they were
        introduced.
      properties:
        batchId:
          type: string
          description: Batch ID, a lowercase UUID; pass it in `referenceBatchIds`.
        createdAt:
          type: number
          description: Batch creation time, Unix milliseconds.
        manifest:
          $ref: '#/components/schemas/SceneFile'
        kind:
          type: string
          enum:
            - initial
            - generated
        views:
          type: array
          items:
            $ref: '#/components/schemas/SceneView'
    ErrorCode:
      description: |
        The failure vocabulary of the draft-based render flow. The resource
        operations project the same vocabulary onto the lower_snake_case codes
        described by `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
        - NOT_FOUND
        - TASK_FAILED
        - PROCESSING_FAILED
    ErrorRemediation:
      type: object
      additionalProperties: false
      required:
        - action
        - retry_after_ms
      properties:
        action:
          type: string
          description: >-
            Suggested machine-readable or human-readable next action, such as
            retrying later, uploading media again, or correcting input.
        retry_after_ms:
          type: integer
          description: >-
            Recommended delay in milliseconds before retrying; null when no
            timed retry is advised.
          nullable: true
          format: int64
          minimum: 0
    SceneView:
      type: object
      additionalProperties: false
      required:
        - index
        - url
        - c2w
        - intrinsic
      properties:
        index:
          type: integer
          minimum: 0
          description: Position in the batch, from 0.
        url:
          type: string
          format: uri
          description: Signed download URL of the image, valid for 3 hours.
        c2w:
          $ref: '#/components/schemas/SceneMatrix'
        intrinsic:
          type: array
          description: Camera intrinsics, as recorded in the batch manifest.
          items:
            type: number
    SceneMatrix:
      type: array
      description: >-
        4 × 4 camera-to-world matrix as four rows of four finite numbers; the
        last row must be `[0, 0, 0, 1]`.
      minItems: 4
      maxItems: 4
      items:
        type: array
        minItems: 4
        maxItems: 4
        items:
          type: number
      example:
        - - 1
          - 0
          - 0
          - 0
        - - 0
          - 1
          - 0
          - 0
        - - 0
          - 0
          - 1
          - 0
        - - 0
          - 0
          - 0
          - 1
  headers:
    RequestId:
      description: Stable request identifier for support and tracing.
      schema:
        type: string
  responses:
    BadRequest:
      description: Invalid request.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    V1Unauthorized:
      description: Missing, invalid, or expired credential.
      headers:
        WWW-Authenticate:
          schema:
            type: string
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    PaymentRequired:
      description: Insufficient credits.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    SceneUploadTimeout:
      description: >-
        A multipart upload did not finish arriving before the read deadline.
        Code `UPLOAD_TIMEOUT`, retryable: retry, or pass `panoramaUri` instead.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    SceneSessionBusy:
      description: >-
        The session already has a task queued or running;
        `error.details.running_task_id` names it. Code `INVALID_REQUEST`.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    RateLimited:
      description: Rate limit exceeded.
      headers:
        Retry-After:
          schema:
            type: integer
            minimum: 0
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    ServiceUnavailable:
      description: Service temporarily unavailable.
      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: |
        Server-side SDK clients use a project API key. Remote MCP clients use
        an OAuth access token. Never expose a project API key in browser code.

````

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