Skip to main content

cURL examples

Uthana provides a powerful GraphQL API for all programmatic access to animation, character, and motion data. There is no REST API—all features are available via GraphQL.

This guide shows how to use curl to interact with the GraphQL API, including authentication, queries, mutations, and file uploads.

Endpoint

https://uthana.com/graphql

Authentication

Use the -u flag to authenticate with your API key:

curl -s "https://uthana.com/graphql" \
-u YOUR_API_KEY: \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--data-raw '{<your-query-or-mutation>}'

or 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 as a query parameter:

curl 'https://uthana.com/graphql?api_key=<your-api-key>'

Making GraphQL queries with cURL

Send a POST request with your query or mutation in the JSON body:

Get motion details

curl -X POST https://uthana.com/graphql \
-u <your-api-key>: \
-H "Content-Type: application/json" \
-d '{
"query": "query GetMotion($id: String!) { motion(id: $id) { id name created } }",
"variables": { "id": "m3G3XSJrjEJH" }
}'

Download a motion

To download a motion file (fbx or glb), use 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)

Download a motion as FBX

curl -L "https://uthana.com/motion/file/motion_viewer/<character-id>/<motion-id>/fbx/<character-id>-<motion-id>.fbx" \
-u <your-api-key>: \
-o motion.fbx
  • Replace <character-id> and <motion-id> with your actual IDs.
  • The -L flag follows redirects (if any).
  • The -o flag saves the file as motion.fbx.

Generate motion from text (text-to-motion)

curl -X POST https://uthana.com/graphql \
-u <your-api-key>: \
-H "Content-Type: application/json" \
-d '{
"query": "mutation CreateTextToMotion($character_id: String!, $prompt: String!) { create_text_to_motion(character_id: $character_id, prompt: $prompt) { ok job_id motion { id name } } }",
"variables": { "character_id": "<your-character-id>", "prompt": "walk casually" }
}'

Upload files (multipart/form-data)

To upload files (e.g., for create_character or create_video_to_motion), use the GraphQL multipart request spec:

Upload a character

curl -X POST https://uthana.com/graphql \
-u <your-api-key>: \
-F 'operations={
"query": "mutation ($file: Upload!, $name: String!) { create_character(file: $file, name: $name) { ok character_id } }",
"variables": { "file": null, "name": "My Character" }
}' \
-F 'map={ "0": ["variables.file"] }' \
-F '0=@/path/to/character.fbx'

Complete examples

Create a text-to-motion job and download the motion as FBX and GLB

#!/bin/bash

set -eo pipefail

# Set your API key and character ID for easy reuse
UTHANA_APIKEY=<your-api-key>
HOST="uthana.com"
CHARACTER_ID=<your-character-id>

# Create a text-to-motion job
RES="$(curl -s "https://$HOST/graphql" \
-u $UTHANA_APIKEY: \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--data-raw $'{"query":"mutation CreateTextToMotion($character_id: String!, $model: String!, $prompt: String!) {create_text_to_motion(character_id: $character_id, model: $model, prompt: $prompt) {motion{id name}}}","variables":{"character_id":"'"$CHARACTER_ID"'","model":"text-to-motion","prompt":"a person runs in a circle"},"operationName":"CreateTextToMotion"}'
)"
echo $RES

MOTION_ID="$(echo $RES | jq -r .data.create_text_to_motion.motion.id)"
echo "motion_id: $MOTION_ID"

# Download the motion as FBX
curl -s --remote-name "https://$HOST/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/fbx/$CHARACTER_ID-$MOTION_ID.fbx" \
-u $UTHANA_APIKEY:

# Download the motion as GLB
curl -s --remote-name "https://$HOST/motion/file/motion_viewer/$CHARACTER_ID/$MOTION_ID/glb/$CHARACTER_ID-$MOTION_ID.glb" \
-u $UTHANA_APIKEY:

# View the motion in the Uthana Web UI
echo "https://$HOST/app/play/$CHARACTER_ID/$MOTION_ID"

Upload a character

#!/bin/bash

set -eo pipefail

# Set your API key and character ID for easy reuse
UTHANA_APIKEY=<your-api-key>
HOST="uthana.com"
CHARACTER_NAME="My Character"

# Your existing fbx or glb file – ensure it has a rigged skeleton
FILE="$1"
if [ ! -e "$FILE" ]; then
echo "$FILE is missing?"
fi

# Upload & create character

# In this request we auto-retarget to our internal skeleton, so the first time
# we see a skeleton this might be slow, but if you use the same skeleton again,
# it should be faster. Please contact us if you have issues during this process.

# You can also include a motion prompt to generate a motion from text in the same
# request, or omit `prompt` to just create the character.
RES="$(curl -s -X POST "https://$HOST/graphql" \
-u $UTHANA_APIKEY: \
-H 'Accept: application/json' \
--form $'operations={"query":"mutation CreateCharacter($file: Upload!, $name: String!) {\\n create_character(file: $file, name: $name) {character_id motion_id}\\n}","variables":{"file":null,"name":"'"$CHARACTER_NAME"'","prompt":"a person runs in a circle"},"operationName":"CreateCharacter"}' \
--form 'map={ "nFile": ["variables.file"] }' \
--form nFile=@$FILE
)"
echo $RES

CHARACTER_ID="$(echo $RES | jq -r .data.create_character.character_id)"
MOTION_ID="$(echo $RES | jq -r .data.create_character.motion_id)"

# List existing characters
curl -s "https://$HOST/graphql" \
-u $UTHANA_APIKEY: \
-H 'Accept: application/json' \
-H 'Content-Type: application/json' \
--data-raw $'{"query":"{ characters { id name created } }"}'

# View the character in the Uthana Web UI
echo "https://$HOST/app/play/$CHARACTER_ID/$MOTION_ID"

Error handling

Errors are returned in the errors array of the GraphQL response:

{
"errors": [
{
"message": "Rate limit exceeded",
"extensions": {
"code": "RATE_LIMIT_EXCEEDED",
"resetAt": "2025-01-01T00:00:00Z"
}
}
]
}

Rate limits

Rate limits are enforced on a per-organization basis. Contact the Uthana team to discuss your needs.