Skip to content
Masko logomasko
Docs
Documentation

Animations

Generate animated mascot videos from scratch or from existing images. Image-to-video animation uses /generate with type: "animation". From Video uses the reference-video endpoint below.

Upload and animate in one request

Upload your image with POST /v1/upload, then use its data.asset_id below. You can create the mascot and start animation 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
  }'

create_mascot.name is optional. If omitted, AI chooses a short character name, such as Pip. It generates no character description. If naming is unavailable, a temporary Mascot <suffix> name is used. You can rename it later with PATCH /v1/mascots/{id}. The original upload becomes the new mascot's first reference without image regeneration.

The 202 response includes data.mascot_id, data.mascot_name, data.mascot_created, data.job_id, data.item_id, data.asset_ids, data.estimated_cost and data.poll_url.

For subsequent animations of that character, replace create_mascot with the returned mascot_id:

{
  "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 or create_mascot. Each create_mascot request creates a separate mascot in the specified project, so reuse mascot_id to keep related animations together. Existing mascot references remain unchanged. An optional variant_id is supported for an existing mascot.

This endpoint defaults to Standard, 5 seconds, and looping: 10 credits. Naming, mascot creation and cropping add no credits. Non-square images use a centered square crop; pass source_image_crop for explicit framing as described under image framing.

Retry an uncertain response with the same Idempotency-Key and unchanged body. If generation fails after creating the mascot, error.details.mascot_id gives its ID. Reuse that ID with a new key when submitting a corrected request. The API never guesses whether two different uploads are the same character.

Image + Animation (New)

Generate a new image and animate it in one request. Provide both an image_prompt (for the pose) and an animation_prompt (for the motion). With Standard, this costs 1 credit for the image plus 2 credits per second of video: a 5-second animation costs 11 credits total. Premium costs 31 credits for the same duration.

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 Existing Image

Animate an image you already have by passing source_image_asset_id. This skips image generation, so you only pay for the video - 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

Transfer motion from a video to your mascot with Premium. This operation costs 6 credits per output second plus 1 image credit. Output duration is 4–30 whole seconds and defaults to 5 seconds, for 31 credits. Standard is not available for From Video.

Upload the motion video and an image of its first frame using POST /v1/upload with multipart form data. Each upload returns an asset_id. Video uploads accept MP4 or WebM, up to 50 MB; image uploads accept PNG, JPEG, and WebP up to 10 MB. Use a short, clear motion clip within the 4–30 second range.

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 source assets must be completed, active, and accessible to your API key. Optional variant_id selects an approved mascot variant; context_asset_id reuses the saved mascot context of an asset in this mascot when no variant is specified. Optional prompt adds pose or appearance instructions.

The response is 202 Accepted with data.job_id, data.poll_url, data.estimated_cost, and data.asset_ids. It creates one animation item and two pose items, identified by item_id, start_item_id, and end_item_id. Poll GET /v1/jobs/{job_id} until completed or failed; do not submit the request again while it is processing. Use the returned asset IDs to fetch the MP4, transparent WebM/HEVC, and start/end images with GET /v1/assets/{id}.

Transitions

Create a transition between two poses by providing both source_image_asset_id and end_image_asset_id. Transitions automatically set loop: false since they play once between two states. Costs 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
  }'

Loops use the source pose's saved generation context, including its named variant. An explicit conflicting variant_id returns 409, unless that variant intentionally includes the image among its references; then the selected variant guides the new animation without changing the source image's provenance. On a mixed canvas, a Sporty pose keeps Sporty's context even when the canvas defaults to Original. Transitions preserve the before and after contexts separately.

For uploaded images without a generation receipt, variant_id selects the context when that variant includes the image in its references. Without a selection, an upload in Original's references uses Original; an upload belonging to exactly one variant uses that variant. If several variants share an upload and Original does not reference it, generation returns 409 before charging. Select a matching variant or first generate distinct poses for the intended contexts. One shared upload cannot represent two different endpoint contexts in the same request; use separate generated poses for that transition.

Auto-Reverse

When creating a transition, set auto_reverse: true to automatically generate the return transition (B to A) at 0 extra credits. The response includes a reverse_job with its own job ID and asset IDs.

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

Duration & Looping

Pass animation_model to choose the same quality options as Studio. The field is supported by single generation, each request in generate-batch, and canvas edge / generate-all requests.

animation_modelDurationDefaultCredits per second
standard5–15 whole seconds5s2
premium4–30 whole seconds5s6
omitted (legacy clients)4–10 whole seconds4s5

Use "animation_model": "premium" for Premium. Durations outside the selected range return 400 before charging. Images remain 1 credit; an existing source image has no image charge. Reverse animations remain free. Video editing has its separate existing pricing.

Omitting animation_model preserves existing provider selection and pricing for older integrations. Explicitly send the field to use the new rates.

The loop field defaults to true for standard animations and is automatically set to false for transitions (when end_image_asset_id is provided). loop asks generation for a seamless clip. Your player or runtime decides whether to repeat it, hold a frame, or move to another state.

Output Formats

Every animation produces multiple format variants optimized for different platforms:

TypeFormatUse Case
videoMP4 (H.264)Universal fallback, opaque background
webmWebM (VP9)Transparent video for Chrome, Firefox, Edge
hevcMOV (HEVC + Alpha)Transparent video for Safari, iOS, macOS
stacked_videoMP4 (stacked)Transparent video for Android (color + alpha stacked vertically)

Size Variants

By default, animations are generated at full resolution. You can configure a mascot to automatically produce smaller size variants for each new animation - useful for responsive layouts, thumbnails, or mobile-optimized assets.

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

Available sizes are 720, 480, 360, and 240 pixels. When enabled, new animation outputs automatically generate resized variants alongside the original.

To backfill missing size variants for existing completed animations, use the dedicated endpoint. Normal usage sends an empty body; it uses the mascot's configured sizes, or [360] if no sizes are configured, and only creates missing variants.

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

Do not re-toggle PATCH /v1/mascots/:id/settings to force a backfill. The size-variants endpoint is the idempotent repair path. force: true exists only for explicit recovery when you intentionally want to regenerate existing variants.

Instant CDN URLs for Size Variants

When generating an animation, pass the sizes array to get pre-allocated CDN URLs for specific size variants immediately in the response:

curl -X POST https://api.masko.ai/v1/mascots/COL_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]
  }'

The response includes both original and variant URLs:

{
  "data": {
    "urls": {
      "webm": "https://assets.masko.ai/.../wave.webm",
      "hevc": "https://assets.masko.ai/.../wave.mov",
      "webm_480": "https://assets.masko.ai/.../wave-480.webm",
      "hevc_480": "https://assets.masko.ai/.../wave-480.mov",
      "stacked_video_480": "https://assets.masko.ai/.../wave-480.mp4"
    }
  }
}

The sizes parameter is a filter - it only returns URLs for sizes that are enabled in the mascot settings. If you request sizes: [720] but the mascot only has [480, 360] configured, no 720 URLs are returned.

All variant URLs serve placeholders immediately and are replaced with the real resized files when the size variant workflow completes. Poll the job to check size_variants.status.

Cost Reference

At the 5-second default for explicitly selected Standard or Premium:

OperationStandardPremium
New image + animation11 credits31 credits
Animate existing image10 credits30 credits
Transition (A to B)10 credits30 credits
Auto-reverse (B to A)0 credits0 credits

From Video uses Premium at 31 credits for 5 seconds, including the pose image.

Without animation_model, legacy pricing remains 20 credits for a 4-second animation, plus 1 credit if a new source image is needed.

Direct uploads

source_image_asset_id also accepts an unattached image returned by POST /v1/upload. The upload must belong to the caller. Masko imports a source record under the destination mascot, preserves the original uploaded file, and skips image generation. Non-square sources are center-cropped before animation. It does not add or replace mascot references. Select an approved variant_id for a new upload when needed. Existing source assets keep their saved context. See animate an uploaded image.

Image framing

Animations use square input images. Before sending an existing image to the video model, Masko center-crops horizontal or vertical images to a square and saves a separate 1024 × 1024 source. Square images are used directly. The same rule applies to images resolved through item_id and transition end frames. The original file and mascot references stay unchanged, and cropping adds no credits.

For a character that is not centered, set source_image_crop explicitly:

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

This example selects an 800 × 800 region from an image at least 1000 × 800. Coordinates are integers in pixels after applying EXIF orientation. Width and height must describe a square, within one pixel for crop-tool rounding. The rectangle must fit inside the image. Invalid crops return 400 before a job is queued or credits are deducted.

For transitions, end_image_crop sets the end frame's crop independently and requires end_image_asset_id. Omit either crop to use its centered default. Image crops do not apply when reversing an existing video.