Skip to content
maskostudioDocs

All pages

  • Overview/docs/use-cases
  • Mobile app/docs/use-cases#mobile
  • Website/docs/use-cases#website
  • Desktop/docs/use-cases#desktop
  • AI agents/docs/use-cases#agents
  • Videos/docs/use-cases#videos
  • Brand/docs/use-cases#brand
  • Start building/docs/ai-agents
  • Set up once/docs/ai-agents#set-up-once
  • Ask in plain words/docs/ai-agents#ask-in-plain-words
  • What your agent does/docs/ai-agents#what-your-agent-does
  • MCP server/docs/mcp
  • Masko for Cursor/docs/ai-tools/cursor
  • Masko in ChatGPT/docs/ai-tools/chatgpt
  • Start here/docs/tutorials#start-here
  • All tutorials/docs/tutorials
  • Create your first mascot/docs/tutorials/first-mascot
  • Create an animated character/docs/tutorials/first-animation
  • Make a character talk/docs/tutorials/make-it-talk
  • Put your mascot on your website/docs/tutorials/mascot-on-your-website
  • Guide onboarding with a talking mascot/docs/tutorials/web-onboarding-mascot
  • Add a mascot that celebrates progress and welcomes users back/docs/tutorials/web-progress-companion
  • Add a talking support mascot in the bottom right/docs/tutorials/web-support-mascot
  • Show a mascot while your AI thinks/docs/tutorials/ai-loading-mascot
  • Give your AI agent a face/docs/tutorials/ai-agent-face
  • Animate the mascot you already have/docs/tutorials/animate-your-mascot
  • How to make Telegram stickers/docs/tutorials/telegram-stickers
  • How to make Discord stickers/docs/tutorials/discord-stickers
  • Quickstart: your first animation/docs/quickstart
  • Terminal quickstart/docs/terminal
  • API keys and workspaces/docs/authentication
  • CLI browser login/docs/authentication/cli
  • How mascots work/docs/how-mascots-work
  • Credits and costs/docs/credits
  • From text/docs/create/from-text
  • From an image/docs/create/from-image
  • From a website/docs/create/from-website
  • From a brand book/docs/create/from-brand-book
  • Reference images/docs/manage/references
  • What you can generate/docs/generation
  • Pose-to-animation walkthrough/docs/generate/workflow
  • Images and poses/docs/generate/images
  • Animations/docs/generate/animations
  • Talking animations/docs/generate/talking
  • Logos, backgrounds and stickers/docs/generate/design-assets
  • Cursor follower/docs/generate/cursor-follower
  • Batch generation/docs/generate/batch
  • Image and video exports/docs/manage/media-exports
  • Canvases and releases/docs/canvas
  • Build a canvas/docs/canvas/build
  • Canvas templates/docs/canvas/templates
  • Generate canvas assets/docs/canvas/generate-all
  • Export a canvas/docs/canvas/export
  • Overview and demo/docs/player
  • Play one animation/docs/player/one-animation
  • Play a canvas/docs/player/canvas
  • Hosting and file formats/docs/generate/cdn
  • File sizes/docs/generate/file-sizes
  • Float a mascot on your Mac/docs/integrations/desktop
  • Jobs and polling/docs/manage/jobs
  • Webhooks/docs/manage/webhooks
  • Manage mascots and assets/docs/manage/collections
  • All endpoints/docs/reference
  • Requests and responses/docs/reference/conventions
  • Errors and recovery/docs/reference/errors
  • Command line reference/docs/terminal/commands
  • TypeScript SDK/docs/sdk/typescript
  • Changelog/docs/reference/changelog
  • Migrate to mascots and canvases/docs/manage/studio-migration
Get an API key
Documentation

Animations

Animate your mascot on a transparent background: a loop that repeats, or a transition from one pose to another. Each animation comes as a transparent WebM (Chrome, Firefox, Edge), a transparent HEVC .mov (Safari, Apple devices) and an MP4.

Ko's idle loop at its 360-pixel size.

Upload and animate in one request

Upload the image with POST /v1/upload, then animate its data.asset_id. create_mascot creates the mascot in the same request:

curl -X POST https://api.masko.ai/v1/animations \
  -H "Authorization: Bearer $MASKO_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: first-wave-001" \
  -d '{
    "source_image_asset_id": "UPLOADED_IMAGE_ID",
    "create_mascot": { "project_id": "PROJECT_ID" },
    "name": "Wave",
    "animation_prompt": "Wave gently, keeping the feet planted.",
    "animation_model": "standard",
    "duration": 5
  }'
  • Defaults: Standard, 5 seconds, looping, 10 credits. Naming, mascot creation and cropping are free; non-square images get a centered square crop (image framing).
  • Without create_mascot.name, AI picks a short name such as Pip (Mascot <suffix> if naming fails) and writes no description. The upload becomes the mascot's first reference as is.
  • The 202 response has data.mascot_id, mascot_name, mascot_created, job_id, item_id, asset_ids, estimated_cost and poll_url.

Each create_mascot makes a new mascot, so send the returned mascot_id for the next animation of that character:

{
  "mascot_id": "RETURNED_MASCOT_ID",
  "source_image_asset_id": "UPLOADED_IMAGE_ID",
  "name": "Bounce",
  "animation_prompt": "Bounce gently in place."
}

Send exactly one of mascot_id (optionally with variant_id) or create_mascot. Retry an uncertain response with the same Idempotency-Key and body; if generation fails after the mascot was created, reuse error.details.mascot_id with a new key.

New pose and animation

Send an image_prompt for the pose and an animation_prompt for the motion. Five seconds cost 11 credits with Standard (1 for the image) and 31 with Premium.

curl -X POST https://api.masko.ai/v1/mascots/MASCOT_ID/generate \
  -H "Authorization: Bearer masko_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "animation",
    "animation_model": "standard",
    "name": "Idle breathing",
    "image_prompt": "standing relaxed with arms at sides",
    "animation_prompt": "gentle breathing motion, subtle body sway",
    "duration": 5,
    "loop": true
  }'

Animate an existing image

Pass source_image_asset_id to skip image generation: 10 credits for 5 seconds with Standard.

curl -X POST https://api.masko.ai/v1/mascots/MASCOT_ID/generate \
  -H "Authorization: Bearer masko_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "animation",
    "animation_model": "standard",
    "name": "Waving animated",
    "source_image_asset_id": "3c8ce568-35ce-59c2-b3f8-9fb7e4a16e52",
    "animation_prompt": "waving hello with smooth arm motion",
    "duration": 5,
    "loop": true
  }'

From Video

Copy a video's motion onto your mascot, Premium only: 6 credits per output second plus 1 image credit, 4 to 30 whole seconds, 31 credits at the default 5.

Upload the video (MP4 or WebM, up to 50 MB) and its first frame (PNG, JPEG or WebP, up to 10 MB), then send both IDs:

curl -X POST https://api.masko.ai/v1/upload \
  -H "Authorization: Bearer $MASKO_API_KEY" \
  -F "file=@motion.mp4"

curl -X POST https://api.masko.ai/v1/upload \
  -H "Authorization: Bearer $MASKO_API_KEY" \
  -F "file=@first-frame.png"

curl -X POST https://api.masko.ai/v1/mascots/$MASCOT_ID/animations/reference-video \
  -H "Authorization: Bearer $MASKO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "video_asset_id": "VIDEO_ASSET_ID",
    "first_frame_asset_id": "FRAME_ASSET_ID",
    "name": "Friendly wave from video",
    "animation_model": "premium",
    "duration": 5
  }'
  • Both sources must be completed, active and accessible to your key. Optional: variant_id, context_asset_id (reuse a mascot asset's saved context when no variant is set) and prompt (pose or look).
  • The 202 response has data.job_id, poll_url, estimated_cost and asset_ids, for one animation item and two pose items (item_id, start_item_id, end_item_id).
  • Poll GET /v1/jobs/{job_id}?api_version=2026-09-26 without resubmitting, then fetch each file with GET /v1/assets/{id}.

Transitions

Send both source_image_asset_id and end_image_asset_id; loop becomes false. 10 credits for 5 seconds with Standard.

curl -X POST https://api.masko.ai/v1/mascots/MASCOT_ID/generate \
  -H "Authorization: Bearer masko_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "animation",
    "animation_model": "standard",
    "name": "Idle to Wave",
    "source_image_asset_id": "6aec5b1a-cb7f-5f10-8d6e-235ec16b4d97",
    "end_image_asset_id": "18d4fd5e-7193-57f1-8af9-f3bdff007783",
    "animation_prompt": "smoothly transitioning from idle stance to waving",
    "duration": 5
  }'

Variant context. A loop uses its source pose's saved context, even on a canvas that defaults to Original, and a transition keeps its start and end contexts separately.

  • A conflicting variant_id returns 409, unless that variant lists the image among its references.
  • An upload with no generation receipt uses the variant_id that references it, else Original if it does, else the only variant that does.
  • If several variants share an upload and Original does not, the request returns 409 before charging. Pick a variant or generate distinct poses first.

Auto-reverse

On a transition, auto_reverse: true also makes the return clip (B to A), named by reverse_name, for 0 extra credits. It comes back as reverse_job.

curl -X POST https://api.masko.ai/v1/mascots/MASCOT_ID/generate \
  -H "Authorization: Bearer masko_YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "type": "animation",
    "animation_model": "standard",
    "name": "Idle to Wave",
    "source_image_asset_id": "6aec5b1a-cb7f-5f10-8d6e-235ec16b4d97",
    "end_image_asset_id": "18d4fd5e-7193-57f1-8af9-f3bdff007783",
    "animation_prompt": "transitioning from idle to waving",
    "auto_reverse": true,
    "reverse_name": "Wave to Idle",
    "duration": 5
  }'

Models, duration and looping

animation_model works on /generate, each generate-batch request, and canvas edge and generate-all requests.

animation_modelDurationDefaultCredits per second
standard2–15 whole seconds5s2
premium4–30 whole seconds5s6

A duration outside the range returns 400 before charging. loop defaults to true (false for transitions) and asks for a seamless clip; your player decides whether to repeat it.

Output formats

Each animation has video (MP4, opaque), webm (VP9 with alpha), hevc (MOV with alpha) and stacked_video (MP4 with color and alpha stacked, for Android). See hosting and file formats.

Size variants

Every animation has its files at 720 px. Set up to two smaller animation_sizes, such as 480, 360, 240 or 128, in the mascot settings to get free resized copies of new animations. Sizes of 720 or more are ignored, and a third smaller size is refused.

curl -X PATCH https://api.masko.ai/v1/mascots/MASCOT_ID/settings \
  -H "Authorization: Bearer masko_..." \
  -H "Content-Type: application/json" \
  -d '{
    "publish_params": {
      "animation_sizes": {
        "enabled": true,
        "sizes": [480, 240]
      }
    }
  }'

For finished animations, call the backfill with an empty body. It uses the configured sizes, or [360], and makes only the files each animation lacks: WebM, HEVC, stacked MP4 and stacked AV1, at its own width and at each size. Files that exist keep their links, and animations made before AV1 get their AV1 files.

curl -X POST https://api.masko.ai/v1/mascots/MASCOT_ID/size-variants \
  -H "Authorization: Bearer masko_..." \
  -H "Content-Type: application/json" \
  -d '{}'

Do not toggle the settings to force a backfill. force: true regenerates existing variants, for explicit recovery only.

Instant CDN URLs for size variants

Pass sizes when generating to get variant URLs at once:

curl -X POST https://api.masko.ai/v1/mascots/MASCOT_ID/generate \
  -H "Authorization: Bearer masko_..." \
  -H "Content-Type: application/json" \
  -d '{
    "type": "animation",
    "animation_model": "standard",
    "name": "wave",
    "image_prompt": "standing with a smile",
    "animation_prompt": "waving hello",
    "duration": 5,
    "sizes": [480]
  }'

Only sizes enabled in the settings come back, and each URL serves a placeholder until its file is ready; poll the job's size_variants.status.

Direct uploads

source_image_asset_id also takes your own unattached POST /v1/upload image. It is imported as a source under the mascot, with the original file kept, no image generation and no change to mascot references. A new upload can take an approved variant_id; existing sources keep their context.

Image framing

Animations use square images. Other images, including those from item_id and transition end frames, are center-cropped into a separate 1024 × 1024 source; originals and references stay unchanged, and cropping is free.

For an off-center character, set source_image_crop:

{
  "type": "animation",
  "name": "Wave",
  "source_image_asset_id": "IMAGE_ASSET_ID",
  "source_image_crop": { "x": 200, "y": 0, "width": 800, "height": 800 },
  "animation_prompt": "Wave gently.",
  "animation_model": "standard",
  "duration": 5
}
  • Coordinates are integer pixels after EXIF orientation; this takes 800 × 800 from an image at least 1000 × 800.
  • The crop must be square (within one pixel) and inside the image, or the request returns 400 before any job or charge.
  • end_image_crop crops the end frame and needs end_image_asset_id. Crops do not apply when reversing a video.