GraphQL API
The Uthana GraphQL API provides a flexible way to query and mutate animation data.
Endpoint
https://uthana.com/graphql
Authentication
Include your API key in the basic Authorization
header, base64-encoded with a colon:
AUTH_STRING=$(echo -n "<your-api-key>:" | base64)
curl -H "Authorization: Basic $AUTH_STRING" \
https://uthana.com/graphql
or in the query string (plaintext):
https://uthana.com/graphql?api_key=<your-api-key>
Schema
Queries
type Query {
# Get the current user's organization
org: Org
# Get the current user
user: User
# List all characters available to the user
characters: [Character!]
# Get a motion by ID
motion(id: String): Motion
# List motions, with optional filters
motions(
character_id: String
app_ids: [String!]
methods: [String]
): [Motion!]
# Search for labels by description
label_search(
query: String
limit: Int = 20
): [LabelSearchResult!]
# Get a job by job ID
job(job_id: String): Job
# List jobs, optionally filtered by method
jobs(method: String): [Job!]
}
Mutations
The following mutations are available for creating and modifying data:
create_text_to_motion
Generate a motion from a text prompt.
mutation {
create_text_to_motion(
character_id: String!
foot_ik: Boolean = true
model: String
prompt: String!
): CreateTextToMotion!
}
create_video_to_motion
Generate a motion from a 2D video file.
mutation {
create_video_to_motion(
character_id: String!
file: Upload!
motion_name: String!
): CreateVideoToMotion!
}
create_character
Upload a new character. (See also: create_rig)
mutation {
create_character(
file: Upload!
name: String!
root: String
root_rotation: [Float]
root_translation: [Float]
use_prerotations: Boolean = true
): CreateCharacter!
}
create_rig
Auto-rig a character (used when upload fails due to missing rig). You will need to implement this as part of your error handling of the create_character
mutation.
mutation {
create_rig(
character_id: String!
filename: String!
org_id: String!
): CreateRig!
}
create_stitched_motion
Stitch two motions together.
mutation {
create_stitched_motion(
character_id: String!
duration: Float
leading_motion_id: String!
trailing_motion_id: String!
): CreateStitchedMotion!
}
create_motion_from_gltf
Create a motion from a GLTF string (typically this is used to "bake" a motion with changes).
mutation {
create_motion_from_gltf(
character_id: String!
desired_motion_name: String
# motion_method: String – internal use only
gltf: String!
motion_id: String!
): CreateMotionFromGltf!
}
trim_and_loop_motion
Trim and optionally loop a motion.
mutation {
trim_and_loop_motion(
desired_motion_name: String
end_pct: Float!
loop: Boolean!
loop_root_motion: Boolean!
orig_motion_id: String!
start_pct: Float!
): TrimAndLoopMotion!
}
rate_motion
Rate a motion or label. Valid values for score
are:
- 0: "Downvote"
- 1: "Upvote"
mutation {
rate_motion(
label_id: String
motion_id: String!
score: Int!
): RateMotion!
}
update_motion
Update a motion's name and/or deletion status.
mutation {
update_motion(
deleted: Boolean
motion_id: String!
name: String
): UpdateMotion!
}
Example queries
Get motion details
query GetMotion($id: String!) {
motion(id: $id) {
id
name
created
updated
org_id
priority
tags
motion_viewer
training
assets {
id
filename
}
labels {
id
description
start
end
}
rating {
score
user_id
}
}
}
List motions
query ListMotions {
motions(methods: ["TextToMotion"]) {
id
name
org_id
created
assets {
filename
}
}
}
Generate motion from text (text-to-motion)
mutation GenerateTextMotion {
create_text_to_motion(
character_id: "CHARACTER_ID"
prompt: "walk casually"
foot_ik: true
model: "text-to-motion"
) {
ok
job_id
motion {
id
name
}
}
}
Upload a character
mutation UploadCharacter($file: Upload!) {
create_character(
file: $file
name: "My Character"
) {
ok
character_id
skeleton_id
motion_id
}
}
Auto-rigging a character
The create_rig
mutation can be used to automatically create a skeleton rig for characters that were uploaded without proper rigging.
Note: The character_id
needed for this mutation comes from the failed create_character
response, so this is always a two-step request. You will need to implement this as part of your error handling of the create_character
mutation:
- Attempt character upload with
create_character
- Check if the response contains
error: "no rig found in scene"
- If so, extract the
character_id
from the failed response - Call
create_rig
with thecharacter_id
,filename
, andorg_id
mutation AutoRigCharacter {
create_rig(
character_id: "CHARACTER_ID"
filename: "character.fbx"
org_id: "ORG_ID"
) {
ok
character_id
error
}
}
Download a motion as FBX or GLB
All motion files are available via the following endpoint:
https://uthana.com/motion/file/motion_viewer/<character-id>/<motion-id>/<type>/<character-id>-<motion-id>.<type>
- app_id: The application context (always use
motion_viewer
) - character_id: The character's ID
- motion_id: The motion's ID
- type: The file type/format (
fbx
,glb
)
Rate limits
Rate limits are enforced on a per-organization basis. Reach out to the Uthana team to discuss your needs.
Error handling
GraphQL errors are returned in the errors
array:
{
"errors": [
{
"message": "Rate limit exceeded",
"extensions": {
"code": "RATE_LIMIT_EXCEEDED",
"resetAt": "2025-01-01T00:00:00Z"
}
}
]
}