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

# Export 3D Motion (for 3D/game engines)

> Get a signed download URL for a Motion's 3D animation extraction or generation.

Only meaningful for a Motion created with `type` `glb` or `all`, or generated from text via `POST /v1/motions` with `application/json`; a `render`-only Motion has nothing to export. This replaces the old, now-removed `GET /v1/animations/{animation_id}`.

`download_type` is the skeleton choice itself — `mixamo` or `metahuman` — not a separate output format. There is no `fbx`, and both skeleton variants are always generated up front, so switching between them on the same `motion_id` never triggers new work or waits on a regeneration. The exported GLB works with **Mixamo**, **MetaHuman**, and other **Unity-compatible** animation workflows.

## Request parameters

| Parameter       | Type   | Required | Description                                                                                                                                            |
| --------------- | ------ | :------: | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `motion_id`     | string |    Yes   | Complete Motion ID returned by Create, Generate, Import, or List Motions. The Motion must contain a requested 3D animation output to expose an export. |
| `download_type` | string |    No    | Selects which pre-generated skeleton variant's glb to download: `mixamo` or `metahuman`. Omit to retrieve status only.                                 |

## Response parameters

Returns `200 OK`.

| Field           | Type           | Always present | Description                                                                                   |
| --------------- | -------------- | :------------: | --------------------------------------------------------------------------------------------- |
| `id`            | string         |       Yes      | Requested public Motion ID.                                                                   |
| `status`        | string         |       Yes      | `queued`, `processing`, `ready`, or `failed`.                                                 |
| `download_type` | string or null |       Yes      | Echoes the requested `download_type` — also the skeleton variant selected. `null` if omitted. |
| `glb_url`       | string or null |       Yes      | Populated only when `download_type` is set and that skeleton variant is ready.                |
| `thumbnail_url` | null           |       Yes      | Always `null` — animations have no thumbnail.                                                 |
| `created_at`    | string or null |       Yes      | ISO 8601 timestamp. May be an empty string on a task that has not recorded one.               |
| `updated_at`    | string or null |       Yes      | ISO 8601 timestamp of the most recent update.                                                 |
| `error`         | object or null |       Yes      | Structured failure details when `status` is `failed`.                                         |

```json theme={null}
{
  "id": "mot_456def",
  "status": "ready",
  "download_type": "mixamo",
  "glb_url": "https://assets.viggle.ai/results/animation_mixamo.glb",
  "thumbnail_url": null,
  "created_at": "2026-07-21T10:00:00+00:00",
  "updated_at": "2026-07-21T10:01:00+00:00",
  "error": null
}
```

Request `metahuman` for the same Motion instead — no regeneration needed:

```json theme={null}
{
  "id": "mot_456def",
  "status": "ready",
  "download_type": "metahuman",
  "glb_url": "https://assets.viggle.ai/results/animation_metahuman.glb",
  "thumbnail_url": null,
  "created_at": "2026-07-21T10:00:00+00:00",
  "updated_at": "2026-07-21T10:01:00+00:00",
  "error": null
}
```

## Examples

<CodeGroup>
  ```go Go theme={null}
  req,_:=http.NewRequest("GET","https://apis.viggle.ai/v1/motions/mot_456def/export?download_type=mixamo",nil); req.Header.Set("Authorization","Bearer "+os.Getenv("VIGGLE_API_KEY")); resp,err:=http.DefaultClient.Do(req); if err!=nil {panic(err)}; defer resp.Body.Close()
  ```

  ```javascript JavaScript theme={null}
  const response=await fetch("https://apis.viggle.ai/v1/motions/mot_456def/export?download_type=mixamo",{headers:{Authorization:`Bearer ${process.env.VIGGLE_API_KEY}`}}); const exported=await response.json();
  ```

  ```python Python theme={null}
  import os, requests
  response=requests.get("https://apis.viggle.ai/v1/motions/mot_456def/export",params={"download_type":"mixamo"},headers={"Authorization":f"Bearer {os.environ['VIGGLE_API_KEY']}"}); response.raise_for_status(); exported=response.json()
  ```

  ```bash cURL theme={null}
  curl "https://apis.viggle.ai/v1/motions/mot_456def/export?download_type=mixamo" -H "Authorization: Bearer $VIGGLE_API_KEY"
  ```
</CodeGroup>

<Tip>
  Download URLs are short-lived and re-signed on every read — request `download_type` again rather than caching the URL.
</Tip>

## Next step

A text-generated Motion has no 2D render counterpart — only this export applies. A video-sourced `glb`/`all` Motion also keeps its `video_render` capability; use [Render Video (from Character and/or Motion)](/v1/api-reference/renders/create) with `motion_id` for that side once it's ready.


## OpenAPI

````yaml openapi.yaml GET /v1/motions/{motion_id}/export
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 text-to-video (`vid_` prefix), and read the
      unified view over every video the caller owns — H3 generations and
      character+motion Renders (`render_` prefix) — merged into one
      resource.
paths:
  /v1/motions/{motion_id}/export:
    parameters:
      - $ref: '#/components/parameters/MotionId'
      - $ref: '#/components/parameters/RequestId'
      - $ref: '#/components/parameters/SourceChannel'
    get:
      tags:
        - Motions
      summary: Get a signed download URL for a motion's 3D animation extraction
      description: |
        Only meaningful for a motion created with `type` `glb` or
        `all`, or generated from text via `POST /v1/motions` with
        `application/json`; a `render`-only motion has nothing to export.
        `download_type` is the skeleton choice itself — `mixamo` or
        `metahuman` — both generated up front, so switching between them on
        the same `motion_id` never triggers new work. There is no `fbx`.
        Replaces the old `GET /v1/animations/{animation_id}`.
      operationId: exportMotion
      parameters:
        - name: download_type
          in: query
          required: false
          description: >-
            Selects which pre-generated skeleton rig to return as a signed GLB
            URL: `mixamo` for Mixamo-compatible rigs or `metahuman` for
            MetaHuman-compatible rigs.
          schema:
            type: string
            enum:
              - mixamo
              - metahuman
      responses:
        '200':
          description: Current animation export state.
          headers:
            X-Request-Id:
              $ref: '#/components/headers/RequestId'
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/MotionExport'
        '400':
          $ref: '#/components/responses/ResourceBadRequest'
        '401':
          $ref: '#/components/responses/ResourceUnauthorized'
        '404':
          $ref: '#/components/responses/ResourceNotFound'
        '409':
          $ref: '#/components/responses/ResourceConflict'
        '500':
          $ref: '#/components/responses/ResourceInternalServerError'
        '502':
          $ref: '#/components/responses/ResourceBadGateway'
        '503':
          $ref: '#/components/responses/ResourceServiceUnavailable'
components:
  parameters:
    MotionId:
      name: motion_id
      in: path
      required: true
      description: >-
        Public Motion ID returned by motion creation or listing. It normally
        begins with `mot_` and must identify a Motion owned by the caller.
      schema:
        type: string
        minLength: 1
      example: mot_7d2e9f1a3c5b4e8d9f0a1b2c3d4e5f60
    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
  headers:
    RequestId:
      description: Stable request identifier for support and tracing.
      schema:
        type: string
  schemas:
    MotionExport:
      description: |
        A motion's 3D animation extraction (video source) or generation
        (text source), for download. `glb_url` is populated only when the
        request carried a `download_type`, which is itself the skeleton
        choice — `mixamo` or `metahuman` — both generated up front, so
        switching between them on the same `motion_id` never triggers new
        work. There is no `fbx`. Download URLs are short-lived and
        re-signed on every read. Formerly `AnimationResource`, returned by
        the now-removed `GET /v1/animations/{animation_id}`.
      type: object
      additionalProperties: false
      required:
        - id
        - status
        - download_type
        - glb_url
        - thumbnail_url
        - created_at
        - updated_at
        - error
      properties:
        id:
          type: string
          description: ID of the Motion whose 3D animation export is represented.
          minLength: 1
        status:
          description: >-
            Current lifecycle of the 3D animation extraction or generation.
            Download only when this is `ready` and `glb_url` is populated.
          allOf:
            - $ref: '#/components/schemas/ResourceStatus'
        download_type:
          description: >-
            Echoes the requested `download_type` — also the skeleton variant
            selected.
          type: string
          nullable: true
          enum:
            - mixamo
            - metahuman
            - null
        glb_url:
          type: string
          description: >-
            Short-lived signed URL for the selected skeleton variant's GLB when
            the export is ready; otherwise null.
          nullable: true
        thumbnail_url:
          description: >-
            Reserved for response-shape compatibility and always null because
            Motion animation exports do not generate thumbnails.
          type: string
          nullable: true
        created_at:
          description: >-
            ISO 8601 timestamp with a UTC offset. May be an empty string on a
            task that has not recorded one.
          type: string
          nullable: true
        updated_at:
          type: string
          description: >-
            ISO 8601 timestamp with a UTC offset for the latest 3D animation
            state update; null if unavailable.
          nullable: true
        error:
          type: object
          description: >-
            Structured extraction or generation failure when `status` is
            `failed`; otherwise null.
          nullable: true
          allOf:
            - $ref: '#/components/schemas/ResourceError'
    ResourceStatus:
      description: |
        The public lifecycle shared by every asynchronous resource. It carries
        the same values as `RenderStatus`.
      type: string
      enum:
        - queued
        - processing
        - ready
        - failed
        - cancelled
    ResourceError:
      description: |
        The failure attached to an asynchronous resource. `code` is a stable,
        lower_snake_case string and deliberately not an enum: the extraction
        and render workers own this vocabulary and add to it over time, and a
        failure with no published mapping surfaces as `processing_failed`.

        Published codes: `worker_stopped`, `motion_model_mismatch`,
        `image_required`, `motion_video_required`, `unsupported_video_format`,
        `video_too_long`, `video_too_large`, `video_resolution_too_high`,
        `video_unreadable`, `invalid_background_mode`,
        `video_dimensions_must_be_even`, `result_expired`,
        `video_inaccessible`, `no_humans_detected`, `all_workers_busy`,
        `task_failed`, `unexpected_error`, `processing_failed`.
      type: object
      additionalProperties: false
      required:
        - code
        - message
        - request_id
      properties:
        code:
          type: string
          description: >-
            Stable, lower_snake_case asynchronous failure code. The vocabulary
            is open, so clients must tolerate new values.
          minLength: 1
        message:
          type: string
          description: Human-readable explanation of the asynchronous processing failure.
        request_id:
          type: string
          description: >-
            Correlation identifier from the worker or originating request; null
            when unavailable.
          nullable: true
    ResourceErrorResponse:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          description: Top-level synchronous resource-operation error payload.
          allOf:
            - $ref: '#/components/schemas/ResourceHttpError'
    ResourceHttpError:
      description: |
        The failure envelope of a synchronous resource request. Every code is
        produced by one mapping in the API service, so the set is closed; a
        failure with no published mapping surfaces as `processing_failed`.

        The asynchronous `error` object on a resource carries the wider,
        deliberately open vocabulary of `ResourceError` instead.
      type: object
      additionalProperties: false
      required:
        - code
        - message
        - request_id
      properties:
        code:
          type: string
          description: >-
            Closed, lower_snake_case error code for a synchronous resource
            request; use it for programmatic handling.
          enum:
            - authentication_required
            - invalid_api_key
            - insufficient_credits
            - invalid_request
            - motion_not_ready
            - character_not_found
            - motion_not_found
            - not_found
            - id_already_exists
            - rate_limited
            - service_unavailable
            - task_failed
            - internal_error
            - processing_failed
        message:
          type: string
          description: Human-readable explanation of the synchronous request failure.
        request_id:
          description: |
            Always null on a synchronous failure. Correlate with the
            `X-Request-Id` response header instead.
          type: string
          nullable: true
  responses:
    ResourceBadRequest:
      description: |
        Invalid request. The resource operations answer every request-shape
        rejection with `400`; they never answer `422`.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ResourceErrorResponse'
    ResourceUnauthorized:
      description: Missing, invalid, or expired API key.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ResourceErrorResponse'
    ResourceNotFound:
      description: |
        The resource does not exist, or it is not owned by the calling
        principal. The two cases are deliberately indistinguishable.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ResourceErrorResponse'
    ResourceConflict:
      description: The client-supplied task ID is already in use.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ResourceErrorResponse'
    ResourceInternalServerError:
      description: Unexpected server error.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ResourceErrorResponse'
    ResourceBadGateway:
      description: The extraction backend is unavailable or the extraction failed.
      headers:
        X-Request-Id:
          $ref: '#/components/headers/RequestId'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ResourceErrorResponse'
    ResourceServiceUnavailable:
      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/ResourceErrorResponse'
  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.

````