Quickstart | Uthana API Docs

On this page

Get started with the Uthana API in minutes. This guide will help you create your first AI-powered animation.

Official clients:

Using Context7 with the Uthana API

Context7 helps LLMs and AI code editors pull up-to-date documentation and code examples (instead of relying on stale training data). It's designed for AI assistants like Cursor / Claude Code.

  1. Install Context7 in your IDE: Context7 Installation
  2. Add Uthana as a source: https://context7.com/websites/uthana_api (library id: /websites/uthana_api)
  3. Use it in your prompts (example): "How do I create a text-to-motion animation with the Uthana API? use context7 library /websites/uthana_api"

Prerequisites

Step 1: Install the client

# No install needed — use curl directly.
# For the Python client: pip install uthana
pip install uthana

Python async

All Python methods are async by default. The examples on this page use async/await wrapped in asyncio.run(main()). Every method also has a _sync variant (e.g. ttm.create_sync(...)) if you need a synchronous call.

npm install @uthana/client
npm install @uthana/react @uthana/client @tanstack/react-query

There is no official C# client. Use raw GraphQL and HTTP requests — see each step below for C# examples.

Step 2: Authenticate

Connect the client using your API key and confirm the key is valid.

API_KEY="your-api-key"

curl 'https://uthana.com/graphql' \
  -u $API_KEY: \
  -H "Content-Type: application/json" \
  -d '{"query": "{ __typename }"}'

You should see {"data":{"__typename":"Query"}}.

from uthana import Uthana

client = Uthana("your-api-key")

user = client.org.get_user_sync()
print(user.get("name"), user.get("email"))
import { UthanaClient } from "@uthana/client";

const client = new UthanaClient(process.env.UTHANA_API_KEY!);

const user = await client.org.getUser();
console.log(user.name, user.email);

Wrap your app in UthanaProvider once (typically in your root layout). All Uthana hooks work inside it automatically.

import { UthanaProvider, useUthanaUser } from "@uthana/react";

function App() {
  return (
    <UthanaProvider apiKey={process.env.REACT_APP_UTHANA_API_KEY!}>
      <UserInfo />
    </UthanaProvider>
  );
}

function UserInfo() {
  const { user } = useUthanaUser();
  return <p>{user ? `Hello, ${user.name}` : "Loading..."}</p>;
}
using System.Net.Http;
using System.Text;
using System.Text.Json;

private const string ApiUrl = "https://uthana.com/graphql";
private readonly string _apiKey = "your-api-key";

var authValue = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{_apiKey}:")); 
_httpClient.DefaultRequestHeaders.Authorization =
    new System.Net.Http.Headers.AuthenticationHeaderValue("Basic", authValue);

var request = new { query = "{ __typename }" };
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");

var response = await _httpClient.PostAsync(ApiUrl, content);
var responseJson = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseJson);

Step 3: Prepare your character model

(Note: You can skip this step if you're using the default character, "Tar", with the character ID cXi2eAP19XwQ.)

To generate motion for your character, you need to upload a 3D character model in FBX (.fbx) or glTF (.glb/.gltf) format. The easiest way to do this when you're just getting started is to use the Web UI.

  1. Go to the Web UI and sign in.
  2. Click the Upload character button.
  3. Upload your character model in FBX (.fbx) or glTF (.glb/.gltf) format.
  4. Verify that the character is loaded correctly by viewing or generating a motion.
  5. Copy the character ID from the URL: https://uthana.com/app/<character-id>/<motion-id>.
  6. Save the character ID for later use.

You can also upload a character via the API — see Auto-rig / add a character.

Auto-rigging

If your character doesn't have a skeleton rig, Uthana will automatically attempt to create one. Auto-rigging typically takes an additional 30-60 seconds and allows you to use characters that weren't originally rigged for animation.

Step 4: Generate a motion from text

curl 'https://uthana.com/graphql' \
  -u your-api-key: \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation { create_text_to_motion(prompt: \"A person walking down the street\") { motion { id name } } }"
  }'
import asyncio
from uthana import Uthana

client = Uthana("your-api-key")

async def main():
    result = await client.ttm.create("a person walking down the street")
    print(result.character_id, result.motion_id)

asyncio.run(main())
const result = await client.ttm.create("a person walking down the street");
console.log(result.character_id, result.motion_id);
import { useUthanaTtm } from "@uthana/react";

function GenerateButton() {
  const ttm = useUthanaTtm();

return (
    <button onClick={() => ttm.mutate({ prompt: "a person walking down the street" })} disabled={ttm.isPending}>
      {ttm.isPending ? "Generating..." : "Generate motion"}
    </button>
  );
}
}
var query = @"
    mutation {
        create_text_to_motion(prompt: \"A person walking down the street\") {
            motion {
                id
                name
            }
        }
    }";

var request = new { query = query };
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");

var response = await _httpClient.PostAsync(ApiUrl, content);
response.EnsureSuccessStatusCode();

var responseJson = await response.Content.ReadAsStringAsync();
var result = JsonSerializer.Deserialize<GraphQLResponse<CreateTextToMotionData>>(responseJson);

var motion = result.Data.CreateTextToMotion.Motion;
Console.WriteLine($"Created motion: {motion.Id} - {motion.Name}");

Text-to-motion results are returned in the result object.

Step 5: Download your motion

CHARACTER_ID="cXi2eAP19XwQ"  # Default character, or use your own
MOTION_ID="<motion-id-from-step-4>"

# Download the motion as FBX (includes character mesh, filename is customizable)
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/fbx/motion.fbx" \
  -u your-api-key: \
  -o motion.fbx

# Download the motion as GLB (includes character mesh, filename is customizable)
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/glb/motion.glb" \
  -u your-api-key: \
  -o motion.glb

# Download at 30 FPS
curl -L "https://uthana.com/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/fbx/motion.fbx?fps=30" \
  -u your-api-key: \
  -o motion-30fps.fbx

# Download the motion-only GLB (animation data without character mesh, filename is customizable)
curl -L "https://uthana.com/motion/animation/motion_viewer/$CHARACTER_ID/$MOTION_ID/glb/motion.glb" \
  -u your-api-key: \
  -o motion-only.glb
import asyncio
from uthana import Uthana

client = Uthana("your-api-key")

async def main():
    result = await client.ttm.create("a person walking down the street")
    data = await client.motions.download(
        result.character_id,
        result.motion_id,
        output_format="glb",
        fps=30,
    )
    with open("motion.glb", "wb") as f:
        f.write(data)

asyncio.run(main())
const buffer = await client.motions.download(result.character_id, result.motion_id, {
  output_format: "glb",
  fps: 30,
});

// Node.js: write to disk
import { writeFileSync } from "fs";
writeFileSync("motion.glb", Buffer.from(buffer));

// Browser: create a download link
const url = URL.createObjectURL(new Blob([buffer], { type: "model/gltf-binary" }));
import { useUthanaClient } from "@uthana/react";

function DownloadButton({ characterId, motionId }: { characterId: string; motionId: string }) {
  const client = useUthanaClient();

async function download() {
    const buffer = await client.motions.download(characterId, motionId, {
      output_format: "glb",
      fps: 30,
    });
    const url = URL.createObjectURL(new Blob([buffer], { type: "model/gltf-binary" }));
    const a = document.createElement("a");
    a.href = url;
    a.download = "motion.glb";
    a.click();
  }

return <button onClick={download}>Download GLB</button>;
}
private const string CHARACTER_ID = "cXi2eAP19XwQ"; // Default character, or use your own
var motionId = "<motion-id-from-step-4>";

var downloadUrl = $"https://uthana.com/motion/file/motion_viewer/{CHARACTER_ID}/{motionId}/glb/motion.glb?fps=30";
var downloadResponse = await _httpClient.GetAsync(downloadUrl);
downloadResponse.EnsureSuccessStatusCode();

var motionData = await downloadResponse.Content.ReadAsByteArrayAsync();
await File.WriteAllBytesAsync("motion.glb", motionData);

Next steps