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

# Quick Start: Mocap

> Turn a motion video into a downloadable FBX animation.

Upload one motion video to create an asynchronous 3D animation. When the task is ready, download the FBX from `model_url`.

## What you need

* An API key from the [Viggle Dashboard](https://portal.viggle.ai/keys)
* A motion video, such as `motion.mp4`

## Create and poll the animation

<CodeGroup>
  ```go Go theme={null}
  // Requires: bytes, encoding/json, io, mime/multipart, net/http, os, time.
  file, err := os.Open("motion.mp4")
  if err != nil { panic(err) }
  defer file.Close()

  body := &bytes.Buffer{}
  writer := multipart.NewWriter(body)
  part, _ := writer.CreateFormFile("video", "motion.mp4")
  io.Copy(part, file)
  writer.Close()

  req, _ := http.NewRequest("POST", "https://apis.viggle.ai/v1/animations", body)
  req.Header.Set("Authorization", "Bearer "+os.Getenv("VIGGLE_API_KEY"))
  req.Header.Set("Content-Type", writer.FormDataContentType())
  resp, err := http.DefaultClient.Do(req)
  if err != nil { panic(err) }
  defer resp.Body.Close()
  ```

  ```javascript JavaScript theme={null}
  const form = new FormData();
  form.append("video", motionVideoFile);

  let animation = await fetch("https://apis.viggle.ai/v1/animations", {
    method: "POST",
    headers: { Authorization: `Bearer ${process.env.VIGGLE_API_KEY}` },
    body: form,
  }).then((response) => response.json());

  while (!["ready", "failed"].includes(animation.status)) {
    await new Promise((resolve) => setTimeout(resolve, 5000));
    animation = await fetch(`https://apis.viggle.ai/v1/animations/${animation.id}`, {
      headers: { Authorization: `Bearer ${process.env.VIGGLE_API_KEY}` },
    }).then((response) => response.json());
  }

  if (animation.status !== "ready") throw new Error(animation.error?.message);
  console.log(animation.model_url);
  ```

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

  headers = {"Authorization": f"Bearer {os.environ['VIGGLE_API_KEY']}"}
  with open("motion.mp4", "rb") as video:
      response = requests.post(
          "https://apis.viggle.ai/v1/animations",
          headers=headers,
          files={"video": video},
      )
  response.raise_for_status()
  animation = response.json()

  while animation["status"] not in {"ready", "failed"}:
      time.sleep(5)
      response = requests.get(
          f"https://apis.viggle.ai/v1/animations/{animation['id']}", headers=headers
      )
      response.raise_for_status()
      animation = response.json()

  if animation["status"] != "ready":
      raise RuntimeError(animation["error"])
  print(animation["model_url"])
  ```

  ```bash cURL theme={null}
  curl -X POST "https://apis.viggle.ai/v1/animations" \
    -H "Authorization: Bearer $VIGGLE_API_KEY" \
    -F "video=@motion.mp4"
  ```
</CodeGroup>

## Response

```json theme={null}
{
  "id": "anim_123abc",
  "status": "queued",
  "model_url": null,
  "created_at": null,
  "updated_at": null,
  "error": null
}
```

Poll `GET /v1/animations/{animation_id}` every five seconds. When `status` is `ready`, `model_url` points to the generated FBX. Download it promptly; task records and signed URLs are retained for one hour.

<Card title="Animation API reference" icon="box" href="/v1/api-reference/conversion/create-animation">
  See every request and response field.
</Card>
