Skip to main content

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(app_ids: [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.

  • prompt: The text prompt to generate a motion from.
  • foot_ik: Whether to enable foot IK.
mutation {
create_text_to_motion(
prompt: String!
model: String # internal use only
foot_ik: Boolean = false
) {
motion {
id
name
}
}
}

create_video_to_motion

Generate a motion from a 2D video file.

  • file: File or URL of the video file to create a motion from.
  • motion_name: The name of the resulting motion.
mutation {
create_video_to_motion(
file: Upload!
motion_name: String!
) {
job {
id
status
}
}
}

create_character

Upload a new character. Auto-rigging is handled automatically if the character doesn't have a rig.

  • file: File or URL of the character file to create.
  • name: The name of the resulting character.
  • auto_rig: Whether to auto-rig the character. (default: true)
mutation {
create_character(
file: Upload!
name: String!
auto_rig: Boolean = true # optional, defaults to true
root: String # internal use only
root_rotation: [Float] # internal use only
root_translation: [Float] # internal use only
use_prerotations: Boolean = true # internal use only
) {
character {
id
name
}
}
}

create_stitched_motion

Stitch two motions together.

Note: The motion stitching model has been upgraded, and this endpoint will be improved soon with new behavior. Legacy behavior may be preserved in a separate endpoint.

  • leading_motion_id: The ID of the leading motion.
  • trailing_motion_id: The ID of the trailing motion.
  • duration: The duration in seconds of the transition between the two motions. (default: 0.5)
mutation {
create_stitched_motion(
leading_motion_id: String!
trailing_motion_id: String!
duration: Float = 0.5
) {
motion {
id
name
}
}
}

trim_and_loop_motion

Note: This mutation’s contract (its name and parameters) may change in the future. The implementation is stable, and the resulting motions are unaffected.

Trim and optionally loop a motion.

  • motion_id: The ID of the motion to trim and loop.
  • motion_name: The name of the resulting motion.
  • start/end: The start and end times of the trimmed motion, as a decimal value between 0 (start of motion) and 1 (end of motion).
  • loop: Whether to loop the trimmed motion. (default: false)
  • loop_root_motion: Whether to loop the root motion. (default: false)
mutation {
trim_and_loop_motion(
motion_id: String!
motion_name: String
start: Float!
end: Float!
loop: Boolean!
loop_root_motion: Boolean!
) {
motion {
id
name
}
}
}

rate_motion

Rate a motion or label.

  • motion_id: The ID of the motion to rate.
  • label_id: The ID of the label to rate.
  • score: The score to rate the motion or label with. Must be one of:
    • 0: Downvote
    • 1: Upvote
mutation {
rate_motion(
label_id: String
motion_id: String!
score: Int! # must be 0 or 1
) {
rating {
score
user_id
}
}
}

update_motion

Update a motion's name and/or deletion status.

  • motion_id: The ID of the motion to update.
  • name: The new name of the motion.
  • deleted: Marks the motion as deleted. While not permanently removed, it will not appear in API responses or the UI.
mutation {
update_motion(
deleted: Boolean
motion_id: String!
name: String
) {
motion {
id
name
deleted
}
}
}

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
}
}
}

List jobs

query ListJobs {
jobs(method: "VideoToMotion") {
id
status
}
}

Generate motion from text (text-to-motion)

mutation GenerateTextMotion {
create_text_to_motion(
prompt: "walk casually"
foot_ik: true
model: "text-to-motion" # optional, specify custom model if available
) {
motion {
id
name
}
}
}

Upload a character

mutation UploadCharacter($file: Upload!) {
create_character(
file: $file
name: "My Character"
auto_rig: true # optional, defaults to true
) {
character {
id
name
}
}
}

Download a character as FBX or GLB

All character files are available via the following endpoint:

https://uthana.com/motion/bundle/<character-id>/character.<fbx,glb>
  • character_id: The character's ID
  • type: The file type/format (fbx, glb)

Note: You will need to pass your API key in the Authorization header (see this curl example).

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

Errors are returned in the errors array with detailed information:

{
"errors": [
{
"message": "Invalid character model format. Expected .fbx or .glb file.",
"path": ["create_character"],
"extensions": {
"code": "INVALID_MODEL_FORMAT",
"timestamp": "2025-01-15T10:30:00Z"
}
}
]
}
{
"errors": [
{
"message": "Rate limit exceeded",
"extensions": {
"code": "RATE_LIMIT_EXCEEDED",
"resetAt": "2025-01-01T00:00:00Z"
}
}
]
}