Manage your characters, motions, and other assets through the Uthana API. Upload, list, download, and organize your 3D assets programmatically.

## Overview

Asset management covers the full lifecycle of your 3D assets:

- **Characters**: Upload and manage 3D character models
- **Motions**: List, query, and download animation sequences
- **Assets**: Access metadata and file information

## Character management

### List your characters

Retrieve all characters available to your organization.

- Shell
- Python
- TypeScript
- React
- C#

```
API_KEY="your-api-key"

curl -X POST https://uthana.com/graphql \
  -u $API_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "query": "{ characters { id name created updated assets { id filename } } }"
  }'
```

```
import asyncio
from uthana import Uthana

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

async def main():
    characters = await client.characters.list()
    for c in characters[:10]: # Limit to 10 characters
        print(c.get("id"), c.get("name"))

asyncio.run(main())
```

```
import { UthanaClient } from "@uthana/client";

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

const characters = await client.characters.list();
const limitedCharacters = characters.slice(0, 10);
limitedCharacters.forEach((c) => console.log(c.id, c.name));
```

```
import { useUthanaCharacters } from "@uthana/react";

function CharacterList() {
  const { characters } = useUthanaCharacters();
  const limitedCharacters = characters?.slice(0, 10);
  return <ul>{limitedCharacters?.map((c) => <li key={c.id}>{c.name}</li>)}</ul>;
}
```

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

public async Task<List<Character>> GetCharactersAsync()
{
    var query = @"
        query {
            characters {
                id
                name
                created
                updated
                assets {
                    id
                    filename
                }
            }
        }";

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

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

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

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

return result.Data.Characters;
}

// Usage
var characters = await GetCharactersAsync();
foreach (var character in characters.Take(10)) {
    Console.WriteLine($"{character.Name} ({character.Id})");
}
```

See the [Auto-rig / add a character](/content/docs/api/capabilities/auto-rig-and-add-character/index.html) guide for uploading characters.

### Rename a character

- Shell
- Python
- TypeScript
- React
- C#

```
CHARACTER_ID="your-character-id"

curl -X POST https://uthana.com/graphql \
  -u $API_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation UpdateCharacter($character_id: String!, $name: String) { update_character(character_id: $character_id, name: $name) { character { id name } } }",
    "variables": { "character_id": "'"$CHARACTER_ID"'", "name": "New name" }
  }'
```

```
async def main():
    await client.characters.rename("your-character-id", "New name")

asyncio.run(main())
```

```
await client.characters.rename("your-character-id", "New name");
```

```
import { useUthanaRenameCharacter } from "@uthana/react";

function RenameButton({ characterId }: { characterId: string }) {
  const rename = useUthanaRenameCharacter();
  return <button onClick={() => rename.mutate({ character_id: characterId, name: "New name" })}>Rename</button>;
}
```

```
var query = @"
    mutation UpdateCharacter($character_id: String!, $name: String) {
        update_character(character_id: $character_id, name: $name) {
            character { id name }
        }
    }";
var request = new { query = query, variables = new { character_id = "your-character-id", name = "New name" } };
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(ApiUrl, content);
response.EnsureSuccessStatusCode();
```

### Delete a character

Delete a character by setting its `deleted` flag to `true`. Built-in characters (like the default character "Tar") cannot be deleted.

- Shell
- Python
- TypeScript
- React
- C#

```
CHARACTER_ID="your-character-id"

curl -X POST https://uthana.com/graphql \
  -u $API_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation UpdateCharacter($character_id: String!, $deleted: Boolean) { update_character(character_id: $character_id, deleted: $deleted) { character { id name deleted } } }",
    "variables": { "character_id": "'"$CHARACTER_ID"'", "deleted": true }
  }'
```

```
async def main():
    await client.characters.delete("your-character-id")

asyncio.run(main())
```

```
await client.characters.delete("your-character-id");
```

```
import { useUthanaDeleteCharacter } from "@uthana/react";

function DeleteButton({ characterId }: { characterId: string }) {
  const remove = useUthanaDeleteCharacter();
  return <button onClick={() => remove.mutate({ character_id: characterId })}>Delete</button>;
}
```

```
public async Task<Character> DeleteCharacterAsync(string characterId)
{
    var query = @"
        mutation UpdateCharacter($character_id: String!, $deleted: Boolean) {
            update_character(character_id: $character_id, deleted: $deleted) {
                character {
                    id
                    name
                    deleted
                }
            }
        }";

var request = new
    {
        query = query,
        variables = new
        {
            character_id = characterId,
            deleted = true
        }
    };

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<UpdateCharacterData>>(responseJson);

return result.Data.UpdateCharacter.Character;
}
```

See the [Download a character](/content/docs/api/capabilities/downloading-character/index.html) guide for downloading characters.

## Motion management

### List your motions

Retrieve all motions available to your organization.

- Shell
- Python
- TypeScript
- React
- C#

```
curl -X POST https://uthana.com/graphql \
  -u $API_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "query": "{ motions { id name created updated assets { id filename } } }"
  }'
```

```
async def main():
    motions = await client.motions.list()
    for m in motions[:10]: # Limit to 10 motions
        print(m.get("id"), m.get("name"))

asyncio.run(main())
```

```
const motions = await client.motions.list();
const limitedMotions = motions.slice(0, 10);
limitedMotions.forEach((m) => console.log(m.id, m.name));
```

```
import { useUthanaMotions } from "@uthana/react";

function MotionList() {
  const { motions } = useUthanaMotions();
  const limitedMotions = motions?.slice(0, 10);
  return <ul>{limitedMotions?.map((m) => <li key={m.id}>{m.name}</li>)}</ul>;
}
```

```
public async Task<List<Motion>> GetMotionsAsync()
{
    var query = @"
        query {
            motions {
                id
                name
                created
                updated
                assets {
                    id
                    filename
                }
            }
        }";

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<MotionsData>>(responseJson);

return result.Data.Motions;
}
```

### Get a specific motion

Retrieve detailed information about a specific motion by ID.

- Shell
- Python
- TypeScript
- React
- C#

```
MOTION_ID="your-motion-id"

curl -X POST https://uthana.com/graphql \
  -u $API_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "query": "query GetMotion($id: String!) { motion(id: $id) { id name created updated tags assets { id filename } } }",
    "variables": { "id": "'"$MOTION_ID"'" }
  }'
```

```
async def main():
    motion = await client.motions.get("your-motion-id")
    print(motion.get("name"), motion.get("created"))

asyncio.run(main())
```

```
const motion = await client.motions.get("your-motion-id");
console.log(motion.name, motion.created);
```

```
import { useUthanaMotion } from "@uthana/react";

function MotionDetail({ motionId }: { motionId: string }) {
  const { motion } = useUthanaMotion(motionId);
  return <div>{motion?.name}</div>;
}
```

```
public async Task<Motion> GetMotionAsync(string motionId)
{
    var query = @"
        query GetMotion($id: String!) {
            motion(id: $id) {
                id
                name
                created
                updated
                tags
                assets {
                    id
                    filename
                }
            }
        }";

var request = new
    {
        query = query,
        variables = new { id = motionId }
    };

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<MotionData>>(responseJson);

return result.Data.Motion;
}
```

### Rename a motion

- Shell
- Python
- TypeScript
- React
- C#

```
MOTION_ID="your-motion-id"
NEW_NAME="Updated motion name"

curl -X POST https://uthana.com/graphql \
  -u $API_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation UpdateMotion($motion_id: String!, $name: String) { update_motion(motion_id: $motion_id, name: $name) { motion { id name } } }",
    "variables": { "motion_id": "'"$MOTION_ID"'", "name": "'"$NEW_NAME"'" }
  }'
```

```
async def main():
    await client.motions.rename("your-motion-id", "Updated motion name")

asyncio.run(main())
```

```
await client.motions.rename("your-motion-id", "Updated motion name");
```

```
const client = useUthanaClient();
await client.motions.rename(motionId, "Updated motion name");
```

```
public async Task<Motion> UpdateMotionAsync(string motionId, string newName)
{
    var query = @"
        mutation UpdateMotion($motion_id: String!, $name: String) {
            update_motion(motion_id: $motion_id, name: $name) {
                motion {
                    id
                    name
                }
            }
        }";

var request = new
    {
        query = query,
        variables = new
        {
            motion_id = motionId,
            name = newName
        }
    };

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<UpdateMotionData>>(responseJson);

return result.Data.UpdateMotion.Motion;
}
```

### Delete a motion

Delete a motion by setting its `deleted` flag to `true`. The motion will be marked as deleted and will not appear in API responses or the UI.

- Shell
- Python
- TypeScript
- React
- C#

```
MOTION_ID="your-motion-id"

curl -X POST https://uthana.com/graphql \
  -u $API_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation UpdateMotion($motion_id: String!, $deleted: Boolean) { update_motion(motion_id: $motion_id, deleted: $deleted) { motion { id name deleted } } }",
    "variables": { "motion_id": "'"$MOTION_ID"'", "deleted": true }
  }'
```

```
async def main():
    await client.motions.delete("your-motion-id")

asyncio.run(main())
```

```
await client.motions.delete("your-motion-id");
```

```
const client = useUthanaClient();
await client.motions.delete(motionId);
```

```
public async Task<Motion> DeleteMotionAsync(string motionId)
{
    var query = @"
        mutation UpdateMotion($motion_id: String!, $deleted: Boolean) {
            update_motion(motion_id: $motion_id, deleted: $deleted) {
                motion {
                    id
                    name
                    deleted
                }
            }
        }";

var request = new
    {
        query = query,
        variables = new
        {
            motion_id = motionId,
            deleted = true
        }
    };

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<UpdateMotionData>>(responseJson);

return result.Data.UpdateMotion.Motion;
}
```

### Favorite a motion

- Shell
- Python
- TypeScript
- React
- C#

```
MOTION_ID="your-motion-id"

curl -X POST https://uthana.com/graphql \
  -u $API_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation UpdateMotion($motion_id: String!, $favorite: Boolean) { update_motion(motion_id: $motion_id, favorite: $favorite) { motion { id name } } }",
    "variables": { "motion_id": "'"$MOTION_ID"'", "favorite": true }
  }'
```

```
async def main():
    await client.motions.favorite("your-motion-id", True)
    # Unfavorite:
    await client.motions.favorite("your-motion-id", False)

asyncio.run(main())
```

```
await client.motions.favorite("your-motion-id", true);
// Unfavorite:
await client.motions.favorite("your-motion-id", false);
```

```
const client = useUthanaClient();
await client.motions.favorite(motionId, true);
```

```
var query = @"
    mutation UpdateMotion($motion_id: String!, $favorite: Boolean) {
        update_motion(motion_id: $motion_id, favorite: $favorite) {
            motion { id name }
        }
    }";
var request = new { query = query, variables = new { motion_id = "your-motion-id", favorite = true } };
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(ApiUrl, content);
response.EnsureSuccessStatusCode();
```

### Rate a motion

Rate a motion with a thumbs up or thumbs down.

- Shell
- Python
- TypeScript
- React
- C#

```
MOTION_ID="your-motion-id"

curl -X POST https://uthana.com/graphql \
  -u $API_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "query": "mutation RateMotion($motion_id: String!, $score: Int!) { rate_motion(motion_id: $motion_id, score: $score) { motion { id } } }",
    "variables": { "motion_id": "'"$MOTION_ID"'", "score": 1 }
  }'
```

```
async def main():
    # 1 = thumbs up, 0 = thumbs down
    await client.motions.rate("your-motion-id", 1)

asyncio.run(main())
```

```// 1 = thumbs up, 0 = thumbs down
await client.motions.rate("your-motion-id", 1);
```

```
import { useUthanaRateMotion } from "@uthana/react";

function RateButtons({ motionId }: { motionId: string }) {
  const rate = useUthanaRateMotion();
  return (
    <div>
      <button onClick={() => rate.mutate({ motion_id: motionId, score: 1 })}>👍</button>
      <button onClick={() => rate.mutate({ motion_id: motionId, score: 0 })}>👎</button>
    </div>
  );
}
```

```
var query = @"
    mutation RateMotion($motion_id: String!, $score: Int!) {
        rate_motion(motion_id: $motion_id, score: $score) {
            motion { id }
        }
    }";
var request = new { query = query, variables = new { motion_id = "your-motion-id", score = 1 } };
var json = JsonSerializer.Serialize(request);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var response = await _httpClient.PostAsync(ApiUrl, content);
response.EnsureSuccessStatusCode();
```

## Next steps

- Learn about [Text to motion](/content/docs/api/capabilities/text-to-motion/index.html) for generating animations
- Learn about [Locomotion](/content/docs/api/capabilities/locomotion/index.html) for controllable directional movement
- Explore [Video to motion](/content/docs/api/capabilities/video-to-motion/index.html) for converting video files
- Check [Account and organization](/content/docs/api/capabilities/account-and-organization/index.html) for user and organization information
- Check the [API reference](/content/docs/api/graphql/index.html) for complete schema documentation
