Quickstart guide
Get started with the Uthana API in minutes. This guide will help you create your first AI-powered animation.
Official clients:
- Python:
uthana—pip install uthana - JavaScript/TypeScript:
@uthana/client—npm install @uthana/client
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.
- Install Context7 in your IDE: Context7 Installation
- Add Uthana as a source: https://context7.com/websites/uthana_api (library id:
/websites/uthana_api) - 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
- An Uthana account (sign up for free here)
- An API key (get it from your account settings once logged in)
Step 1: Install the client
- Shell
- Python
- TypeScript
- React
- C#
# No install needed — use curl directly.
# For the Python client: pip install uthana
pip install uthana
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.
- Shell
- Python
- TypeScript
- React
- C#
API_KEY="{{apiKey}}"
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("{{apiKey}}")
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 = "{{apiKey}}";
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.
- Go to the Web UI and sign in.
- Click the button.
- Upload your character model in FBX (.fbx) or glTF (.glb/.gltf) format.
- Verify that the character is loaded correctly by viewing or generating a motion.
- Copy the character ID from the URL:
https://uthana.com/app/<character-id>/<motion-id>. - 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
- Shell
- Python
- TypeScript
- React
- C#
curl 'https://uthana.com/graphql' \
-u {{apiKey}}: \
-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("{{apiKey}}")
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
- Shell
- Python
- TypeScript
- React
- C#
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 {{apiKey}}: \
-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 {{apiKey}}: \
-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 {{apiKey}}: \
-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 {{apiKey}}: \
-o motion-only.glb
import asyncio
from uthana import Uthana
client = Uthana("{{apiKey}}")
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
- Explore Capabilities for detailed tutorials on each feature
- Review the API reference for complete schema documentation
- Get support for common questions and troubleshooting
- Join our Discord for community support